Archive for August, 2009

One of the first things we learn in Rails which are greatly useful are ActiveRecord validations. However, since they are easy to add, it happens frequently that we are burdening our users with validations instead of making forms easier and clearer.

For instance, let’s suppose we are validating the Social Security Number (SSN) of an user on signup. A sample code would be:

1
2
3
4
5
6
7
class User < ActiveRecord::Base
  validates_presence_of :ssn
  validates_length_of :ssn, :is => 9
  validates_numericality_of :ssn
  validates_uniqueness_of :ssn
  validates_as_ssn :ssn # Checks if a reserved or special SSN was sent
end

With the configuration above, if the user forgets to fill in the SSN, leaving it blank, four error messages related to the SSN field will be shown:

  • SSN can’t be blank
  • SSN is the wrong length (should be 9 characters)
  • SSN is not a number
  • SSN is invalid

The question is: if the user just left the field blank, why we should show all those errors to him? Are they all relevant?

OMG! What have I done wrong to appear so many errors?

OMG! What have I done wrong to appear so many errors?

Luckily, the solution is quite simple: we can make use of the :allow_blank option, so other validations won’t be triggered if the field is blank:

1
2
3
4
5
6
7
class User < ActiveRecord::Base
  validates_presence_of :ssn
  validates_length_of :ssn, :is => 11, :allow_blank => true
  validates_numericality_of :ssn, :allow_blank => true
  validates_uniqueness_of :ssn, :allow_blank => true
  validates_as_cpf :ssn, :allow_blank => true
end

This is also a nice use case for the Object#with_options method added by Rails:

1
2
3
4
5
6
7
8
9
10
class User < ActiveRecord::Base
  validates_presence_of :ssn
 
  with_options :allow_blank => true do |v|
    v.validates_length_of :ssn, :is => 11
    v.validates_numericality_of :ssn
    v.validates_uniqueness_of :ssn
    v.validates_as_cpf :ssn
  end
end

SSN is just an example, but we are frequently burdening our users in username, e-mail, password and many other fields.

Do not validate presence of confirmation fields

Another interesting subject about validations are the confirmation fields. We have the following note in the documentation of validates_confirmation_of:

1
2
validates_confirmation_of :password
# NOTE: This check is performed only if password_confirmation is not nil

And this is a feature. This means that you don’t need to give the :password_confirmation key when creating objects in console or when writing tests:

1
2
3
it "should be valid with valid attributes" do
  User.new(:password => "123456").should be_valid
end

If the test fails, you are validating the presence of :password_confirmation, which is unnecessary. Since the :password_confirmation field will be available in the views, it will always be sent. So if the user leave it blank, it’s sent as blank value to the model and therefore will be checked. Just in the place it needs to be.

First, what is Inherited Resources?

Inherited Resources is a gem/plugin that allows you to speed up development by making your controllers inherit all restful actions so you just have to focus on what is important. A Rails scaffold controller which responds to html, xml and json is as simple as:

1
2
3
class ProjectsController < InheritedResources::Base
  respond_to :html, :xml, :json
end

However all actions are still customizable! For example, you can change the behavior of the create action on success just doing:

1
2
3
4
5
6
7
8
9
class ProjectsController < InheritedResouces::Base
  respond_to :html, :xml, :json
 
  def create
    create! do |success, failure|
      success.html { redirect_to edit_project_url(@project) }
    end
  end
end

It also supports I18n (all flash messages are set with I18n), belongs to association (like a task belongs to project), nested belongs to (task belongs to project which belongs to company), polymorphic belongs to (comments belong to task or file or message) and optional belongs to (the same as previously, but you can request the resource with or without parents).

As you noticed, besides simplifying your controllers, InheritedResouces makes easy to reproduce your models behavior and relationship in controllers. And right now, it’s also scopes and responder fluent!

has_scope: named_scope twin brother

Let’s suppose that we have a ProjectsController and at some point you want to add some filters on the index action like showing just featured projects, selecting projects by methodology or even let the user choose how many projects he can see per page. The first thing to do? Add named scopes to your model:

