Filters

To achieve DRY code in controllers Rails provides feature called - filters. Filters are methods that get executed before, after or before and after code. Filters named after their behaviour: before_filter, after_filter, around_filter (which executes before and after code).

Before filters are often used for authentication, as you can see below. Lets take our controller and add before_filter:
class BooksController < ApplicationController

  before_filter :login_required, :only => ["new", "create", "edit", "update"]

  def index
    revs = Review.all
    @review1 = Review.find(revs.rand.id)
    @review2 = Review.find(revs.rand.id)
    @books = Book.all(:order => 'created_at DESC', :limit => 3)
  end

  def list
      @books = Book.search(params[:search])
  end

  def show
    @book = Book.find(params[:id])
    @genres = @book.genres.map {|genre| genre.name}.compact.join(' , ')
    @authors = @book.authors
    if @current_user
      @readings = @current_user.readings.map{|b| b.read }
    end
  end

  def new
    @book = Book.new
    @authors = Author.all
    @genres = Genre.all

    respond_to do |wants|
      wants.html
    end
  end

  def create
    @book = Book.new(params[:book])
    @genres = Genre.all
    @authors = Author.all
    @book = @current_user.books.build params[:book]

    respond_to do |wants|
      if @book.save
        wants.html do
          flash[:notice] = "Successfully created book." 
          redirect_to @book
        end
      else
        wants.html { render :action => 'new' }
      end
    end
  end

  def edit
    @book = Book.find(params[:id])
    @genres = Genre.all
    @authors = Author.all
    if @current_user.id == @book.user.id && @book.readers.length == 0
        respond_to do |wants|
            wants.html
        end
    else
    flash[:error] = 'You cannot edit this book.'
    redirect_to @book
    end
  end

  def update
    @book = Book.find(params[:id])
    params[:book][:genre_ids] ||= []
    params[:book][:author_ids] ||= []
    respond_to do |wants|
      if @book.update_attributes(params[:book])
        wants.html do
          flash[:notice] = "Successfully updated book." 
          redirect_to @book
        end
      else
        wants.html { render :action => 'edit' }
      end
    end
  end

  def destroy
    @book = Book.find(params[:id])
    if @current_user.id == @book.user.id && @book.readers.length == 0
      @book.destroy
      flash[:notice] = "Successfully removed book." 
      redirect_to books_url
    else
      flash[:error] = "Cannot remove book." 
      redirect_to books_url
    end
  end
end
The login_required method is defined in the application_controller, but this method can be defined right in books_controller.
private
  def login_required
            return true if logged_in?
            session[:return_to] = request.request_uri
            redirect_to new_session_path and return false
  end

It is better to put this code in the application_controller so you can use it in all your controllers.

Filters can have options :only and :except just as you saw in the Views_and_layouts section.

Looking at the controller above, we can still find duplicate lines in controller.
The line:
@book = Book.find(params[:id])
is in four methods show,edit, update, and destroy. To remove this duplication, we can add another before filter to the book_controller:
private
  def find_book
    @book = Book.find(params[:id])
  end
And then add the new before_filter to the top of controller:
  before_filter :login_required, :only => ["new", "create", "edit", "update"]
  before_filter :find_book, :only => ["show", "edit", "update", "destroy"]

So now we can delete line
@book = Book.find(params[:id])
from top of actions: show, edit, update, destroy.

If you define a before_filter in application_controller, then that filter will execute for every controller. However, Rails contains method skip_defore_filter which allows you to bypass this functionality for a specific controller.
To use it, just enter :

skip_before_filter :filter_name
right after controller definition.

Additional resources

  1. Rails Guides: Action controller overview

Also available in: HTML TXT