In part 2 of this series I am going to discuss the use of form objects. Just as in the last installment I drew my inspiration from this article by Bryan Helmkamp. As a warning, I believe the form object is probably the most misunderstood pattern contained in Bryan’s article. One needs to immediately decouple the form object from the concept of a UI form (more on this later).

What is a Form Object and Why Should I Use It?

A form object is the abstraction of operations that should occur when saving a record within a system, business logic if you will. The form object provides many benefits, some of which are:

  • Abstracts the responsibility of create/update of a model(s) to some other class for a better separation of concerns
  • A layer of indirection between your application and the persistence library being used
  • Eliminates validation spaghetti (a la ActiveRecord validations, etc)
  • Allows for more control of how to save associated (nested) objects

While ORMs like ActiveRecord provide a means to persist to a DB by generating SQL, validate attributes, accepts_nested_attributes_for in order to save associated “nested” objects, and many other features, it does not mean you should use them all. An ORM should know how to read/write data to a database, period. Once you start layering all of these other concerns into the “model,” you get yourself into trouble quickly. I believe that most of the pain I have experienced with mature Rails applications is a result of this overlaying of concerns in a single class.

Abstracts the responsibility of create/update of a model(s) to some other class for a better separation of concerns

A form object can be considered a type of decorator for your models. Just as you may use a presenter (a type of decorator) for logic that is not directly related to your data model but more for presentation, you would use a form object for functionality that is not directly related to your data model, but more to the business logic you would like to include in the create/update operations for your model.

Specific examples of this business logic are validation of attributes, creation of associated (nested) records, etc.

A layer of indirection between your application and the persistence library being used

Providing a layer (adapter) between your application and ORM is something that most people scoff at due to the unlikeliness of needing to change ORMs in the lifetime of a project. I myself might have subscribed to this line of thought a mere year ago. However, I have experienced the bite of this issue first hand now. A project I am working on had a requirement for a distributed data model injected late in the project. After analyzing how hard it would be to move from a RDBMS to a document database that has eventual consistency out of the box, like Cassandra, we determined that we could not achieve the refactor of the persistence layer in time to deliver the project. The reason for this is the application is tightly coupled to the persistence layer. If we simply had one level of indirection built into the persistence layer using something like form and query objects, we could have easily acheived a move to Cassandra.

Many developers employ the data repository pattern in order to provide a level of indirection between their application logic and ORM classes. An alternaive to this pattern is to use form and query objects. I will cover query objects in the next installment of this series. I prefer for and query objects over a data respository because the repository usually grows to be a rather large monolithic class in itself. Form and query objects allow for the encapsulation of a single domain operation per class.

Eliminates validation spaghetti (a la ActiveRecord validations, etc)

The easiest way to explain this is through an example. Given a user model that is used to register a new user and also to manage the user’s profile.

class User < ActiveRecord::Base

  attr_accessor :registering

  validates_presence_of :password, if: :registering?
  validates_presence_of :password_confirmation, if: :password_present?

protected

  def registering?
    registering
  end

  def password_present?
    password.present?
  end

end

Even in this simple example you can see how it get hard to determine when valdiations will execute. Imagine adding more concerns/features that the user model is handling with even more conditional validations. The object quickly becomes brittle and even a slight change could result in lots of broken specs.

Why does all of this logic have to live in a single class? The following is a better implementation.

class User < ActiveRecord::Base
end

class UserRegistrationForm < Reform::Form # from gem apotonick/reform

  property :email
  property :password
  property :password_confirmation

  validates :email, 
            :password, 
            :password_confirmation, presence: true

end

When you are registering a user, you can use the UserRegistrationForm. If you need a form for updating the user’s additional profile elements you might implement a form like the following.

class UserProfileUpdateForm < Reform::Form # from gem apotonick/reform

  property :name
  property :phone_number
  property :age

  validates :age, numericality: true

end