1
2
3
4
5
class Project < ActiveRecord::Base
  named_scope :featured, :conditions => { :featured => true }
  named_scope :by_methodology, proc {|methodology| { :conditions => { :methodology => methodology } } }
  named_scope :limit, proc{|limit| :limit => limit.to_i }
end

The next step would be to add a lot of code in your controllers that check which named scopes you should call, based on the parameters sent right? Well, not anymore. Your controller can be as simple as:

1
2
3
4
5
class ProjectsController < InheritedResources::Base
  has_scope :featured, :boolean => true
  has_scope :by_methodology
  has_scope :limit, :default => 10, :only => :index
end

Then for each request:

/projects
#=> acts like a normal request, but returning only 10 projects

/projects?featured=true
#=> calls the featured named scope and bring 10 featured projects

/projects?featured=true&by_methodology=agile&limit=20
#=> brings 20 featured projects with methodology agile

If you configure your routes, you could even have pretty urls with it:

/projects/agile/featured
#=> brings 10 featured projects with methodology agile

Yay!

Responder

A couple weeks ago, we wrote about ActionController::Responder. But you don’t have to wait Rails 3 to be released to play with it, you can start now by using Inherited Resources.

Quick redirect

After using Inherited Resouces, I realized that most of the times I overwrite a create, update or destroy actions is to change the redirect destination. In our ProjectsController above, if we want to redirect to the edit page after create, we would have to do:

1
2
3
4
5
6
7
8
9
class ProjectsController < InheritedResouces::Base
  respond_to :html, :xml, :json
 
  def create
    create! do |success, failure|
      success.html { redirect_to edit_project_url(@project) }
    end
  end
end

It wouldn’t be cool if it have a shortcut? Now it has:

1
2
3
4
5
6
7
class ProjectsController < InheritedResouces::Base
  respond_to :html, :xml, :json
 
  def create
    create! { edit_project_url(@project) }
  end
end

That simple, just give the url as a proc and since the proc does not expect any parameters, it assumes that you want to overwrite the redirect url.

Finally some DSL?

Last weeks, there was a discussion on Boston.rb group about different resource controllers gems. Reading some of the feedback there, I’ve decided to stab a DSL to Inherited Resources. It will mainly remove the duplication when you have to give a block, the previous example above could be written as:

1
2
3
4
5
6
7
class ProjectsController < InheritedResouces::Base
  respond_to :html, :xml, :json
 
  create! do |success, failure|
    success.html { redirect_to edit_project_url(@project) }
  end
end

Or even in the compact form:

1
2
3
4
class ProjectsController < InheritedResouces::Base
  respond_to :html, :xml, :json
  create! { redirect_to edit_project_url(@project) }
end

Those changes were not applied yet, it depends mainly on you. If you like or not, let us know in the comments!

Uma das primeira coisas que aprendemos em Rails e que são de grande utilidade são as validações do ActiveRecord. Porém, como as validações são muito fáceis de adicionar e remover, temos que ter certeza que não estamos sobrecarregando nossos usuários com validações.

Por exemplo, supondo que estamos validando o CPF do usuário no cadastro e temos o seguinte código:

1
2
3
4
5
6
7
class User < ActiveRecord::Base
  validates_presence_of :cpf
  validates_length_of :cpf, :is => 11
  validates_numericality_of :cpf
  validates_uniqueness_of :cpf
  validates_as_cpf :cpf # Checa se o cálculo de dígitos é correto
end

Na configuração acima, se o usuário esquece de preencher o campo CPF, deixando-o em branco, nada menos que quatro erros aparecerão para ele:

  • Campo CPF não pode ficar em branco;
  • Campo CPF deve possuir 11 caracteres;
  • Campo CPF deve possuir apenas números;
  • Campo CPF é inválido.

Se o usuário deixou apenas o campo em branco, porque mostrar todos esses erros para ele? Todos os erros mostrados são relevantes?

Ó céus! O que fiz de errado para aparecer tantos erros?

Ó céus! O que fiz de errado para aparecer tantos erros?

Felizmente, a solução é simples, apenas adicione :allow_blank nas validações que elas não serão calculadas caso o campo seja enviado vazio:

