basically i have Admin and User in my app. Here after signing by user it is also routing user_dashboard but if i make change in url as admin_dashboard it is getting routed for that also. How can i stop that
similarly if Admin get sign in it is also routing to Admin_dashboard but if i make change in url as user_dashboard it get routed. How can i restrict that
class ApplicationController < ActionController::Base
protect_from_forgery
skip_before_filter :authenticate_user! , :only => ["welcome#index"]
def after_sign_in_path_for(user)
user_dashboard_index_path
end
def after_sign_out_path_for(user)
welcome_index_path
end
end
I believe the way to do this is to override the devise before and after_sign_in_path_for helpers
I think (from what I've read), you can use logic to determine the best way to handle this:
def after_sign_in_path_for(resource)
stored_location_for(resource) ||
if resource.is_a?(Admin)
admin_dashboard_path
else
user_path(resource)
end
end
If you have any field like "is_admin" in user model then you need to just check whether logged in user is admin or not.
like
def after_sign_in_path_for(user)
if user.is_admin?
admin_dashboard_index_path
else
user_dashboard_index_path
end
end
Related
I have a rails app where I have added a boolean field named 'authorized' to the user model. Basically, I want to lock the app down such that only authorized users can access the app. I am trying to do this in my application controller:
class ApplicationController < ActionController::Base
protect_from_forgery with: :exception
def authorized
redirect_to root_path, alert: "Not Authorized" if !current_user.authorized?
end
end
However, I am getting a redirect error when I do this as I have the root route set to a path where authentication is required.
I now I can do this check in the view or another controller, but I'd like to do it in the app controller as I want the entire app locked down.
You can override these methods in your user model.
def active_for_authentication?
super && approved?
end
def inactive_message
'my custom inactive message' unless approved?
super
end
I recommend you to change the authorized name by approved, I'm not sure but authorized sounds like an internal Devise method name.
Here was my solution...
In the controller where I wanted the 'authorized' authentication I added...
before_filter :authorized, :except => :not_authorized
...
def authorized
if !current_user.authorized?
redirect_to not_authorized_path
end
end
In my routes, I added..
get 'not_authorized' => 'my_controller#not_authorized'
...and added a simple app/views/my_controller/not_authorized.html.erb
In ApplicationController, according to devise docs, How To: Redirect to a specific page on successful sign in and sign out, the case switch when can not be reached, even in pry debugging console, it shows 'resource.class == User is true'. I don't know what part of Rails processing I missed, any hint will be appreciated!
# ApplicationController.rb
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
protected
def after_sign_in_path_for(resource)
# check for the class of the object to determine what type it is
binding.pry
case resource.class
when User
puts "user redirect ==== "
return session.delete(:return_to) || current_user_path
else
puts "super call ....."
super
end
end
end
You are pretty close. Just need to get the resource class name using resource.class.name , so that you can compare it with a string such as 'User' which is nothing but your class name.
def after_sign_in_path_for(resource)
# check for the class of the object to determine what type it is
binding.pry
case resource.class.name #=>this would return the class name i.e 'User'
when 'User'
puts "user redirect ==== "
return session.delete(:return_to) || current_user_path
else
puts "super call ....."
super
end
end
You can make workaround by creating SessionsController that inherits from Devise::SessionsController.
class SessionsController < Devise::SessionsController
skip_before_filter :authenticate_user!
def create
user = User.find_for_database_authentication(email: params[:session][:email])
if user && user.valid_password?(params[:session][:password])
sign_in user
redirect_to session.delete(:return_to) || '/authorized'
else
redirect_to '/sign_in'
end
end
def destroy
sign_out :user
redirect_to '/signed_out'
end
end
Point to it inside your routes.rb like this:
devise_for :users, controllers: {sessions: 'sessions'}
There is authenticate_user! in a comments_controller.
before_action :authenticate_user!
When a user clicks to create a comment, they are now redirected to users/sign_in page.
But, I want to redirect them to root_url and put a notice to log in. There are login buttons(FB and G+) on home page.
I've looked at this, but when I implement it, I just get a black page with the same URL and Completed 401 Unauthorized.
You can add authenticate_user! method to the application_controller.rb
class ApplicationController < ActionController::Base
protected
def authenticate_user!
redirect_to root_path, notice: "You must login" unless user_signed_in?
end
end
I added a page to the Devise wiki showing the correct way to do this with a failure app: Redirect to new registration (sign up) path if unauthenticated
The key is to override the route method, like so:
# app/lib/my_failure_app.rb
class MyFailureApp < Devise::FailureApp
def route(scope)
:new_user_registration_url
end
end
and then have Devise use your failure app:
# config/initializers/devise.rb
config.warden do |manager|
manager.failure_app = MyFailureApp
end
This approach is preferable to overriding authenticate_user! in your controller because it won't clobber a lot of "behind the scenes" stuff Devise does, such as storing the attempted URL so the user can be redirected after successful sign in.
With multiple user types
If you have Admin and User Devise resources, you'll probably want to keep the default "new session" functionality for admins. You can do so quite easily by checking what type of scope is being processed:
# app/lib/my_failure_app.rb
class MyFailureApp < Devise::FailureApp
def route(scope)
scope.to_sym == :user ? :new_user_registration_url : super
end
end
comments_controller.rb
before_filter :loged_in?, :only => [:create, :edit, :destroy] #customize to fit your needs
private
def loged_in?
redirect_to root_path, notice: 'Your have to log in' unless current_user
end
it will check if current_user exists, which it will if a user is signed in, otherwise redirects to root path with given notice.
Is it possible to redirect users to different pages (based on role) after signing in with Devise? It only seems to redirect to the root :to => ... page defined in routes.rb
By default Devise does route to root after it's actions. There is a nice article about overriding these actions on the Devise Wiki, https://github.com/plataformatec/devise/wiki/How-To:-Redirect-to-a-specific-page-on-successful-sign-in
Or you can go even farther by setting stored_locations_for(resource) to nil, and then have different redirects for each action, ie: after_sign_up_path(resource), after_sign_in_path(resource) and so on.
You can simply add this method to your application controller:
def after_sign_in_path_for(resource)
user_path(current_user) # your path
end
Devise has a helper method after_sign_in_path_for which can be used to override the default Devise route to root after login/sign-in.
To implement a redirect to another path after login, simply add this method to your application controller.
#class ApplicationController < ActionController::Base
def after_sign_in_path_for(resource)
users_path
end
Where users_path is the path that you want it to redirect to, User is the model name that corresponds to the model for Devise.
Note: If you used Admin as your model name for Devise, then it will be
#class ApplicationController < ActionController::Base
def after_sign_in_path_for(resource)
admins_path
end
Also, if you generated controllers for Devise, then you can define this in the sessions controller, say, your Devise model is Admin, you can define this in the app/controllers/admins/sessions_controller.rb file to route to the dashboard_index_path:
# app/controllers/admins/sessions_controller.rb'
def after_sign_in_path_for(resource)
dashboard_index_path
end
And in the registrations controller - app/controllers/admins/registrations_controller.rb file:
# app/controllers/admins/registrations_controller.rb
def after_sign_up_path_for(resource)
dashboard_index_path
end
That's all.
I hope this helps
You can use the below code in the application controller or any controller where you need to do the operation:
def after_sign_in_path_for(resource)
users_path
end
https://github.com/heartcombo/devise/wiki/How-To:-Redirect-to-a-specific-page-on-successful-sign-in,-sign-up,-or-sign-out
I used example 1:
class ApplicationController < ActionController::Base
protect_from_forgery with: :exception
before_action :authenticate_user!
protected
def after_sign_in_path_for(resource)
current_user.is_a?(Admin) ? admin_tests_path : (stored_location_for(resource) || root_path)
end
end
To expand on the answer provided by #Asnad Atta
Here is what I ended up using.
def after_sign_in_path_for(resource)
if current_user.role == 'admin'
start_path
else
news_path
end
end
I wanted everyone who logs in to first be pushed to a News page.
After the initial login the Home on the Navbar goes to the start_path (just what I call it in my app). The start_path is also in my root to:
This wonderful after_sign_in_path_for(resource) over rides the root to: path ONLY on the initial Login.
This is exactly what I wanted.
I hope this can help save someone some time.
Scott
Here's what I believe is the answer you are looking for from the devise wiki:
How To: Change the default sign_in and sign_out routes
I need to make sure a user has the correct permissions before allowing them to edit an employee's information. Specifically the user has to be an admin and the user must belong to the same company as the employee. What's the best way to do something like this?
def EmployeesController < ApplicationController
before_filter :requires_admin_from_company(cid)
# Only allow access to this if user.admin is true and user.company_id is equal to employee.company_id
def update
# Somehow pass #employee.company_id into admin
#employee = Employee.find(params[:id])
#employee.update_attributes(params[:employee])
end
def requires_admin_from_company(cid)
if !#current_user.admin? || #current_user.company_id != cid
redirect_to login_url
end
end
end
How about
before_filter lambda{ requires_admin_from_company(params[:cid]) }, :only => :create
I've found Authorization with CanCan to be very helpful in these situations