is it possible to have:
before_filter :authenticate_user! || :authenticate_admin!
before_filter :do_authentication
def do_authentication
authenticate_user! || authenticate_admin!
end
before_filter {authenticate_user! || authenticate_admin!}
Passing in a proc to the before_filter method, would be the closest to what you have provided in you question.
Since :authenticate_user! is a symbol, :foo == true is valid. Therefore, your example will always just equate to before_filter :authenticate_user!
Try something like (not sure of your setup here..):
if method_defined?(:authenticate_user!)
before_filter :authenticate_user!
else
before_filter :authenticate_admin!
end
If you have both methods defined and want to run authenticate_user! then if that returns false, run authenticate_admin!, just make one authenticate! method that checks for uses/admin and run that before_filter.
Related
I have an authorization module that I built to authorize user actions. Everything is working great, except now I want to skip the action if the user requesting the page is the current user. The resource is nested below user so passes a :user_id as part of the params.
From what I've been able to find out, the simplest way to do this is to use a lambda, but it doesn't appear that I have access to the passed params from the before filter.
This is my controller
class Certifications::FitnessController < ApplicationController
prepend_before_action :authenticate_user!
before_action :authorize, unless: -> { params[:user_id] == current_user.id }
end
The problem is that the :authorize before_action is never called so all actions are allowed (I assume because the unless statement is always evaluating to true), but I can't examine what is going on because if I stop execution there, no params seem to be there (which I would think should make it always evaluate to false, not true).
If anyone can tell me either what I'm doing wrong or a better way to implement, I would really appreciate it.
EDIT: The code above actually works if you convert the params to an integer to match the current_user.id
before_action :authorize, unless: -> { params[:user_id].to_i == current_user.id }
before_action do |controller|
unless params[:user_id].to_i == current_user.id
controller.authorize
end
end
Alternatively you can do so like:-
before_action :authorize
def authorize
unless params[:user_id].to_i == current_user.id
#do your stuff..
end
end
2nd Alternative
before_action :authorize, unless: -> { params[:user_id].to_i == current_user.id }
I'm getting a redirect loop. I have a clear idea why, user is logged out, redirected to login page (welcome#index) and user is still logged out and we have an endless loop.
How do I get out of loop?
I read about several options.
before_action :require_login placing it inside controllers where login is required. EASY, but a lot of copy paste, we love dry don't' we?
except, before_action :require_login, :except => root? I couldn't find details about except. I'm getting a lot of hits on before_filter which seems to be deprecated.
skip_before_action same here, I can only find bits and pieces :(
There should be a better way to handle these, is it rails way to do check routes level in config/routes.rb?
Application controller:
class ApplicationController < ActionController::Base
# Prevent CSRF attacks by raising an exception.
# For APIs, you may want to use :null_session instead.
protect_from_forgery with: :exception
helper_method :current_user
before_action :require_login
private
def current_user
#current_user ||= Dedit::User.find(session[:user_id]) if session[:user_id]
end
private
def require_login
redirect_to root_path unless current_user.present?
end
end
login page controller:
class WelcomeController < ApplicationController
layout 'basic'
def index
if current_user.present? then redirect_to dedit_path end
end
end
before_action :require_login, except: [:index]
I am setting up a very simple rails app that involves a simple authentication check before you can enter the site. But, when the before_filter runs, and the user is redirected to the login path, a redirect loop occurs.
ApplicationController:
class ApplicationController < ActionController::Base
# Prevent CSRF attacks by raising an exception.
# For APIs, you may want to use :null_session instead.
protect_from_forgery with: :exception
before_filter :check_session
private
def check_session
redirect_to login_path and return unless current_user?
end
def current_user?
!session[:username].blank?
end
end
SessionsController
class SessionsController < ApplicationController
def new
end
end
The issue is that, since your SessionsController inherits from ApplicationController, it actually inherits the before_filter as well. This means you are not allowing someone to see the login page unless they are logged in, which is usually undesirable behavior. You want to skip this before_filter on the login page:
class SessionsController < ApplicationController
skip_before_filter :check_session, only: :new
def new
end
end
I think you have problem in your routes. One way of solution is defining a root path for your app as:
root 'app_entry#index'
Then create a controller for it as given below:
class AppEntryController < ApplicationController
def index
if current_user
redirect_to 'controller_name/action_name'
else
redirect_to '/users/sign_in'
end
end
Hope this helps you.
You should use the before filter like this
before_filter :check_session, :except => [:new]
I am trying to access one variable set in a method from another method. This is in Rails 1.9 code below.
class ApplicationController < ActionController::Base
protect_from_forgery
before_filter :method1
before_filter :method2
def method1
#remote_user = 'dev_user'
end
def method2
unless #remote_user.present?
render :status => 401, :text => "Authentication failed"
false
end
end
When attempting to access it in the second method, it is always returning blank. The 401 is always returning with the text "Authentication failed". Could someone advise on to what I am doing wrong?
if you need to guarantee that a method is called before another on before_filter, do something like this:
before_filter :fn3
def fn3
fn1
fn2
end
from -> How can I specify the order that before_filters are executed?
Hope it helps
EDITED
Better yet, use prepend_before_filter for anything you needs to be resolved before the before_filter method.
in your case:
class ApplicationController < ActionController::Base
protect_from_forgery
prepend_before_filter :method1
before_filter :method2
def method1
#remote_user = 'dev_user'
end
def method2
unless #remote_user.present?
render :status => 401, :text => "Authentication failed"
false
end
end
To ensure correct order of before_filter you can use prepend_before_filter or append_before_filter. Imho prepend is the default behaviour, so your filters are executed in reverse order.
So to fix this you will have to write:
class ApplicationController < ActionController::Base
before_filter :method2
prepend_before_filter :method1
You could just write before_filter twice (in this order) and it would be fine, but this is imho more expresssive. First write all the before_filters for which the order does not matter, and then prepend the one that needs to be first.
Alternatively you could write
class ApplicationController < ActionController::Base
before_filter :method1
append_before_filter :method2
which does exactly the same, but makes sure method2 is executed last. Whichever you prefer :)
Also note that filters defined in other controllers (deriving from ApplicationController) will normally be executed first!
I am using devise and in my profile_controller.rb I have the usual 7 methods and an additional methods, now I am using before_filter as only authenticated user can access those methods but for just 1 method, I need it to bypass it. How to do it ?
before_filter :authenticate_user!
def index
...
end
...
def destroy
...
end
def edit_name
...
end
before_filter :authenticate_user!, except: :method_you_want_to_bypass
In this way you skip the call to authenticate_user! method when the current action is :method_you_want_to_bypass. This solution works in general, not only with Devise.