Ucasy
Ucasy is a lightweight Ruby gem that helps you structure and organize business logic in Rails applications using the service object pattern. It provides a simple framework for building, validating, and composing reusable “use cases,” supporting input validation, transactional flows, and clear separation of concerns. Ucasy makes it easy to manage complex application logic and ensure robust, maintainable code.
Installation
As gem dependence
Add this line to your application's Gemfile:
gem "ucasy", "~> 0.3.3"And then execute:
bin/bundle installOr install it yourself as:
bin/bundle add ucasyCopying files
Add this line to your application's Gemfile:
group :development do
gem "ucasy", "~> 0.3.3", require: false
endAnd then execute:
bin/bundle installOr install it yourself as:
bin/bundle add ucasy --require false --group developmentCreate base file
You can use a Rails generator to create setup UseCaseBase file:
As gem dependence
bin/rails g ucasy:installThis will only create app/use_cases/use_case_base.rb
class UseCaseBase < Ucasy::Base
class Flow < Ucasy::Flow
end
endAnd you need use ucasy gem as production dependence
Copying files
bin/rails g ucasy:copyThis will copy all needed code to your rails application:
create app/use_cases/use_case_base.rb
create app/use_cases/ucasy
create app/use_cases/ucasy/base.rb
create app/use_cases/ucasy/callable.rb
create app/use_cases/ucasy/context.rb
create app/use_cases/ucasy/failure.rb
create app/use_cases/ucasy/flow.rb
create app/use_cases/ucasy/validators/required_attributes.rb
create app/use_cases/ucasy/validators/validate.rb
create app/use_cases/ucasy/version.rb
Basic usage
You can create a simple use case to app/use_cases/authenticate_user.rb:
class AuthenticateUser < UseCaseBase
def before
context.user = User.find_by(login: context.login)
end
def call
return if context.user.valid_password?(context.password)
context.fail!(
status: :unprocessable_entity,
message: "User not found",
errors: context.user.errors
)
end
def after
UserMailer.with(user: context.user).login_warning.perform_later
end
endUsing methods
There is some methods to ensure arguments for each use case:
required_attributes
class AuthenticateUser < UseCaseBase
required_attributes(:login, :password)
def call
context.login
context.password
end
endThe method required_attributes raises an error if login or password is blank
validate
You can use ActiveModel or any class that respond to valid?, errors, present? and accepts a hash as arguments to validate you payload.
Create a class
class AuthenticateUser < UseCaseBase
validate(AuthenticateUserValidation)
def call
context.login
context.password
end
endYou can filter attributes. Only context.login and context.password will be validated in example below:
class AuthenticateUser < UseCaseBase
validate(AuthenticateUserValidation, :login, :password)
...
endAdds a validation
class AuthenticateUserValidation
include ActiveModel::Model
attr_accessor :login, :password
validates :login, presence: true
validates :password, presence: true
def to_context
{login:, :password} # this hash will be injected in use cases context
end
endUsing Flow
You can also create a flow to organize your use cases:
class PlaceOrder < UseCaseBase::Flow
transactional # if any use case fails ActiveRecord will rollback transaction
validate(PlaceOrderValidation)
flow(ChargeCard, SendThankYou, FulfillOrder)
endContributing
Bug reports and pull requests are welcome on GitHub at https://github.com/LaVendaSoftware/ucasy.
License
The gem is available as open source under the terms of the MIT License.