Each of the form objects above implements the business rules necessary to perform a create/update operation within a specific context. This makes the business logic contained in each much more explicit and easier to follow.

Allows for more control of how to save associated (nested) objects

Persisting complex object graphs through a single method call is a highly desirable level of abstraction for any application. However, ActiveRecord’s accepts_nested_attributes_for feature is an abomination and should be deprecated from ActiveRecord. Why should a model be concerned with how to persist its associated models?

Form objects can also help clean up this complex task. Given a project that has many tasks you may implement a form for project creation that allows for one or more initial tasks to be defined.

class Project < ActiveRecord::Base
  has_many :tasks
end

class Task < ActiveRecord::Base
  belongs_to :project
end

class ProjectCreationForm < Reform::Form # from gem apotonick/reform

  property :name
  validates :name, presence: true

  property :due_on

  collection :tasks do
    property :description
    validates :description, presence: true

    property :due_on
  end

  def save
    Project.transaction do
      # save project
      # save tasks
    end
  end

end

The above implementation is much more explict and much less magic involved than accepts_nested_attributes_for. If there is a problem, it will be much easier to track down what is going on. Not to mention, when using the ProjectCreationForm we can be sure that only a project and one or more tasks can be created. With accepts_nested_attributes_for, we could accidentally create other associated objects if our attributes hash happened to have stray attributes in it providing an opportunity for a bug that would be hard to track down. This is due to smashing too many concerns into a single class. The more concerns that build up in the class, the more opportunites that bugs will occur.

Form Objects are Not Always Used with a UI Form

The sooner one realizes that a form object is not always used in conjunction with a UI form the quicker one will begin to understand the form object’s true place within a system. Following are some of the situations in which you might use a form object:

  • In the Rails console when you want to create a valid record
  • In the create or update action for a REST API
  • When importing records from a flat file

If you use forms correctly there is no longer a need to define any validations on your ActiveRecord model classes. If this makes you feel uncomforatble, ask yourself why? To truly have a layer of indirection between the application and ORM, you should only directly use the ActiveRecord model layer within the form and query objects when employing this pattern.

The Reform Gem

When implementing form objects, I prefer to use the reform gem by apotonick. It already has a very well thought out and designed API and it is still a pre 1.0 release. A bonus feature with this gem is it plays nicely with Rails’ built-in form builders and 3rd party form builders formtastic and simple_form. You can pass the form object to these builders in place of the model and everything will work as expected.

I have been thinking and experimenting with different techniques to make Rails applications manageable as they grow for about 2 years now. This exercise is not because I desire to add layers/complexity to my Rails applications, but because I have experienced the pain that a Rails application can provide as it matures. In this multi-part series I will break down some of the successful techniques I am using to achieve my goals.

One of my starting places was this article by Bryan Helmkamp. I will often reference this article in this series. Thanks Bryan for sharing your techniques.

I agree with Bryan the suggestion to make “fat models” is not a best practice. The model should not contain logic that does not directly correspond to reading/writing to the database.

Part 1

The first technique Bryan discusses in his article is to “Extract Value Objects.” According to Bryan, value objects are, “simple objects whose equality is dependent on their value rather than an identity.” This is an important conecpt taken from domain driven design. In his book on DDD, Eric Evans states: “Many objects have no conceptual identity. These objects describe characteristics of a thing.”

A great example of a value object is color:

class Color
  include Comparable

  def initialize(key)
    @key = key
  end

  def <=>(other)
    other.to_s <=> to_s
  end

  def eql?(other)
    to_s == other.to_s
  end

  def to_s
    @key.to_s
  end
end

Value Objects in the Model

It is common practice for developers to define value objects in a model, usually as a constant in the model.

class Car < ActiveRecord::Base
  COLOR = %w(
    black
    blue
    green
  )
end

