Per the Agile Development book, I have an Admin MVC that controls how users log in. In ApplicationController, I have a before_filter that checks for authorization. So, this will check that the user has logged in for every page.
The problem is that I want everyone to be able to access the new method, for example, in Users (that is, anyone should be able to create a new user -- naturally! Only admin users should have access to the other methods in UsersController such as edit, etc.). What's the best way to do that?
You can either of this
before_filter :except=>[:method_name] #methods you want to skip filter
OR
before_filter :only=>[:method_name] #methods you want to be filtered before called.
EDITED
before_filter :filter_method, :except=>[:method_name] #methods you want to skip filter
OR
before_filter :filter_method, :only=>[:method_name] #methods you want to be filtered before called.
You can use the skip_before_filter method in child controller classes to skip the default filter processing. For example:
class UsersController < ApplicationController
skip_before_filter :authorize, :only => [:new, :create]
end
—Will skip the before filter named :authorize only for the new and create actions within the users controller i.e. the filter will still get applied for all other actions.
I would also suggest using CanCan gem for authorization as it has a really simple and clean way to define authorization rules.
http://github.com/ryanb/cancan
Related
I'm using Devise for authentication in a Rails 6 app. Once a user logs in, I'd like to conditionally check that they have completed onboarding before allowing them to visit any and all authenticated routes. If they haven't, then they should be redirected back through the onboarding flow. Something like this:
unless current_user.has_completed_onboarding
redirect_to '/onboarding'
end
I have about a dozen routes where I want to implement this logic. What's the best way to add this check before each request to an authenticated route without duplicating it within each controller? Thanks!
what you can do in this type of case is write a method in the ApplicationController. Suppose check_user_onboarding
def check_user_onboarding
return redirect_to '/onboarding' unless current_user.has_completed_onboarding
end
Then in the controllers you can check by adding a before_action callback. The below one will check all the methods of that controller.
before_action :check_user_onboarding
You can also specify the methods that needs to be checked like -
before_action :check_user_onboarding, only: [:method1, :method2]
or there is also except
before_action :check_user_onboarding, except: [:method1, :method2]
I'm using devise for Authentication in a Rails 4 app. Almost all of the app requires a user to be authenticated, however, there are a few 'public' pages (Terms and conditions - that kind of stuff).
Devise itself makes the sign up and sign in pages public, using prepend_before_filter :require_no_authentication. However, that method is intended only for devise controllers. And devise doesn't seem to provide a 'proper' way to make single actions public.
So, what's the best way to make just a couple of actions public?
The only ways I can think of so far is:
To make a new public namespace, and have separate controllers for public actions, which inherit from a PublicController that does not execute before_filter :authenticate_user!
Same as above, but ditch the inheritance and the namespace. So the PublicController could act as a bucket for anything that needs to be public - which at this stage isn't much.
Is there a better way to make individual actions public with devise?
You can optionally use skip_before_action for the public controllers. Example from guides:
class LoginsController < ApplicationController
skip_before_action :require_login, only: [:new, :create]
end
In your controller, you want to have:
before_action :authenticate_user!, :except => [:index]
This will perform the :authenticate_user! method on all actions except index action.
You can find more explanation in this answer.
I've been looking for a way to redirect all requests of my app to the sign_in page if the user is not signed in, but I haven't found a way to do it (I could do it verifying a system variable and then redirect_to, but it does sound like the bad way)
I'm using ldap_authenticatable (devise) to authenticate, and then use Cancancan (for Access Control List), is there a way to use those tools (Cancancan) to do this ? , or how should I do it?
Thanks for your time
You can just add before_filter :authenticate_user! to your base ApplicationController. Devise Docs
Devise uses "authenticate_user!" filter to authenticate users. For authenticating users you can do something like this:
before_action :authenticate_user!
It will trigger authentication for all methods and if you want authentication only for some specific actions then you can use only or except options like:
before_action :authenticate_user!, :only => [your actions].
For more detail click here
add
class ApplicationController < ActionController::Base
before_action :authenticate_user!
end
in the application controller, this will automatically authenticate the user, if he is not logged in then he will be redirected to the sign_in page automatically
I'd like /something to only be accessible for logged in users, I have a current_user helper which returns a user id or nil if the current visitor is not logged in.
Where would be the best place to limit access to /something in the controller or can it be added as part of the routes?
You must add in controller :before_filter and create action for that.
:before_filter :authenticate
def authenticate
redirect_to(registration_path) unless current_user.nil?
end
Also you can use :only or :except filter options.
Or i did not understant question?
You should handle that in your controller. Routes decide where things go and then it is up to the controller to decide if you're allowed to go there.
You should have a general purpose authenticate method in your ApplicationController that checks if someone is logged in and redirects them to a login page if they're not. Then in your specific controller:
class SomethingController < ApplicationController
before_filter :authenticate
def handler
#...
end
end
You can skip authentication for a specific handling with the :except option:
before_filter :authenticate, :except => [ :this_one, :and_this_one ]
There are other options as well, see the filters section of the Action Controller Overview for details.
I have my regular ApplicationController class & I have a Admin::ApplicationController class. The problem is that Admin::ApplicationController doesn't seem to be getting loaded or executed or anything. Am I not allowed to have a namespaced application controller? The reasoning for wanting to have it is so that I can check if a user is an admin w/ CanCan & redirect them out if they're not.
Call this controller Admin::BaseController, as it is more to act as the base of the namespace than to do anything for the appilcation. For it to do what you want to do, you will need to make all admin namespaced controllers inherit from this controller.
The only times I've seen namespacing like that is when the controller is nested in a subfolder. So Admin::ApplicationController would expect to be in controllers/admin/application_controller.rb
One possible solution:
If you want everything except your home page to kick them out, simply set a before_filter on your application controller with an exception for home/index like this:
ApplicationController.rb
before_filter :authorize_admin
def authorize_admin
//dostuff
end
HomeController.rb
skip_before_filter :authorize_admin, :only => ['index']
Where index is your action that you want to skip. Leave off the only to skip the filter for the whole controller.