before_filter wisdom

Dan Croak

Using Rails’ before_filter is a great way to keep your controller actions clean by moving logic about authentication, authorization, or state of the resource out of the main method, right?

The common wisdom

Here’s a typical usage of before_filter:

class Admin::ArticlesController < ApplicationController
  before_filter :deny_access, :unless => :draft_and_admin?

  def show
    @article = Article.find(params[:id])
  end

  protected

  def draft_and_admin?
    Article.find(params[:id]).draft? && current_user.admin?
  end
end

Awesome. We deny the user access to the show action if the article is a draft and they are not an admin. The show action looks standard. When we look at the top of the file, we see a nice one-liner encapsulating concerns of authorization.

The hip wisdom

If we were using a RESTful controller abstraction such as inherited_resources, our code might look like this:

class Admin::ArticlesController < InheritedResources::Base
  before_filter :deny_access, :unless => :draft_and_admin?
  actions :show

  protected

  def draft_and_admin?
    Article.find(params[:id]).draft? && current_user.admin?
  end
end

The shortest of our three options, this approach requires more knowledge of the libraries in use.

The old-school wisdom

What if it looked like this?

class Admin::ArticlesController < ApplicationController
  def show
    if draft_and_admin?
      @article = Article.find(params[:id])
      render
    else
      deny_access
    end
  end

  protected

  def draft_and_admin?
    Article.find(params[:id]).draft? && current_user.admin?
  end
end

This is not standard Rails!

Yet all the logic is inline inside the action. It reads sequentially. It even has an explicit render in there, thumbing its nose at the Rails way!

The core responsibility of the action (fetching the Article of a given id) is more muddled here but the path of the code is clear to any Rubyist. No special knowledge required.

The Questions

What advantage does before_filter provide that Ruby does not? Does the before_filter layer of indirection make the code easier or harder to read? Do RESTful controller abstractions influence our preference?