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.
Related
I want one pages of my ruby on rails web application inaccessible to one of my STI model types. I have two models typeA and typeB inheriting from User. I have used the column type in the User table to implement STI. I am using Devise gem for User sessions. I want one webpage 'http://localhost:3000/rate' inaccessible to my typeA User. Whenever an User logs in who is of the type 'typeA', he does not have the option of seeing the link 'Rate'. But I also do not want him to be able to access that page by the link 'http://localhost:3000/rate'. If he tries to access it through that link, I want to sign him out and make him log in again.
I managed this by using a piece of code in my Controller with the specific method for 'rate'.
def rate
if current_user.type == "typeA"
sign_out(current_user)
redirect_to new_user_session_path
else
#Code for User of typeB
end
end
This is working but I wanted to know if this can be done in a better way using before_filter :authenticate_user! or something else
Right now my before_filter part looks like this
before_filter :authenticate_user!, except: [:index, :show]
Is there any way I can make a change to the upper code to achieve that functionality.
P.S: Maybe this can be done better if I had used roles or other gems like CanCan/Pundit but I do not have much time left to submit my project, so I do not want to get into all that right now.
you can add another before_filter on the controller you want to restrict the access just to confirm your STI user type without overiding devise's authenticate_user! filter.
application_controller.rb
class ApplicationController < ActionController::Base
def confirm_user_type(user_type)
redirect_to new_user_session_path unless current_user.is_a?(user_type)
end
end
pages_controller.rb
class PagesController < ApplicationController
# must be authenticated to access
before_filter :authenticate_user!
# must be user of TypeA to access
before_filter { |c| c.confirm_user_type(TypeA) }
def rate
...
end
end
Then, you can use the same filter before_filter { |c| c.confirm_user_type(TypeB) } for STI user type: 'TypeB'
Try this:
class ApplicationController
before_action :authenticate_user!
def authorize_user!
if current_user.type == "typeA"
sign_out(current_user)
redirect_to new_user_session_path
end
end
end
with your controller:
class SomeController < ApplicationController
before_action :authorize_user!, except: [:index, :show]
def top_secret
...
end
end
I believe if a before_action (the new name for before_filter) renders or redirects, the action won't be processed.
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]
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.
Using Ruby on Rails, I want to before filter an action but only when users are logged in.
How is this possible?
before_filter :only_when_user_is_logged_in, :only => :the_action
Or for multiple
before_filter :only_when_user_is_logged_in, :only => [:the_action, :another_action]
On the flip side, you can also provide an :except => :this_action option
I think you're asking how to run a before filter only if a user is logged in. There is no built-in semantic for this, but it's easy enough to inline:
class SomeController < ApplicationController
before_filter :do_something
def do_something
if logged_in?
# the stuff you want to do
end
end
end
Before filters take an optional block which is passed the current controller instance
so you could do something like this:
before_filter :do_stuff, lambda { |controller| controller.logged_in? }
If you really don't want the before_filter executing for anyone other than logged in users consider using #skip_before_filter in your authentication filter. For instance if when you're checking if users are logged in in your authentication filter, if authentication fails, merely call skip_before_filter :filter_for_logged_in_users_only.
Other than that you can simply test if the user is logged in before executing the member only filter. For example:
def filter_for_logged_in_users_only
return true unless current_user && logged_in?
#rest of the logic
end
If you're using restful authentication, it's just before_filter :login_required. If you are using your own authentication framework, you can create a method in application.rb that returns true if the user is logged in or redirects to the login page otherwise.
class LoginsController < ApplicationController
skip_before_filter :require_login, :only => [:new, :create]
end