Slayer: A Killer Service Layer
Slayer is intended to operate as a minimal service layer for your ruby application. To achieve this, Slayer provides base classes for business logic.
Slayer is still under development, and not yet ready for production use. We are targetting a stable API with the 0.4.0 launch, so expect breaking changes until then.
Slayer provides 3 base classes for organizing your business logic:
Services. Each of these has a distinct role in your application's structure.
Slayer::Forms are objects for wrapping a set of data, usually to be passed as a parameter to a
Slayer::Commands are the bread and butter of your application's business logic.
Commands are where you compose services, and perform one-off business logic tasks. In our applications, we usually create a single
Commands should call
Services should never call
Services are the building blocks of
Commands, and encapsulate re-usable chunks of application logic.
Add this line to your application's Gemfile:
And then execute:
Or install it yourself as:
$ gem install slayer
While Slayer is independent of any framework, we do offer a first-class integration with Ruby on Rails. To install the Rails extensions, add this line to your application's Gemfile:
And then execute:
And that's it. The integration provides a small handful of features that make your life easier when working with Ruby on Rails.
Slayer::Form objects are automatically extended with
ActiveRecord validations. You can use the same validations you would on your
ActiveRecord models, but directly on your forms.
slayer_rails there are two new methods for instantiating
from_model. These make it easier to populate forms with data while in your Rails controllers.
Take the following example for a
class FooController < ApplicationController def new @foo_form = FooForm.new end def edit @foo = Foo.find(params[:id]) @foo_form = FooForm.from_model(@foo) end def create @foo_form = FooForm.from_params(foo_params) end def update @foo_form = FooForm.from_params(foo_params) end private def foo_params params.require(:foo).permit(:bar, :baz) end end
Slayer::Service objects are extended with access to
ActiveRecord transactions. Anywhere in your
Service objects, you can execute a
transaction block, which will let you bundle database interactions.
class FooCommand < Slayer::Command def call transaction do # => database interactions end end end
Use generators to make sure your
Slayer objects are always in the right place.
slayer_rails includes generators for
$ bin/rails g slayer:form foo_form $ bin/rails g slayer:command foo_command $ bin/rails g slayer:service foo_service
Slayer Commands should implement
call, which will
fail the service based on input. Commands return a
Slayer::Result which has a predictable interface for determining
failure?, a 'value' payload object, a 'status' value, and a user presentable
# A Command that passes when given the string "foo" # and fails if given anything else. class FooCommand < Slayer::Command def call(foo:) if foo == "foo" pass! value: foo, message: "Passing FooCommand" else fail! value: foo, message: "Failing FooCommand" end end end result = FooCommand.call(foo: "foo") result.success? # => true result = FooCommand.call(foo: "bar") result.success? # => false
Slayer Services are objects that should implement re-usable pieces of application logic or common tasks. To prevent circular dependencies Services are required to declare which other Service classes they depend on. If a circular dependency is detected an error is raised.
In order to enforce the lack of circular dependencies, Service objects can only call other Services that are declared in their dependencies.
class NetworkService < Slayer::Service def self.post() ... end end class StripeService < Slayer::Service dependencies NetworkService def self.pay() ... NetworkService.post(url: "stripe.com", body: my_payload) ... end 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 tags, and push the
.gem file to rubygems.org.
To generate documentation run
yard. To view undocumented files run
yard stats --list-undoc.
Bug reports and pull requests are welcome on GitHub at https://github.com/apsislabs/slayer.
The gem is available as open source under the terms of the MIT License.