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 install
Haku 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: :user
For 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
end
Call 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 attributes
to 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
end
class ApplicationAction
include Haku::Core
include Haku::Resourceable
include Haku::Eventable
end
class Users::Update < ApplicationAction
end
After 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.