Project

mini_form

0.02
Low commit activity in last 3 years
A long-lived project that still receives updates
Sugar around ActiveModel::Model
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
 Dependencies

Development

= 3.12.0
= 3.12.0
>= 2.1.4
>= 12.3.3

Runtime

 Project Readme

Gem Version Code Climate 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

Using in forms

Using main_model will delegate id, to_param, persisted? and new_record? to the model. Allowing you to use it in forms.

class SignUpForm
  include MiniForm::Model

  main_model :user

  def initialize
    @user = User.new(account: @account)
  end
end
<% form_for SignUpForm.new %>

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