When using Rails, we often need to run tasks in the background without affecting website performance. Rails 4.2 introduced the ActiveJob framework to standardize scheduling background jobs.
A simple example where the ActiveJob use-case fits correctly is sending an email verification when a user signs up as shown below.
class EmailVerificationJob < ActiveJob::Base
def perform(user_id:, email_verification_code:)
# send verification code to user email
end
end
In the above example, we have passed user_id
and email_verification_code
as arguments
to the perform
method.
ActiveJob performs serialization and deserialization on these arguments.
The below argument types are supported (before Rails 7) by default:
Basic types (NilClass, String, Integer, Float, BigDecimal, TrueClass, FalseClass)
Symbol
Date
Time
DateTime
ActiveSupport::TimeWithZone
ActiveSupport::Duration
Hash (Keys should be of String or Symbol type)
ActiveSupport::HashWithIndifferentAccess
Array
Module
Class
Before
As seen in the above list Range
as an argument was not supported before Rails 7.
Let’s take an example where for a given date range we need to pass log report to admins. If we try to pass the date range as an argument, it raises an error as shown below:
class AdminReportJob < ActiveJob::Base
queue_as :default
def perform(date_range:)
# code to fetch report for the passed date range
end
end
start_date = Date.today - 3.days
end_date = Date.today
AdminReportJob.perform_later(date_range: start_date..end_date)
Failed enqueuing AdminReportJob to Sidekiq(default): ActiveJob::SerializationError (Unsupported argument type: Range)
In Rails 6 or above, we can resolve the above issue by adding a custom serializer for the Range argument type. To know more about custom serializers, please refer to our previous blog.
After
With
the changes
in Rails 7, we can now pass range
as an argument type and avoid adding custom serializers.
The above AdminReportJob
will work without raising any error.
class AdminReportJob < ActiveJob::Base
queue_as :default
def perform(date_range:)
# code to fetch report for the passed date range
end
end
start_date = Date.today - 3.days
end_date = Date.today
AdminReportJob.perform_later(date_range: start_date..end_date)
=> Enqueued AdminReportJob (Job ID: d5688e0c-e826-4587-9413-1309a2332f0e) to Async(default) with arguments: Thu, 20 May 2021..Sun, 23 May 2021