Stop returning false from your before filters 3

Posted by pratik
on Friday, July 31

In the past version of Rails you had to explicitly return false from before filters to halt the filter chain and make sure the action doesn’t get run. The code looked somewhat like :

1
2
3
4
5
6
7
8
9
10
11
12
class AdminController < ApplicationController
  before_filter :check_admin

  private

  def check_admin
    unless current_user.admin?
      redirect_to home_path
      return false
    end
  end
end

But since Rails 2.0, If you call render, head or redirect_to from a before_filter, the filter chain will be halted. So the above controller will now look like :

1
2
3
4
5
6
7
8
9
class AdminController < ApplicationController
  before_filter :check_admin

  private

  def check_admin
    redirect_to home_path unless current_user.admin?
  end
end

You should go ahead and update all your before filters to reflect this change. return false is nothing but code smell.

Rescue from dispatching 13

Posted by pratik
on Sunday, July 20

This question gets asked quite a few times, if there’s an easy way to handle exceptions raised while dispatching a request (routing exceptions, invalid method etc.) gracefully and show a customized error page. After this commit, there is.

rescue_from to the rescue

Now you can handle those exceptions inside your application.rb like :

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class ApplicationController < ActionController::Base
  rescue_from ActionController::RoutingError, :with => :route_not_found
  rescue_from ActionController::MethodNotAllowed, :with => :invalid_method
  
  private
  
  def route_not_found
    render :text => 'What the fuck are you looking for ?', :status => :not_found
  end
  
  def invalid_method
    message = "Now, did your mom tell you to #{request.request_method.to_s.upcase} that ?"
    render :text => message, :status => :method_not_allowed
  end
end

Just make sure you don’t raise another exception from your rescue_from action!

Dispatcher callbacks 2

Posted by pratik
on Tuesday, October 16

Changeset 7640 introduced 2 new members to rails family of callbacks : before_dispatch and after_dispatch. These callbacks are executed before/after every request, and provides you with hooks at much higher level than normal before_filter and after_filter of ActionController::Base.

Also, note that after_filter are not executed if your action raises an exception. So dispatcher callbacks might be a better fit for performance related logging, etc. where the final outcome of your controller doesn’t really matter, and you want your callbacks to be executed for each and every request.

For example, try the following in your environment.rb :

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
require 'dispatcher'
module ActionController
  class Dispatcher
    def start_timer
      @start_time = Time.now
    end
    
    def end_timer
      RAILS_DEFAULT_LOGGER.info "="*100
      RAILS_DEFAULT_LOGGER.info "      URL : #{@request.url}"
      RAILS_DEFAULT_LOGGER.info "     Real : #{Time.now-@start_time} seconds"
      RAILS_DEFAULT_LOGGER.info "Less Real : #{@response.headers["X-Runtime"]} seconds"
      RAILS_DEFAULT_LOGGER.info "="*100
    end
    
    before_dispatch :start_timer
    after_dispatch :end_timer
  end
end