Sugar around ActiveModel::Model
Ruby
Switch branches/tags
Clone or download
Fetching latest commit…
Cannot retrieve the latest commit at this time.
Permalink
Failed to load latest commit information.
lib
spec
.gitignore
.projections.json
.rspec
.rubocop.yml
.travis.yml
CHANGELOG.md
Gemfile
LICENSE.txt
README.md
Rakefile
mini_form.gemspec

README.md

Gem Version Code Climate Build Status Code coverage

MiniForm

Helpers for dealing with form objects and nested forms.

Installation

Add this line to your application's Gemfile:

gem 'mini_form'

And then execute:

$ bundle

Or install it yourself as:

$ gem install mini_form

Usage

class ProductForm
  include MiniForm::Model

  attributes :id, :name, :price, :description

  validates :name, :price, :description, presence: true

  # called after successful validations in update
  def perform
    @id = ExternalService.create(attributes)
  end
end
class ProductsController < ApplicationController
  def create
    @product = ProductForm.new

    if @product.update(product_params)
      redirect_to product_path(@product.id)
    else
      render :edit
    end
  end

  private

  def product_params
    params.require(:product).permit(:name, :price, :description)
  end
end

Delegated attributes

Attributes can be delegated to a sub object.

class SignUpForm
  include MiniForm::Model

  attr_reader :account, :user

  attributes :name, :email, delegate: :user
  attributes :company_name, :plan, delegate: :account

  validates :name, :email, :company_name, :plan, presence: true

  def initialize
    @account = Account.new
    @user    = User.new account: @account
  end

  def perform
    user.save!
    account.save!
  end
end
form = SignUpForm.new
form.name = 'name' # => form.user.name = 'name'
form.name          # => form.user.name
form.plan = 'free' # => form.account.plan = 'free'
form.plan          # => form.account.plan

Nested validator

mini_form/nested validator runs validations on the given model and copies errors to the form object.

class SignUpForm
  include MiniForm::Model

  attr_reader :account, :user

  attributes :name, :email, delegate: :user
  attributes :company_name, :plan, delegate: :account

  validates :account, :user, 'mini_form/nested' => true

  def initialize
    @account = Account.new
    @user    = User.new account: @account
  end

  def perform
    account.save!
    user.save!
  end
end

Nested models

Combines delegated attributes and nested validation into a single call.

class SignUpForm
  include MiniForm::Model

  model :user, attributes: %i(name email)
  model :account, attributes: %i(company_name plan)

  def initialize
    @account = Account.new
    @user    = User.new account: @account
  end

  def perform
    account.save!
    user.save!
  end
end

Auto saving nested models

Most of the time perform is just calling save!. We can avoid this by using model's save option.

class SignUpForm
  include MiniForm::Model

  model :user, attributes: %i(name email), save: true
  model :account, attributes: %i(company_name plan), save: true

  def initialize
    @account = Account.new
    @user    = User.new account: @account
  end
end

Before/after callbacks

class SignUpForm
  include MiniForm::Model

  # ... code

  before_update :run_before_update
  after_update :run_after_update

  private

  def run_before_update
    # ...
  end

  def run_after_update
    # ...
  end

  # alternatively you can overwrite "before_update"
  def before_update
  end

  # alternatively you can overwrite "after_update"
  def after_update
  end
end

Delegating model attributes

class SignUpForm
  include MiniForm::Model

  model :user, attributes: %i(name email), read: %i(id)

  def initialize
    @user    = User.new account: @account
  end
end
form = SignUpForm.new
form.update! form_params
form.id        # => delegates to `user.id`
form.id = 42   # => raises `NoMethodError`

Methods

Method Description
.model Defines a sub object for the form
.attributes Defines an attribute, it can delegate to sub object
.attribute_names Returns list of attribute names
#initialize Meant to be overwritten. By defaults calls `attributes=`
#attributes= Sets values of all attributes
#attributes Returns all attributes of the form
#update Sets attributes, calls validations, saves models and `perform`
#update! Calls `update`. If validation fails, it raises an error
#perform Meant to be overwritten. Doesn't do anything by default
#before_update Meant to be overwritten.
#after_update Meant to be overwritten.
#before_assignment Meant to be overwritten.
#after_assignment Meant to be overwritten.
#transaction If ActiveRecord is available, wraps `perform` in transaction.

Contributing

  1. Fork it
  2. Create your feature branch (git checkout -b my-new-feature)
  3. Commit your changes (git commit -am 'Add some feature')
  4. Push to the branch (git push origin my-new-feature)
  5. Run the tests (rake)
  6. Create new Pull Request

License

MIT License