A gem that provides an interface for creating feature-driven operations. You've probably heard at least one of these terms: "service objects", "form objects", "intentions", or "commands". Subroutine calls these "ops" and really it's just about enabling clear, concise, testable, and meaningful code.
So you need to sign up a user? or maybe update one's account? or change a password? or maybe you need to sign up a business along with a user, associate them, send an email, and queue a worker in a single request? Not a problem, create an op for any of these use cases. Here's the signup example.
class SignupOp < ::Subroutine::Op
string :name
string :email
string :password
string :company_name
validates :name, presence: true
validates :email, presence: true
validates :password, presence: true
validates :company_name, presence: true
outputs :user
outputs :business, type: Business # validate that output type is an instance of Business
protected
def perform
u = create_user!
b = create_business!(u)
deliver_welcome_email(u)
output :user, u
output :business, b
end
def create_user!
User.create!(name: name, email: email, password: password)
end
def create_business!(owner)
Business.create!(company_name: company_name, owner: owner)
end
def deliver_welcome_email(u)
UserMailer.welcome(u.id).deliver_later
end
end
- Avoid cluttering models or controllers with logic only applicable to one intention. You also don't need strong parameters because the inputs to the Op are well-defined.
- Test the Op in isolation
- Clear and concise intention in a single file
- Multi-model operations become simple
Run the test suite against current Rails version:
bundle exec rake test
Run the test suite against all supported Rails versions using appraisal
:
bundle exec appraisal rake test
For help updating the Gemfile
or changing supported Rails versions, see the appraisal
gem README.
Note that the gemfiles in gemfiles/*
are auto-generated by appraisal
and should not be modified directly.