In Trailblazer 2.1, we are introduced to a new concept: Activity.
Unlike Trailblazer 2.0, where Operation was king, activities have taken over as the main orchestrator of business logic. Good old operations are still there, but now they act as a wrapper around activities. Its one and the same, except activities are more powerful! Don’t worry though, its super easy to pick up and its backward compatibility makes switching a breathe.
So, let’s jump right in. What does an activity look like?
module Broadcasts::Cancel extend Trailblazer::Activity::Railway() module_function def set_model(ctx, broadcast_id:, **) ctx[:model] = Broadcast.find_by(id: broadcast_id) end def set_step_status(ctx, model:, **) ctx[:step] = model.action.step.first ctx[:step].status = 'pause' ctx[:step].save end def set_broadcast_status(ctx, model:, **) model.status = 'cancelled' model.save end def set_queued_emails_status(ctx, step:, **) step.queued_emails.update_all(status: 'cancelled', completed_at: Time.now) end def set_job_ids(ctx, action_funnel_step:, **) ctx[:ids] = step.queued_emails.pluck(:job_id) end step method(:set_model) step method(:set_step_status) step method(:set_broadcast_status) step method(:set_queued_emails_status) step method(:set_job_ids) merge!(Sidekiq::InvalidateJobs) end
Here we have an activity that cancels a broadcast. What this code exactly does is not important for the purpose of this article, so lets just examine the activity itself:
- Activities are contained in modules compared to class defined operations.
Trailblazer::Activity::Railway(). This is all you need to use activities.
module_function, a ruby function, is used to define “module methods” as if the module was a class.
- steps are defined just the same as operations in trb 2.0, except now we use “ctx”, standing for context, instead of “options” as the first parameter.
merge!copies steps from another operation (
Sidekiq::InvalidateJobs) and runs them as its own. Order matters!
And this is how you call the activity:
event, (ctx, *) = Broadcasts::Cancel.call(broadcast_id: params[:broadcast_id]) if event.to_h[:semantic] == :success ... else ... end
- ctx contains all the computed information from your activity. In this example, it would contain :model, :step, and :ids
- event contains the success or failure of the activity
Thats it! Keep in mind this is a simple operation doing a simple thing. There is much more that you can do with activities. But you get the gist of it…