Skip to content
PLAY VIDEO PLAY VIDEO PLAY VIDEO
By Leonard Garvey

Form Objects in Rails

Rails applications that go beyond the most basic often require complicated forms, or forms not backed by an ActiveRecord model. Form objects help in this regard, and are a fantastic technique of moving code out of your models.

I like to use form objects whenever I have a slightly complicated form, a form which will write to 2 database models or if I'm creating a form that isn't backed by a database model at all. You can think of the form object as a model of the form itself as displayed to the user. This means you've got a spot to put logic which is related to only the form itself.

You may have heard of form objects before but perhaps you're a little confused on how to use them properly in your Rails applications. If you've got a subscription to RailsCasts you can watch the form object screencast which provides an excellent introduction, but here's the short version:

  1. Create a plain Ruby class.
  2. include ActiveModel::Model (in Rails 3 you had to include Naming, Conversion and Validations instead)
  3. Start using your new form class as if it were a regular ActiveRecord model, the biggest difference being that you cannot persist the data stored in this object.

Example form object implementation

Here's an example form object. I like to put these in app/forms although many people would keep them in app/models.

class ProfileForm
  include ActiveModel::Model

  attr_accessor :name, :email, :subscribed_to_marketing_emails, :age

  validates_presence_of :name, :email
  validates_format_of :email, with: /.+@.+/
  validates_numericality_of :age, allow_nil: true, greater_than: 0

  # instead of doing this you could always remember to provide
  # a default value to the initializer instead: ProfileForm.new(subscribed_to_marketing_emails: true)
  # but that would be frustrating too.
  def subscribed_to_marketing_emails
    @subscribed_to_marketing_email ||= true
  end
end

Your controller for the form might look a little like:

class ProfilesController < ApplicationController
  def new
    @profile_form = ProfileForm.new
  end

...

and your view might look like:

<%= simple_form_for @profile_form, url: profile_path do |f| %>
  <%= f.input :name %>
  <%= f.input :email %>
  <%= f.input :age, as: :integer %>
  <%= f.input :subscribed_to_marketing_emails, as: :boolean %>
<% end %>

The problems

But there are some problems with our code.

  • Having to specify the url in the form helper is frustrating. We can fix this by specifying the model_name on the class of the object we pass to the helper.
  • Having to specify the html representation of the :subscribed_to_marketing_emails and :age fields is frustrating. With simple_form this doesn't happen if you use a normal ActiveRecord object because simple_form infers the type of the html element from the type of the database column.
  • Setting default values for your attributes is a little bit messy. Note that since ActiveModel provides an initializer for our object which accepts a hash like a regular ActiveRecord object, it's not a good idea to override the initialize method.

Enter simpleformobject

Recently I created a very small gem, called SimpleFormObject, which solves the issues above. To refactor the form object code above we'd do the following:

class ProfileForm
  include SimpleFormObject

  attribute :name
  attribute :email
  attribute :subscribed_to_marketing_emails, :boolean, default: true
  attribute :age, :integer

  validates_presence_of :name, :email
  validates_format_of :email, with: /.+@.+/
  validates_numericality_of :age, allow_nil: true, greater_than: 0
end

In this version of the form object we don't need to provide a default using the attribute reader method so it's a little cleaner.

We wouldn't need to change our controller at all but our view is simplified to look like:

<%= simple_form_for @profile_form do |f| %>
  <%= f.input :name %>
  <%= f.input :email %>
  <%= f.input :age %>
  <%= f.input :subscribed_to_marketing_emails %>
<% end %>

Notice here we don't need to specify the url of the form. Nor do we have to specify which html elements we want to create. SimpleFormObject causes each attribute to pretend to be a database column which simple_form will convert automatically to the correct element.

I think this is a small, but useful improvement for form objects. Note that there other fantastic form gems out there. But often I want to stay as close to the Rails defaults as possible and this provides just enough sugar to let me do what I need to do, while getting out of my way.

Let me know what you think!

Latest Articles by Our Team

Our expert team of designers and developers love what the do and enjoy sharing their knowledge with the world.

We Hire Only the Best

reinteractive is Australia’s largest dedicated Ruby on Rails development company. We don’t cut corners and we know what we are doing.

We are an organisation made up of amazing individuals and we take pride in our team. We are 100% remote work enabling us to choose the best talent no matter which part of the country they live in. reinteractive is dedicated to making it a great place for any developer to work.

Free Community Workshops

We created the Ruby on Rails InstallFest and Ruby on Rails Development Hub to help introduce new people to software development and to help existing developers hone their skills. These workshops provide invaluable mentorship to train developers, addressing key skills shortages in the industry. Software development is a great career choice for all ages and these events help you get started and skilled up.

  • Webinars

    Webinars

    Webinars are our online portal for tips, tricks and lessons learned in everything we do. Make the most of this free resource to help you become a better developer.

    Learn more about webinars

  • Installfest

    Installfest

    The Ruby on Rails Installfest includes a full setup of your development environment and step-by-step instructions on how to build your first app hosted on Heroku. Over 1,800 attendees to date and counting.

    Learn more about Installfest

  • Development Hub

    Development Hub

    The Ruby on Rails Development Hub is a monthly event where you will get the chance to spend time with our team and others in the community to improve and hone your Ruby on Rails skills.

    Learn more about Development Hub

Next Community Events

Find more events

Get the “reinteractive Review” Monthly Email