Active Support Improvements in Rails 5

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.

Time.current
=> Fri, 12 Feb 2016 08:53:31 UTC +00:00

Time.current.next_day
=> Sat, 13 Feb 2016 08:53:31 UTC +00:00

Time.current.prev_day
=> Thu, 11 Feb 2016 08:53:31 UTC +00:00

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.

Time.current
=> Fri, 12 Feb 2016 08:53:31 UTC +00:00

Time.current.next_week
=> Mon, 15 Feb 2016 00:00:00 UTC +00:00

Time.current.next_week(:tuesday)
=> Tue, 16 Feb 2016 00:00:00 UTC +00:00

Time.current.prev_week(:tuesday)
=> Tue, 02 Feb 2016 00:00:00 UTC +00:00

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.

Time.current
=> Fri, 12 Feb 2016 09:15:10 UTC +00:00

Time.current.next_week
=> Mon, 15 Feb 2016 00:00:00 UTC +00:00

Time.current.next_week(same_time: true)
=> Mon, 15 Feb 2016 09:15:20 UTC +00:00

Time.current.prev_week
=> Mon, 01 Feb 2016 00:00:00 UTC +00:00

Time.current.prev_week(same_time: true)
=> Mon, 01 Feb 2016 09:16:50 UTC +00:00

on_weekend?

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

Time.current
=> Fri, 12 Feb 2016 09:47:40 UTC +00:00

Time.current.on_weekend?
=> false

Time.current.tomorrow
=> Sat, 13 Feb 2016 09:48:47 UTC +00:00

Time.current.tomorrow.on_weekend?
=> true

on_weekday?

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

Time.current
=> Fri, 12 Feb 2016 09:47:40 UTC +00:00

Time.current.on_weekday?
=> true

Time.current.tomorrow
=> Sat, 13 Feb 2016 09:48:47 UTC +00:00

Time.current.tomorrow.on_weekday?
=> false

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.

Time.current
=> Fri, 12 Feb 2016 09:47:40 UTC +00:00

Time.current.next_weekday
=> Mon, 15 Feb 2016 09:55:14 UTC +00:00

Time.current.prev_weekday
=> Thu, 11 Feb 2016 09:55:33 UTC +00:00

Time.days_in_year

# Gives number of days in current year, if year is not passed.
Time.days_in_year
=> 366

# Gives number of days in specified year, if year is passed.
Time.days_in_year(2015)
=> 365

Improvements in Enumerable

pluck

pluck method is now added to Enumerable objects.

users = [{id: 1, name: 'Max'}, {id: 2, name: 'Mark'}, {id: 3, name: 'George'}]

users.pluck(:name)
=> ["Max", "Mark", "George"]

# Takes multiple arguments as well
users.pluck(:id, :name)
=> [[1, "Max"], [2, "Mark"], [3, "George"]]

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.

# In Rails 4.x
users = User.all
SELECT `users`.* FROM `users`

users.pluck(:id, :name)
SELECT "users"."id", "users"."name" FROM "users"

=> [[2, "Max"], [3, "Mark"], [4, "George"]]


# In Rails 5
users = User.all
SELECT "users".* FROM "users"

# does not fire any query
users.pluck(:id, :name)
=> [[1, "Max"], [2, "Mark"], [3, "George"]]

without

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

vehicles = ['Car', 'Bike', 'Truck', 'Bus']

vehicles.without("Car", "Bike")
=> ["Truck", "Bus"]

vehicles = {car: 'Hyundai', bike: 'Honda', bus: 'Mercedes', truck: 'Tata'}

vehicles.without(:bike, :bus)
=> {:car=>"Hyundai", :truck=>"Tata"}

Array#second_to_last and Array#third_to_last

['a', 'b', 'c', 'd', 'e'].second_to_last
=> "d"

['a', 'b', 'c', 'd', 'e'].third_to_last
=> "c"

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.

4.positive?
=> true

4.negative?
=> false

-4.0.positive?
=> false

-4.0.negative?
=> true

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

users = [:mark, :max, :david]

array_inquirer1 = ActiveSupport::ArrayInquirer.new(users)

# creates ArrayInquirer object which is same as array_inquirer1 above
array_inquirer2 = users.inquiry

array_inquirer2.class
=> ActiveSupport::ArrayInquirer

# provides methods like:

array_inquirer2.mark?
=> true

array_inquirer2.john?
=> false

array_inquirer2.any?(:john, :mark)
=> true

array_inquirer2.any?(:mark, :david)
=> true

array_inquirer2.any?(:john, :louis)
=> false