Redress
Motivation (Command pattern)
The command pattern is sometimes called a service object, an operation, an action, and probably more names that I’m not aware of. Whatever the name we gave it, the purpose of such a pattern is rather simple: take a business action and put it behind an object with a simple interface.
Table of Contents
- Requirements
- Setup
- Usage
- Tests
- Versioning
- Code of Conduct
- Contributions
- License
- History
- Credits
Requirements
- Ruby 2.3
- dry-monads
- dry-struct
- hashie
Optional
To support validations just add activemodel to your project
- activemodel
Setup
For an insecure install, type the following:
gem install redress
Add the following to your Gemfile:
gem "redress"
Usage
Forms
# app/forms/application_form.rb
require 'redress/form'
class ApplicationForm < Redress::Form
end
Let's define simple form (Built-in Types https://dry-rb.org/gems/dry-types/built-in-types/):
class SimpleForm < ApplicationForm
mimic :user
define_schema do
attribute :nickname, Redress::Types::Strict::String.default('superman')
attribute :name, Redress::Types::StrippedString
attribute :email, Redress::Types::StrippedString
attribute :name_with_email, String
attribute :age, Redress::Types::Coercible::Integer
attribute :terms_of_service, Redress::Types::Bool
end
validates :name, presence: true
validates :email, presence: true
def map_model(user)
self.name_with_email = "#{user.name} <#{user.email}>"
end
end
Form with default values (http://dry-rb.org/gems/dry-types/default-values/):
require 'securerandom'
class CommentForm < Redress::Form
define_schema do
attribute(:id, Redress::Types::Coercible::String.default { SecureRandom.uuid })
attribute(:content, Redress::Types::String)
end
validates :content, presence: true
end
Form with multiple comments:
class CommentForm < Redress::Form
define_schema do
attribute :id, Redress::Types::Coercible::Integer
attribute :content, Redress::Types::String
end
validates :content, presence: true
end
class OrderForm < Redress::Form
mimic :order
define_schema do
attribute :title, Redress::Types::String
attribute :comments, Redress::Types::Array.of(CommentForm)
end
end
Form with context:
class CommentForm < Redress::Form
define_schema do
attribute :id, Redress::Types::Coercible::Integer
attribute :content, Redress::Types::String
end
validates :content, presence: true
validate :unsure_order_state_waiting
private
def unsure_order_state_waiting
context.order.state?(:waiting)
end
end
CommentForm.new(content: 'Hi').with_context(order: order)
Commands
# app/commands/application_command.rb
require 'redress/command'
class ApplicationCommand < Redress::Command
end
Simple command for user registration:
# app/commands/users/create_command.rb
module Users
class CreateCommand < ApplicationCommand
def initialize(form)
@form = form
end
def call
return Failure(@form) if @form.invalid?
user = User.new(@form.attributes)
if user.save
Success(user)
else
Failure(user)
end
end
end
end
Controllers
# app/controllers/users_controller.rb
class UsersController < Account::BaseController
respond_to :json, only: :update
def new
@user_form = SimpleForm.new
end
def create
@user_form = SimpleForm.from_params(params)
Users::CreateCommand.call(@user_form) do |c|
c.success { head status: 201 }
c.failure { |form| render status: 422, json: { errors: form.errors } }
end
end
end
Tests
To test, run:
bundle exec rspec ./spec/
Versioning
Read Semantic Versioning for details. Briefly, it means:
- Major (X.y.z) - Incremented for any backwards incompatible public API changes.
- Minor (x.Y.z) - Incremented for new, backwards compatible, public API enhancements/fixes.
- Patch (x.y.Z) - Incremented for small, backwards compatible, bug fixes.
Code of Conduct
Please note that this project is released with a CODE OF CONDUCT. By participating in this project you agree to abide by its terms.
Contributions
Read CONTRIBUTING for details.
License
Copyright (c) 2017 Fodojo LLC. Read LICENSE for details.
History
Read CHANGES for details. Built with Gemsmith.
Credits
Developed by Igor Galeta at Fodojo LLC.