A simple library for build simple service objects.
⚠️ This project is still experimental, use with caution!
Add this line to your application's Gemfile:
gem 'haku'And then execute:
bundle installHaku is made up of four modules that add functionality to our service objects:
Additionally, it's available the Haku::Controller module for use in ours Rails controllers.
class Users::Update
include Haku::Core
input :user, :attributes
on_success :send_email
def call
if user.update(attributes)
success! resource: user
else
failure! resource: user, errors: user.errors
end
end
private
def send_email
UserMailer.with(user: user).update.deliver_later
end
end
response = Users::Update.call(user: User.first, attributes: { name: "Javier" })
response.success? # => true
response.result # => { resource: <User id="1" ...> }
response.resource # => <User id="1" ...>As you can see, if the payload passed to success! or failure! is a hash, each key of the hash can be accessed
directly in response object.
class Users::ComputeHours
include Haku::Core
include Haku::Delayable
input :user
def call
# compute expensive data for user
end
end
Users::ComputeHours.delayed.call(user: User.first)Use delayed.call instead of call for execute service object in background using ActiveJob job.
Users::ComputeHours.delayed(job: OtherJob).call(user: User.first)Users::ComputeHours.delayed(job: OtherJob, queue: :low, priority: 2).call(user: User.first)You can pass the same options allowed by ActiveJob set method:
# config/initializers/haku.rb
Haku.configure do |config|
config.job_queue = "low_priority"
end| Config | Description | Default value |
|---|---|---|
job_queue |
String or Symbol with queue name | default |
class Users::Update
include Haku::Core
include Haku::Eventable
input :user, :attributes
event resource: :user
def call
success! resource: user
end
end
Users::Update.call(user: User.first, attributes: { name: "Javier" })
# => call Event.create(name: "user:update", resource: User.first)The name attribute are calculated using the custom proc from event_name config option. You can change it with
event name: "custom:name", resource: :userFor each property passed as payload of event class method, it will try to:
- If is a block, it is called to get the value of property.
- If is a symbol, a method is used to get the value of property:
- In other case, uses the raw value.
# config/initializers/haku.rb
Haku.configure do |config|
config.event_model = "EventLog"
end| Config | Description | Default value |
|---|---|---|
event_model |
Name of the model used for create events | Event |
event_property_for_name |
Property used for name in event model | :name |
event_name |
String or Proc to determine the event name | Custom Proc. Returns user:create for Users::Create |
This module include helpers to works with ActiveRecord compatible model resources, invoking success! or failure!
based in the result of the performed operation.
class Users::Update
include Haku::Core
include Haku::Resourceable
input :user, :attributes
on_success :send_email
def call
update_resource(user, attributes)
end
private
def send_email
UserMailer.with(user: user).update.deliver_later
end
endCall to create or <singleton>_create method of the parent object passing the attributes and storing
the result object in the ivar instance variable. Invoke success! if the model is persisted or failure! in other
case.
| parameter | type | description |
|---|---|---|
parent |
Object |
Parent object where new resource will be created |
attributes |
Hash |
Attributes for create |
ivar |
Symbol |
Name of the instance variable used to access to the new resource |
options |
Hash |
Options hash |
| parameter | type | description |
|---|---|---|
singleton |
Symbol |
If the resource should be created using <singleton>_create suffix. |
Call to update method of the resource object passing attributesto it. Invoke success! if the model is updated or
failure! in other case.
| parameter | type | description |
|---|---|---|
resource |
Object |
Resource to be updated |
attributes |
Hash |
Attributes to update |
Call to destroy method of the resource. Invoke success! if the model is destroyed or failure! in other case.
| parameter | type | description |
|---|---|---|
resource |
Object |
Resource to be destroyed |
| parameter | type | description |
|---|---|---|
resource |
Object |
Resource to be destroyed |
save_options |
Hash |
Options passed to save method of resource |
For more info please view the source code of the module.
class UsersController < ApplicationController
include Haku::Controller
before_action :find_user
def update
execute Users::Update, user: @user, attributes: update_params
if execution.success?
redirect_to user_path(execution.resource)
else
render :edit, errors: execution.errors
end
end
private
def find_user
@user = User.find(params[:id])
end
def update_params
params.require(:user).permit(:first_name, :last_name)
end
endclass ApplicationAction
include Haku::Core
include Haku::Resourceable
include Haku::Eventable
end
class Users::Update < ApplicationAction
endAfter checking out the repo, run bin/setup to install dependencies. Then, run rake test to run the tests.
You can also run bin/console for an interactive prompt that will allow you to experiment.
To install this gem onto your local machine, run bundle exec rake install.
To release a new version, update the version number in version.rb, and then run bundle exec rake release,
which will create a git tag for the version, push git commits and the created tag, and push the .gem file to
rubygems.org.
Bug reports and pull requests are welcome, please follow Github Flow.
Everyone interacting in the Haku project's codebases, issue trackers, chat rooms and mailing lists is expected to follow the code of conduct.
Copyright © 2022-2023 Javier Aranda. Released under the terms of the MIT license.