Active Support Improvements in Rails 5

Abhishek Jain

Abhishek Jain

February 17, 2016

This blog is part of our  Rails 5 series.

Rails 5 has added some nice enhancements to Active Support. This blog will go over some of those changes.

Improvements in Date, Time and Datetime

prev_day and next_day

As the name of the methods suggests, next_day returns next calendar date.

Similarly, prev_day returns previous calendar date.

1
2Time.current
3=> Fri, 12 Feb 2016 08:53:31 UTC +00:00
4
5Time.current.next_day
6=> Sat, 13 Feb 2016 08:53:31 UTC +00:00
7
8Time.current.prev_day
9=> Thu, 11 Feb 2016 08:53:31 UTC +00:00
10

Support for same_time option to next_week and prev_week

In Rails 4.x next_week returns beginning of next week and prev_week returns beginning of previous week.

In Rails 4.x these two methods also accept week day as a parameter.

1
2Time.current
3=> Fri, 12 Feb 2016 08:53:31 UTC +00:00
4
5Time.current.next_week
6=> Mon, 15 Feb 2016 00:00:00 UTC +00:00
7
8Time.current.next_week(:tuesday)
9=> Tue, 16 Feb 2016 00:00:00 UTC +00:00
10
11Time.current.prev_week(:tuesday)
12=> Tue, 02 Feb 2016 00:00:00 UTC +00:00
13

By using week day as parameter we can get the date one week from now but the returned date is still the beginning of that date. How do we get one week from the current time.

Rails 5 add an additional option same_time: true to solve this problem.

Using this option, we can now get next week date from the current time.

1
2Time.current
3=> Fri, 12 Feb 2016 09:15:10 UTC +00:00
4
5Time.current.next_week
6=> Mon, 15 Feb 2016 00:00:00 UTC +00:00
7
8Time.current.next_week(same_time: true)
9=> Mon, 15 Feb 2016 09:15:20 UTC +00:00
10
11Time.current.prev_week
12=> Mon, 01 Feb 2016 00:00:00 UTC +00:00
13
14Time.current.prev_week(same_time: true)
15=> Mon, 01 Feb 2016 09:16:50 UTC +00:00
16

on_weekend?

This method returns true if the receiving date/time is a Saturday or Sunday.

1
2Time.current
3=> Fri, 12 Feb 2016 09:47:40 UTC +00:00
4
5Time.current.on_weekend?
6=> false
7
8Time.current.tomorrow
9=> Sat, 13 Feb 2016 09:48:47 UTC +00:00
10
11Time.current.tomorrow.on_weekend?
12=> true
13

on_weekday?

This method returns true if the receiving date/time is not a Saturday or Sunday.

1
2Time.current
3=> Fri, 12 Feb 2016 09:47:40 UTC +00:00
4
5Time.current.on_weekday?
6=> true
7
8Time.current.tomorrow
9=> Sat, 13 Feb 2016 09:48:47 UTC +00:00
10
11Time.current.tomorrow.on_weekday?
12=> false
13

next_weekday and prev_weekday

next_weekday returns next day that is not a weekend.

Similarly, prev_weekday returns last day that is not a weekend.

1
2Time.current
3=> Fri, 12 Feb 2016 09:47:40 UTC +00:00
4
5Time.current.next_weekday
6=> Mon, 15 Feb 2016 09:55:14 UTC +00:00
7
8Time.current.prev_weekday
9=> Thu, 11 Feb 2016 09:55:33 UTC +00:00
10

Time.days_in_year

1# Gives number of days in current year, if year is not passed.
2Time.days_in_year
3=> 366
4
5# Gives number of days in specified year, if year is passed.
6Time.days_in_year(2015)
7=> 365
8

Improvements in Enumerable

pluck

pluck method is now added to Enumerable objects.

1
2users = [{id: 1, name: 'Max'}, {id: 2, name: 'Mark'}, {id: 3, name: 'George'}]
3
4users.pluck(:name)
5=> ["Max", "Mark", "George"]
6
7# Takes multiple arguments as well
8users.pluck(:id, :name)
9=> [[1, "Max"], [2, "Mark"], [3, "George"]]
10

one great improvement in ActiveRecord due to this method addition is that when relation is already loaded then instead of firing query with pluck, it uses Enumerable#pluck to get data.

1
2# In Rails 4.x
3users = User.all
4SELECT `users`.* FROM `users`
5
6users.pluck(:id, :name)
7SELECT "users"."id", "users"."name" FROM "users"
8
9=> [[2, "Max"], [3, "Mark"], [4, "George"]]
10
11
12# In Rails 5
13users = User.all
14SELECT "users".* FROM "users"
15
16# does not fire any query
17users.pluck(:id, :name)
18=> [[1, "Max"], [2, "Mark"], [3, "George"]]
19

without

This method returns a copy of enumerable without the elements passed to the method.

1
2vehicles = ['Car', 'Bike', 'Truck', 'Bus']
3
4vehicles.without("Car", "Bike")
5=> ["Truck", "Bus"]
6
7vehicles = {car: 'Hyundai', bike: 'Honda', bus: 'Mercedes', truck: 'Tata'}
8
9vehicles.without(:bike, :bus)
10=> {:car=>"Hyundai", :truck=>"Tata"}
11

Array#second_to_last and Array#third_to_last

1
2['a', 'b', 'c', 'd', 'e'].second_to_last
3=> "d"
4
5['a', 'b', 'c', 'd', 'e'].third_to_last
6=> "c"
7

PR for these methods can be found here.

Integer#positive? and Integer#negative?

positive? returns true if integer is positive.

negative? returns true if integer is negative.

1
24.positive?
3=> true
4
54.negative?
6=> false
7
8-4.0.positive?
9=> false
10
11-4.0.negative?
12=> true
13

Commit for these methods can be found here.

These changes have now been added to Ruby 2.3 also.

Array#inquiry

Rails team has added ArrayInquirer to ActiveSupport which gives a friendlier way to check its contents.

Array#inquiry is a shortcut for wrapping the receiving array in an ArrayInquirer

1
2users = [:mark, :max, :david]
3
4array_inquirer1 = ActiveSupport::ArrayInquirer.new(users)
5
6# creates ArrayInquirer object which is same as array_inquirer1 above
7array_inquirer2 = users.inquiry
8
9array_inquirer2.class
10=> ActiveSupport::ArrayInquirer
11
12# provides methods like:
13
14array_inquirer2.mark?
15=> true
16
17array_inquirer2.john?
18=> false
19
20array_inquirer2.any?(:john, :mark)
21=> true
22
23array_inquirer2.any?(:mark, :david)
24=> true
25
26array_inquirer2.any?(:john, :louis)
27=> false
28

If this blog was helpful, check out our full blog archive.

Stay up to date with our blogs.

Subscribe to receive email notifications for new blog posts.