1
2
3
4
5
6
7
class User < ActiveRecord::Base
  validates_presence_of :cpf
  validates_length_of :cpf, :is => 11, :allow_blank => true
  validates_numericality_of :cpf, :allow_blank => true
  validates_uniqueness_of :cpf, :allow_blank => true
  validates_as_cpf :cpf, :allow_blank => true
end

Você também pode usar o método Object#with_options adicionado pelo Rails para agrupar as validações:

1
2
3
4
5
6
7
8
9
10
class User < ActiveRecord::Base
  validates_presence_of :cpf
 
  with_options :allow_blank => true do |v|
    v.validates_length_of :cpf, :is => 11
    v.validates_numericality_of :cpf
    v.validates_uniqueness_of :cpf
    v.validates_as_cpf :cpf
  end
end

O campo CPF é apenas um exemplo, mas estamos sobrecarregando os nossos usuários frequentemente nos campos username, e-mail, password e outros.

Não exija a presença de campos confirmação

Um outro tópico que vale a pena ser discutido sobre validações são campos de confirmação. Existe a seguinte nota na documentação do Rails para validates_confirmation_of:

1
2
validates_confirmation_of :password
# Nota: essa validação ocorre apenas se o campo :password_confirmation não for nulo.

E isso é uma feature. Isso significa que nos seus testes ou ao criar um objeto no console, você não precisa passar o campo :password_confirmation:

1
2
3
it "should be valid with valid attributes" do
  User.new(:password => "123456").should be_valid
end

Se por acaso o teste falhar, é porque você adicionou a validação de presença para o campo :password_confirmation, que é desnecessária. Como o campo :password_confirmation estará presente nas views, ele sempre será enviado e portanto sempre será checado, justamente onde é necessário.

UPDATE: ActionController::Renderer was renamed to ActionController::Responder, so this post was changed to properly reflect such changes.

About two and a half years ago, resources started to be a first class citizen in Rails when version 1.2 was released and it was all about RESTful admiration and HTTP Lovefest. Since then we’ve added map.resources to our routes, started to use different formats in respond_to and really learned how to love all HTTP verbs.

Your application entry point (the router) has become completely RESTful, but it still haven’t reached ActionPack core. Today we are bringing the missing ingredient: make your controllers more resource aware.

The first step: respond_with(@resource)

About one week ago the first step was given. We brought Merb’s provide/display into Rails, just as DHH proposed: you can define supported formats at the class level and tell in the instance the resource to be represented by those formats. Let’s see some code:

  class UsersController < ApplicationController
    respond_to :html, :xml, :json
 
    def index
      @users = User.all
      respond_with(@users)
    end
  end

It works like this: when a request comes, for example with format xml, it will first search for a template at users/index.xml. If the template is not available, it tries to render the resource given (in this case, @users) by calling :to_xml on it. Before Rails 3.0, the equivalent to the index action above would be:

  class UsersController < ApplicationController
    def index
      @users = User.all
      respond_to do |format|
        format.html
        format.xml { render :xml => @users }
        format.json { render :json => @users }
      end
    end
  end

The gain with respond_with introduction is more obvious if you compare index, new and show actions:

  class UsersController < ApplicationController
    respond_to :html, :xml, :json
 
    def index
      @users = User.all
      respond_with(@users)
    end
 
    def new
      @user = User.new
      respond_with(@user)
    end
 
    def show
      @user = User.find(params[:id])
      respond_with(@user)
    end
  end

With older version:

  class UsersController < ApplicationController
    def index
      @users = User.all
      respond_to do |format|
        format.html
        format.xml { render :xml => @users }
        format.json { render :json => @users }
      end
    end
 
    def new
      @user = User.new
      respond_to do |format|
        format.html
        format.xml { render :xml => @user }
        format.json { render :json => @user }
      end
    end
 
    def show
      @user = User.find(params[:id])
      respond_to do |format|
        format.html
        format.xml { render :xml => @user }
        format.json { render :json => @user }
      end
    end
  end

