/active_model_form_objects

Provides an ActiveModel::FormObject module that can be included into a PORO. Includes a Generator for Form Objects.

Primary LanguageRubyMIT LicenseMIT

ActiveModel::FormObjects

Build Status Coverage Status Gem Version

This Gem provides an ActiveModel::FormObject module that can be included into a PORO. Includes a Rails Generator for Form Objects.

Form Objects are used to encapsulate operations which are triggered by a form submission. They are particularly useful when multiple Models need to be updated by a single form submission. A common example would be a signup form that results in the creation of both a Company and a User.

##Install

In your Gemfile

gem 'active_model_form_objects'

And then execute:

$ bundle

Creating a FormObject with the Generator

The following example generates a UserLogin form-object (and test).

$ rails generate active_model:form_object user login

The test framework your project uses will determine the type of test created:

  • For RSpec it creates:

  • Form-object: app/form_objects/user_login.rb

  • Test: spec/form_objects/user_login_spec.rb

  • For MiniTest it creates:

  • Form-object: app/form_objects/user_login.rb

  • Test: test/form_objects/user_login_test.rb

  • For TestUnit it creates:

  • Form-object: app/form_objects/user_login.rb

  • Test: test/unit/form_objects/user_login_test.rb

User Signup Example

The following example demonstrates a user signup form-object and how this would be intergrated with a form.

  • Points of interest:
  • The use of the before_validation callback hook.
  • The use of the NestedValidator to run any existing validations defined on the User model.
  • The use of the strong_parameters method on the form object instead of defining it in the controller

user_signup.rb:

require 'active_model'

class UserSignup
  include ActiveModel::FormObject

  attr_reader :user

  validates :name, :length => { :minimum => 5 }
  validates :user, :nested => true

  before_validation :create_user

  strong_parameters :user => [:name]

  private

  def create_user
    @user = User.new(user_params)
  end

  def persist!
    user.save!
  end
end

users_controller.rb:

class UsersController < ApplicationController
  respond_to :html

  def signup
    @signup_form = UserSignup.new
  end

  def create
    @signup_form = UserSignup.new(:params => params)
    if @signup_form.save()
      @user = @signup_form.user
      respond_with @user
    else
      render "signup"
    end
  end
end

signup.html.erb:

<h1>Users#signup</h1>

<%= form_for @signup_form do |f| %>
  <%= f.text_field :name %>
  <%= f.submit "Submit" %>
<% end %>

Strong Parameters

In rails 4 the strong_parameters gem is used as a method of protecting the attributes that can be passed through in the creation of a model. The usual way of doing this is defining a method on your controller:

class UsersController < ApplicationController

  private

  def user_params
    params.require(:user).permit(:name, :email)
  end

end

With The ActiveModel::FormObject::StrongParameters module this can now be defined in your form object using the strong_parameters class method. The following is the Form Object version of the user_params method above:

  class UserRegister
    include ActiveModel::FormObject

    strong_parameters :user => [:name, :email]
  end

The default implementation assumes a params method on the FormObject which can be defined in the controller as:

  UserRegister.new(:params => params)

If you wish to change the name of the params method to something else such as my_params then the strong_parameters method can be called with :my_params as an argument:

    strong_parameters, :my_params, :user => [:name, :email]

In your controller you can now do:

  UserRegister.new(:my_params => params)

Permitted Params Validator

The strong_parameters class method will record any unpermitted parameters that are included in the params object. These are stored in a unpermitted_attrs hash attribute on the FormObject. If you wish to invalidate a FormObject based on the existence of unpermitted_attrs then you can use the FormObject::Validators::PermittedParamsValidator as demonstrated in the following example:

  class UserRegister
    include ActiveModel::FormObject

    validates :user, :permitted_params => true

    strong_parameters :user => [:name, :email]
  end

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. Create new Pull Request

License

This project rocks and uses MIT-LICENSE.