This practice is not good because the value object may be used in attribute(s) of a model, but has nothing directly to do with the domain the model is representing. Defining value objects inline in the model class carries the at least following disadvantages:

  • Impossible to add functionality to value object without further polluting the model
  • Limits reuse of the value object
  • Harder to test

Value Objects in the Database

Quite often, developers will include value objects in the database as a model. This is also bad form. The value object is not dynamic so it does not necessitate use of the database. In addition, the value object has no identity, so we do not need a keying system. The only value the database really provides in this case is the limiting of the valid values for a value object to some predefined set that can be enforced.

Enumerative Gem

Enter the enumerative gem. This gem was authored by Nils Jonsson and myself. The enumerative gem provides the tools necessary to create value objects that are limited to a finite set of valid values.

An enumeration for color might be implemented like:

class Color

  def self.valid_keys
    %w(
      black
      blue
      green
    )
  end

  include Enumerative::Enumeration

end

In addition, you must add the translations for the enumeration’s values to the config/en.yml file:

en:
  enumerations:
    color:
      black: Black
      blue: Blue
      green: Green

Now you can use the enumeration.

Color::BLACK # #<Color:0x000001015e6aa8 @key="black">
Color::BLACK.key # "black"
Color::BLACK.value # "Black"
Color.to_select # [["Black", "black"], ["Blue", "blue"], ["Green", "green"]]
Color.new('black').valid? # true
Color.new('some invalid value').valid? # false

The initiatlizer is very forgiving of the values it will accept so that it can be used to easily standardize input, etc.

Color.new(Color::BLACK) # #<Color:0x000001015e7aa0 @key="black">
Color.new('black') # #<Color:0x000001015e7aa0 @key="black">
Color.new(key: 'black') # #<Color:0x000001015e7aa0 @key="black">
Color.new(key: :black) # #<Color:0x000001015e7aa0 @key="black">

HasEnumeration Module

It gets even more exciting when you want to use it in a model. If you included the Enumerative::HasEnumeration module you get automatic casting from the key that is stored in the database to the type of the enumeration your attribute is defined as on a read and back to the key for storage on a write.

class Car < ActiveRecord::Base
  include Enumerative::HasEnumeration

  has_enumeration color, from: Color
end

Convenience when you read from the database:

car = Car.first
car.color_before_type_cast # "black"
car.color # #<Color:0x000001015e7aa0 @key="black">

Convenience when you write to the database

car = Car.new
car.color = Color::BLACK
color.save!
car.reload
car.color_before_type_cast # "black"
car.color # #<Color:0x000001015e7aa0 @key="black">

Testing Enumerations

Enumerative provides some a shared spec for easier specing of enumerations. Following is an example spec for the color enumeration.

require 'spec_helper'
require 'enumerative/enumeration_sharedspec'

describe Color do

  it_should_behave_like 'an Enumeration'

  def self.keys
    %w(
      black
      blue
      green
    )
  end

  self.keys.each do |key|
    const = key.upcase

    it "should have #{const}" do
      described_class.const_get( const ).should be_valid
    end
  end

  it "should have the correct select-box values" do
    described_class.to_select.should == [
      ["Black", "black"],
      ["Blue", "blue"],
      ["Green", "green"]
    ]
  end
end

Project Organization

I recommend placing enumerations in the app/enumerations directory.

Conclusion

With very little effort we have extracted our value object out of the database and retained the ability to limit the valid values to a finite set. We can also use our value object in a model and persist the model’s value for the enumeration in the database. Most importantly, we have successfully removed a common contributer to making Rails models bloated and unmanageable.

Stay tuned for the next installment in the series.

Background

Ignoring the existence of events in a program leads to harder to understand/debug code. Events implicitly exist in all programs and if not explicitly utilized do not go away.

It is obvious that events can help you write loosely coupled class and allow multiple objects to subscribe to a single event. However, events can also help you conform to the Tell, Don’t Ask Principle.

Tell, Don’t Ask Principle