However, even if respond_with is full featured (Ryan Daigle has done an excellent job covering all respond_with features), it started to show some flaws on create, update and destroy actions. A default create action could be written with respond_with as:

  def create
    @user = User.new(params[:user])
    if @user.save
      flash[:notice] = "User was created successfully."
      respond_with(@user, :status => :created, :location => @user) do |format|
        format.html { redirect_to @user }
      end
    else
      respond_with(@user.errors, :status => :unprocessable_entity) do |format|
        format.html { render :action => :new }
      end
    end
  end

You can notice that:

  1. You have to call respond_with twice;
  2. On the first respond_with, you have to give the location twice. One as a hash and other as parameter to redirect_to;
  3. And by giving a block to respond_with, you focus more on the exception than on the default behavior.

Suddenly we realized that respond_with is useful just for GET requests. There was no HTTP Lovefest, it was more like HTTP monotheism.

2. Second step: Love all

At this point, we started to ask ourselves: why can’t respond_with include HTTP verb semantics? Isn’t that what RESTful is all about?

After this commit, we brought all HTTP verbs to respond_with, but only for resourceful formats like xml and json (ie. formats that don’t need to render a template). Then our create action with POST request could be rewritten as:

  def create
    @user = User.new(params[:user])
    respond_with(@user) do |format|
      if @user.save
        flash[:notice] = "User was created successfully."
        format.html { redirect_to @user }
      else
        format.html { render :action => :new }
      end
    end
  end

Internally, when a xml request happened, respond_with would check the current request method (in this case, POST) and whether the resource has errors or not. Depending on these values, it will render the resource or the resource errors, setting accordingly the status and location headers. Now we just have to worry with non-RESTful requests, like html, mobile and iphone… (which we call navigational formats).

Personally, I was quite happy with the results at this iteration, since it solves two of the three problems exposed previously. However, Jeremy Kemper and Yehuda Katz wanted more. And they were right, yeah!

3. Third step: Responder

In step 2, we were able to abstract POST, PUT and DELETE requests for formats like xml and json, but we still would have to repeat html behavior through all controllers, even if almost all of them behave similarly.

So what we want is a simple way to tell the controller how to render our resources depending on the format AND HTTP verb. In this commit, we’ve added ActionController::Responder.

By default, ActionController::Responder holds all formats behavior in a method called to_format. It’s similar to this:

  def to_format
    return render unless resource.respond_to?(:"to_#{format}")
 
    if get?
      render format => resource
    elsif has_errors?
      render format => resource.errors, :status => :unprocessable_entity
    elsif post?
      render format => resource, :status => :created, :location => resource
    else
      head :ok
    end
  end

As you can see, it renders the resource based on the HTTP verb and whether it has errors or not. If some format, like :html, does not fall into the to_format behavior, we just need to define a to_html in ActionController::Responder, which by default is:

  def to_html
    if get?
      render
    elsif has_errors?
      render :action => (post? ? :new : :edit)
    else
      redirect_to resource
    end
  end

As result, you have your resources representation encapsulated in one place. Your controller code just have to send the resource using respond_with(@resource) and respond_with will call ActionController::Responder which will know what to do. Our create action (POST request) can then be written as:

  def create
    @user = User.new(params[:user])
    flash[:notice] = "User was created successfully." if @user.save
    respond_with(@user)
  end

If you need to change the redirect URL, you can overwrite just the html behavior:

  def create
    @user = User.new(params[:user])
    flash[:notice] = "User was created successfully." if @user.save
    respond_with(@user) do |format|
      format.html { redirect_to user_confirmation_url }
    end
  end

On the other hand, if you want to change the redirect url and the Location header for XML and JSON, you can simply give :location as option:

  def create
    @user = User.new(params[:user])
    flash[:notice] = "User was created successfully." if @user.save
    respond_with(@user, :location => user_confirmation_url)
  end

The best of all is that the responder implementation is quite simple and straight-forward, but still powerful. We haven’t enforced any restriction in the API. Anything that responds to :call can be a responder, so you can create your custom classes or even give procs, fibers and so on.

Embrace REST in your design and enjoy a consistent behavior through all your controllers. Spread the word!