21
Jun

Rails: Power to the filters

posted by gchatz 1 comment rails

Rails before_filters in controllers can help you keep your code DRY.
I have coded cases where all action functionality was included in 2-3 before_filters.

I’ll try to showcase some of the methods that work for me.

Authentication

The most commonly used before_filter should be that of authentication, and since this is global you can place it in you ApplicationController.

class ApplicationController < ActionController::Base
  session :session_key => '_fortytwo_session_id'

  before_filter :fetch_logged_user

  def authenticate
    unless @logged_user
      #unauthorized access
      redirect_to login_url, :status => 401
      return false
    end
  end

  def fetch_logged_user

    unless session[:user_id].blank?
      @logged_user = User.find(session[:user_id])
    end

  rescue ActiveRecord::RecordNotFound
  end

end

Now, in every action, in every controller we have a @logged_user object. If it’s not nil , then we have an authenticated user.
So if we want to restrict access to authenticated users in a certain controller for some actions, we just need a before_filter for the authenticate function.

class UsersController < ApplicationController
  before_filter :authenticate, :except => :login
endre

CRUD Operations

Models usually have the common CRUD actions (new, edit, update, delete, create), and some other actions that operate on a specific model record. If you add authentication and probably authorization (only the owner of a blog post can change his content for example), things can get complicated. Unless…

 
class BlogController < ApplicationController
  #authenticate is in our ApplicationController
  before_filter :authenticate, :except => :show
  before_filter :fetch_post, :only => [:show, :edit, :update, :delete]
  before_filter :authorise_as_owner, :only => [:edit, :update, :delete]

private
  
  def fetch_post
    @post = Post.find(params[:id])
    rescue ActiveRecord::RecordNotFound
        #there is no such post
       flash[:alert] = "Got lost?"
       redirect_to error_url, :status => 404 
       return false
  end

  def authorise_as_owner
     unless @post.user_id == @logged_user.id
        #You don't belong here. Go away.
        flash[:alert]  = "Mind your own business"
        redirect_to error_url, :status => 401
     end
  end

end

If you are using roles, you can extend the authorisation behaviour (so that admins can edit any post) like this:

  def authorise
     unless @post.user_id == @logged_user.id || @logged_user.is_admin?
        #You don't belong here. Go away.
        flash[:alert]  = "Mind your own business"
        redirect_to error_url, :status => 401
     end
  end
Comments (1)

Pin dotemacs said on Sep 27, 10:38 PM:

Hi, the code above is not coming up as syntax highlighted.