Instead of asking an object a question about it’s state, making a descision, and proceeding forward we should strive to tell an object what to do.

Procedural code gets information then makes decisions. Object-oriented code tells objects to do things.

— Alec Sharp

Let’s look at some simple examples of a Rails controller action:

Normal Rails Controller

Here is an example you are sure to recognize as it is the normal way of writing a create action for a Rails controller.

class TasksController < ApplicationController

  def create
    @task = Task.new(params[:task])

    if @task.save
      respond_to do |format|
        format.html { redirect_to task_path( @task ) }
      end
    else
      respond_to do |format|
        format.html { render :new }
      end
    end
  end

end

This implementation is not good because we are examining the state of the created task to determine what to do next. Not to mention, lots of business logic, which has nothing to do with the HTTP protocol, is happening in the controller. How are you going to test it?

Rails Controller Action With a Service Class Extracted

Now, we will extract that create logic to a service class the controller can use.

class CreateTaskService

  attr_reader :task

  def initialize(attributes)
    @attributes = attributes
  end

  def call
    @task = Task.create(attributes)
  end

  def success?
    task.valid?
  end

protected

  attr_reader :attributes

end
class TasksController < ApplicationController

  def create
    create_service.call

    if create_service.success?
      task = create_service.task
      respond_to do |format|
        format.html { redirect_to task_path(task) }
      end
    else
      respond_to do |format|
        format.html { render :new }
      end
    end
  end

protected

  def create_service
    @create_service ||= CreateTaskService.new(params[:task])
  end

end

While we know that extracting complex logic out of the controller into another class is a good idea, this particular implementation is just plain ugly. The problem with this implementation is the controller is asking the service class about it’s state and then telling it to do additional tasks.

Rails Controller Action With a Service Class Extracted Utilizing Events

Why not let the service class tell the controller what happened?

In the next example we will use the wisper gem to allow the controller to subscribe to events the service class may publish.

class CreateTaskService

  include Wisper::Publisher

  def initialize(attributes)
    @attributes = attributes
  end

  def call
    task = Task.create(attributes)

    if task.valid?
      publish :success, task
    else
      publish :validation_error, task
    end
  end

protected

  attr_reader :attributes

end
class TasksController < ApplicationController

  def create
    create_service.on :success do |task|
      respond_to do |format|
        format.html { redirect_to task_path(task) }
      end
    end

    create_service.on :validation_error do |task|
      respond_to do |format|
        format.html do 
          @task = task
          render :new
        end
      end
    end

    create_service.call
  end

protected

  def create_service
    @create_service ||= CreateTaskService.new(params[:task])
  end

end

This is a much better implementation. Without sacrificing the relatively linear flow of the code, we have obeyed the tell, don’t ask principle. In addition, we have explicitly acknowledged the presence of events, which makes the code easier to understand.

The ease of comprehension benefit may not seem like a big advantage in the prior example. However, imagine the case where you are 5 levels deep in an object graph that is employing a strategy pattern. Without the use of events to message directly to the outer most object your only option is proxy methods. Good luck tracing that quickly.

As a bonus, things get even better if we need some orthogonal piece of work to occur when the task is successfully created:

class TasksController < ApplicationController

  def create
    create_service.subscribe( task_email_listener,
                              on: :success,
                              with: :task_created )

    create_service.on :success do |task|
      # ...
    end

    create_service.on :validation_error do |task|
      # ...
    end

    create_service.call
  end

protected

  def create_service
    @create_service ||= CreateTaskService.new(params[:task])
  end

  def task_email_listener
    TaskEmailListener.new
  end

end
class TaskEmailListener

  def task_created( task )
    TaskMailer.assignment_email( task ).deliver
  end

end

Wow, we have now accomplished sending an email without tightly coupling it to the CreateTaskService or using ActiveRecord callbacks. This means the CreateTaskService can be used other places in our code without sending an email. This also means when we create a Task in the Rails console, we will not accidentally send an email.