Jump To Content

LearnHub




Action Controller: Filters

Filters

Filters are methods that are run before, after or "around" a controller action. For example, one filter might check to see if the logged in user has the right credentials to acces s that particular controller or action. Filters are inherited, so if you set a filter on ApplicationController, it will be run on every controller in your application. A common, s imple filter is one which requires that a user is logged in for an action to be run. Let's define the filter method first:


class ApplicationController < ActionController::Base

private

  def require_login
    unless logged_in?
      flash[:error] = "You must be logged in to access this section" 
      redirect_to new_login_url # Prevents the current action from running
    end
  end

  # The logged_in? method simply returns true if the user is logged in and
  # false otherwise. It does this by "booleanizing" the current_user method
  # we created previously using a double ! operator. Note that this is not
  # common in Ruby and is discouraged unless you really mean to convert something
  # into true or false.
  def logged_in?
    !!current_user
  end

end

The method simply stores an error message in the flash and redirects to the login form if the user is not logged in. If a before filter (a filter which is run before the action) r enders or redirects, the action will not run. If there are additional filters scheduled to run after the rendering/redirecting filter, they are also cancelled. To use this filter in a controller, use the before_filter method:


class ApplicationController < ActionController::Base

  before_filter :require_login

end

In this example, the filter is added to ApplicationController and thus all controllers in the application. This will make everything in the application require the user to be logg ed in in order to use it. For obvious reasons (the user wouldn't be able to log in in the first place!), not all controllers or actions should require this, so to prevent this fil ter from running you can use skip_before_filter


class LoginsController < Application

  skip_before_filter :require_login, :only => [:new, :create]

end

Now, the LoginsController's "new" and "create" actions will work as before without requiring the user to be logged in. The `:only` option is used to only skip this filter for thes e actions, and there is also an `:except` option which works the other way. These options can be used when adding filters too, so you can add a filter which only runs for selected actions in the first place.

After filters and around filters

In addition to the before filters, you can run filters after an action has run or both before and after. The after filter is similar to the before filter, but because the action h as already been run it has access to the response data that's about to be sent to the client. Obviously, after filters can not stop the action from running. Around filters are res ponsible for running the action, but they can choose not to, which is the around filter's way of stopping it.


# Example taken from the Rails API filter documentation:
# http://api.rubyonrails.org/classes/ActionController/Filters/ClassMethods.html
class ApplicationController < Application

  around_filter :catch_exceptions

private

  def catch_exceptions
    yield
  rescue => exception
    logger.debug "Caught exception! #{exception}" 
    raise
  end

end

Other ways to use filters

While the most common way to use filters is by creating private methods and using *_filter to add them, there are two other ways to do the same thing.

The first is to use a block directly with the *_filter methods. The block receives the controller as an argument, and the `require_login` filter from above could be rewritte to us e a block:


class ApplicationController < ActionController::Base

  before_filter { |controller| redirect_to new_login_url unless controller.send(:logged_in?) }

end

Note that the filter in this case uses `send` because the `logged_in?` method is private and the filter is not run in the scope of the controller. This is not the recommended way to implement this particular filter, but in more simple cases it might be useful.

The second way is to use a class (actually, any object that responds to the right methods will do) to handle the filtering. This is useful in cases that are more complex than can not be implemented in a readable and reusable way using the two other methods. As an example, we will rewrite the login filter again to use a class:


class ApplicationController < ActionController::Base

  before_filter LoginFilter

end

class LoginFilter

  def self.filter(controller)
    unless logged_in?
      controller.flash[:error] = "You must be logged in to access this section" 
      controller.redirect_to controller.new_login_url
    end
  end

end

Again, this is not an ideal example for this filter, because it's not run in the scope of the controller but gets it passed as an argument. The filter class has a class method `fi lter` which gets run before or after the action, depending on if it's a before or after filter. Classes used as around filters can also use the same `filter` method, which will ge t run in the same way. The method must `yield` to execute the action. Alternatively, it can have both a `before` and an `after` method that are run before and after the action.

The Rails API documentation has more information on using filters.

Articles in this guide

  1. Introduction
  2. What does a controller do?
  3. Parameters
  4. Sessions
  5. Cookies
  6. Filters (This article)
  7. Verification
  8. The request and response objects
  9. HTTP Basic Authentication
  10. Streaming and file downloads
  11. Parameter filtering
  12. Rescue

Thanks to the Ruby on Rails documentation team

This guide was written by Tore Darrell as part of the Ruby on Rails Documentation Project and is provided freely under a Creative Commons licence


  1. kinoue saidThu, 24 Nov 2011 17:25:32 -0000 ( Link )

    I just want to point out that I think the following line is a bit misleading/tricky:
    skip_before_filter :require_login, :only => [:new, :create]
    because in the default configuration, it will end up running the filter after the create method, but before the show method that the create method is re-directing to.
    Of course, if you have modified create method that wouldn’t happen, and it might be trivial.. but I had a similar code didn’t realize what was happening and wasted a good amount of time, so just in case… Thanks,

    Actions
    Vote
    Current Rating
    1
    Rate Up
    Rate Down
    1 Total Vote

    Post Comments

  2. kinoue saidThu, 24 Nov 2011 17:26:07 -0000 ( Link )

    I just want to point out that I think the following line is a bit misleading/tricky:
    skip_before_filter :require_login, :only => [:new, :create]
    because in the default configuration, it will end up running the filter after the create method, but before the show method that the create method is re-directing to.
    Of course, if you have modified create method that wouldn’t happen, and it might be trivial.. but I had a similar code didn’t realize what was happening and wasted a good amount of time, so just in case… Thanks,

    Actions
    Vote
    Current Rating
    1
    Rate Up
    Rate Down
    1 Total Vote

    Post Comments

Your Comment
Textile is Enabled (View Reference)