Filters enable controllers to run shared pre and post processing code for its actions. These filters can be used to do authentication, caching, or auditing before the intended action is performed. Or to do localization or output compression after the action has been performed.

Filters have access to the request, response, and all the instance variables set by other filters in the chain or by the action (in the case of after filters). Additionally, it’s possible for a pre-processing before_filter to halt the processing before the intended action is processed by returning false. This is especially useful for filters like authentication where you’re not interested in allowing the action to be performed if the proper credentials are not in order.

Filter inheritance

Controller inheritance hierarchies share filters downwards, but subclasses can also add new filters without affecting the superclass. For example:

  class BankController < ActionController::Base
    before_filter :audit

    private
      def audit
        # record the action and parameters in an audit log
      end
  end

  class VaultController < BankController
    before_filter :verify_credentials

    private
      def verify_credentials
        # make sure the user is allowed into the vault
      end
  end

Now any actions performed on the BankController will have the audit method called before. On the VaultController, first the audit method is called, then the verify_credentials method. If the audit method returns false, then verify_credentials and the intended action is never called.

Filter types

A filter can take one of three forms: method reference (symbol), external class, or inline method (proc). The first is the most common and works by referencing a protected or private method somewhere in the inheritance hierarchy of the controller by use of a symbol. In the bank example above, both BankController and VaultController uses this form.

Using an external class makes for more easily reused generic filters, such as output compression. External filter classes are implemented by having a static filter method on any class and then passing this class to the filter method. Example:

  class OutputCompressionFilter
    def self.filter(controller)
      controller.response.body = compress(controller.response.body)
    end
  end

  class NewspaperController < ActionController::Base
    after_filter OutputCompressionFilter
  end

The filter method is passed the controller instance and is hence granted access to all aspects of the controller and can manipulate them as it sees fit.

The inline method (using a proc) can be used to quickly do something small that doesn’t require a lot of explanation. Or just as a quick test. It works like this:

  class WeblogController < ActionController::Base
    before_filter proc{ |controller| return false if controller.params["stop_action"] }
  end

As you can see, the proc expects to be passed the controller after it has assigned the request to the internal variables. This means that the proc has access to both the request and response objects complete with convenience methods for params, session, template, and assigns. Note: The inline method doesn’t strictly has to be a Proc. Any object that responds to call and returns 1 or -1 on arity will do (such as a Method object).

Filter chain ordering

Using before_filter and after_filter appends the specified filters to the existing chain. That’s usually just fine, but some times you care more about the order in which the filters are executed. When that’s the case, you can use prepend_before_filter and prepend_after_filter. Filters added by these methods will be put at the beginning of their respective chain and executed before the rest. For example:

  class ShoppingController
    before_filter :verify_open_shop

  class CheckoutController
    prepend_before_filter :ensure_items_in_cart, :ensure_items_in_stock

The filter chain for the CheckoutController is now :ensure_items_in_cart, :ensure_items_in_stock, :verify_open_shop. So if either of the ensure filters return false, we’ll never get around to see if the shop is open or not.

Methods
Public Instance methods
after_filter(*filters)
append_after_filter(*filters)

The passed filters will be appended to the array of filters that’s run after actions on this controller are performed.

This method is also aliased as after_filter
     # File lib/action_controller/filters.rb, line 110
110:       def append_after_filter(*filters)  append_filter("after", filters) end
append_before_filter(*filters)

The passed filters will be appended to the array of filters that’s run before actions on this controller are performed.

This method is also aliased as before_filter
    # File lib/action_controller/filters.rb, line 99
99:       def append_before_filter(*filters)  append_filter("before", filters) end
before_filter(*filters)
prepend_after_filter(*filters)

The passed filters will be prepended to the array of filters that’s run after actions on this controller are performed.

     # File lib/action_controller/filters.rb, line 114
114:       def prepend_after_filter(*filters) prepend_filter("after", filters) end
prepend_before_filter(*filters)

The passed filters will be prepended to the array of filters that’s run before actions on this controller are performed.

     # File lib/action_controller/filters.rb, line 103
103:       def prepend_before_filter(*filters) prepend_filter("before", filters) end
Private Instance methods
append_filter(condition, filters)
     # File lib/action_controller/filters.rb, line 130
130:         def append_filter(condition, filters)
131:           write_inheritable_array("#{condition}_filters", filters)
132:         end
prepend_filter(condition, filters)
     # File lib/action_controller/filters.rb, line 134
134:         def prepend_filter(condition, filters)
135:           write_inheritable_attribute("#{condition}_filters", filters + read_inheritable_attribute("#{condition}_filters"))
136:         end