Responders gem is really awesome. It sets flash message based on the controller action and resource status allowing you to dry up your Rails controllers. Trailblazer is a thin layer on top of Rails. It gently enforces encapsulation, an intuitive code structure and gives you an object-oriented architecture. When combining both of them together, you can achieve really slim and functional controllers:
class ContractsController < BaseController def index respond_with(collection Contracts::Index) end def show respond_with(present Contracts::Update) end def new respond_with(form Contracts::Create) end def create respond_with(run Contracts::Create) end def edit respond_with(form Contracts::Update) end def update respond_with(run Contracts::Update) end def destroy respond_with(run Contracts::Destroy) end end
Unfortunately there’s one downside: Since Responders #respond_with method expects a model as a first argument, it will think that your operation is a model (if you return it the way I did) and try to figure out it’s human name. Probably it won’t end up as you expect and you will see a message similar to this one:
Users/campaigns/update was successfully updated.
It happens because of this piece of code from Responders:
resource_name = if resource.class.respond_to?(:model_name) resource.class.model_name.human else resource.class.name.underscore.humanize end
Trailblazer operations don’t respond to #model_name, that’s why all the operations will be translated using the else statement. To make it work as expected, we just need to implement the #model_name class method:
class ApplicationOperation < Trailblazer::Operation def self.model_name ::ActiveModel::Name.new(model_class) end end
I follow the ApplicationController, ApplicationRecord, ApplicationHelper “pattern” also with operations. That way I don’t need to add this code into Trailblazer::Operation or into each of the operations separately. #model_class method is a method that will return the model class that we’ve set using Trailblazer::Operation #method:
class Operation < ApplicationOperation include Model model Contract end Operation.model_class #=> Contract Operation.model_name #=> ActiveModel::Name:0x0000000575b778 @name="Contract"...
From now on, all the Trailblazer operations will introduce themselves to Responders with the name of the model on which we operate.