Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

skip_before_filter ignores conditionals

I'm trying to use skip_before_filter only if the app is in production mode. (I don't want my development instances public, and I want the app to automatically detect what type of instance it is on and display a log-in screen when it is not in production mode). So, my application controller has the following line:

before_filter :authenticate_user!, :except => "sign_in" #redirects to log-in

And the controller for displaying pages has this line:

skip_before_filter :authenticate_user!, :only => :show, :if => :in_production
#public pages are public, but only when in production.

And in_production is simply:

  def in_production
    ENV['RAILS_ENV']=='production'
  end

I realize that there may be other avenues here, but I'm curious as to why skip_before_filter seems to ignore the conditional and always just skip the before_filter. Is there something I'm missing?

like image 928
smudge Avatar asked Jan 09 '11 01:01

smudge


3 Answers

It is a Rails bug (or at least an undocumented strange behaviour). It is tracked here: https://github.com/rails/rails/issues/9703

In this thread, you can find a (twisted) solution.

Instead of

skip_before_filter :authenticate_user!, :only => :show, :if => :in_production

write

skip_before_filter :authenticate_user!, :only => :show
before_filter      :authenticate_user!, :only => :show, :unless => :in_production

It worked for me.

like image 194
Tony - Currentuser.io Avatar answered Oct 18 '22 23:10

Tony - Currentuser.io


I have found that the solution posted by SmartLove in the described scenario presents a kind of security hole or an unexpected behaviour. The line

before_filter :authenticate_user!, :only => :show, :unless => :in_production

because of the :only => :show, is overriding the existing before_filter defined in the ApplicationController. That means that all the actions of this controller (e.g :edit, :create, etc.), except the :show one, will be omitting the authenticate_user! filter.

A possible solution is removing the :only clause and checking the action called inside the conditional method. For example:

before_filter :authenticate_user!, :unless => :skip_filter?

def skip_filter?
  params[:action] == "show" && in_production
end
like image 24
Rafa Paez Avatar answered Oct 18 '22 23:10

Rafa Paez


I'm not sure skip_before_filter accepts an :if parameter, so I'd try this syntax

(skip_before_filter :authenticate_user!, :only => [:show]) if in_production

If it still doesn't work, try putting this in your application controller

if ENV['RAILS_ENV']=='production'
  skip_before_filter :authenticate_user!, :only => :show
end
like image 26
David Sulc Avatar answered Oct 19 '22 01:10

David Sulc