Default Route for an admin User (Devise) - ruby-on-rails-3

Little issue here, I cant seem to route an admin user to the appropriate place. I have setup devise and added the column admin and set it as boolean. I have then updated my user to admin => true and verified this in the console.
When i log into my app a user is routed to one page and the admin user should be routed to another, here is what i have so far
authenticated :current_admin_user do
root :to => 'book#searchbook'
end
authenticated :user do
root :to => 'search#index'
end
root :to => 'main#index'
However when i log in as thew admin user I get routed to 'search#index' as if i was a regular user.. What do i need to do to get the admin user routed to 'book#searchbook'. Ive never had a problem with this before
Any help appreciated
EDIT
ok so after some more research i need to specify the after_sign_in_path for an admin user, so far i have this
def after_sign_in_path_for(resource)
if current_admin_user
searchbook_path
else
root_path
end
end
but still it directs me to the user login page
Thanks

Ok so it seems as if I had quite a bit missing, so if anyone else has had problems like this before here's what i done
In the User model i added
def is_admin?
self.admin == 1
end
and then in my application controller i added these methods
def authenticate_admin_user!
authenticate_user!
unless current_user.admin?
flash[:alert] = "This area is restricted to administrators only."
redirect_to root_path
end
end
def current_admin_user
return nil if user_signed_in? && !current_user.admin?
current_user
end
def after_sign_in_path_for(resource)
if current_user.admin?
searchbook_path
else
root_path
end
end
and then in the controller that was only accessible by the admin user I added before_filter
before_filter :authenticate_admin_user!
Hope this helps anyone else in same situation (and thanks to Jayson Lane)
Turns out he helped me 9 months ago with the same issue...

Just try to implement the below code .. As I used this code in my controller..
def after_sign_in_path_for(resource_or_scope)
if resource_or_scope.is_a?(User)
return root_path
else
return search_path
end
end

Related

Bcrypt with two different user models on rails 5.2

I have two migration tables: parents and teachers. And I use Bcrypt for registration. I can't figure out what I should do with log in and sessions_controller (sessions helper). I can register new user and when user registers he can only see Sign Out link in navbar. However, I can not sign out user, I am not sure how I define the methods in sessions controller and session helper. Maybe somebody can help me with this?
I can not find information about bcrypt with different user models - is this thing not popular or is this so easy and I am just stupid and do not understand a thing??
class SessionsController < ApplicationController
include SessionsHelper
def new
end
def create
teacher = Teacher.find_by(email: params[:session][:email])
parent = Parent.find_by(email: params[:session][:email])
if teacher && teacher.authenticate(params[:session][:password])
log_in teacher
redirect_to documents_path
flash[:notice] = "Welcome!"
elsif parent && parent.authenticate(params[:session][:password])
log_in parent
redirect_to root_path
flash[:notice] = "Welcome!"
else
flash[:alert] = "Please log in again!"
render 'new'
end
end
def destroy
if log_out parent
redirect_to root_path
elsif log_out teacher
redirect_to root_path
end
end
end
And here is my sessions helper:
module SessionsHelper
# Logs in the given user.
def log_in(parent)
session[:parent_id] = parent.id
end
def log_in(teacher)
session[:teacher_id] = teacher.id
end
# Returns the current logged-in user (if any).
def current_teacher
#current_teacher ||= Teacher.find_by(id: session[:teacher_id])
end
def current_parent
#current_parent ||= Parent.find_by(id: session[:parent_id])
end
# Returns true if the user is logged in, false otherwise.
def logged_in?(teacher)
!current_teacher.nil?
end
def logged_in?(parent)
!current_parent.nil?
end
def log_out(teacher)
session.delete(:teacher_id)
#current_teacher = nil
end
def log_out(parent)
session.delete(:parent_id)
#current_parent = nil
end
end
I don't know the details of the your application, but I can explain the general case.
First of all, controller which has log in function is not have to be named sessions_controller, name is anything OK.
And Bcrypt is basically only a library for encrypting passwords. Main process is checking the password entered by user is valid or not without decrypting. There is no clear answer how to implement controller logic.
Apparently, user is divided into two types, Teacher and Parent, and probably each has different functions. So essentially, I want to divide the two login processes into separate controllers or actions. Because each login process is not the same one.
But Teacher and Parent will log in with the same URL if user have to login from the same page due to the UI restriction. If you are in such circumstances, implementing in the same controller & action will be appropriate.
After all, it depends on how to design your application. So your code is not always wrong.
However, look at your code, Teacher or Parent is judged only by e-mail, it is doubtful whether this is a proper approach. I have not seen many websites where users with different privileges log in from the same page.
I think that it is basically divide the login page depending on Teacher or Parent. If you divide the login page, example is as follows.
class TeachersController < ApplicationController
include SessionsHelper
def login
end
def login_action
teacher = Teacher.find_by(email: params[:teacher][:email])
if teacher && teacher.authenticate(params[:teacher][:password])
log_in teacher
flash[:notice] = 'Welcome!'
redirect_to root_path
else
flash[:notice] = 'Invalid log in information!'
redirect_to action: :login
end
end
def logout
teacher = Teacher.find(session[:teacher_id])
log_out teacher
redirect_to root_path
end
end
class ParentsController < ApplicationController
include SessionsHelper
def login
end
def login_action
parent = Parent.find_by(email: params[:parent][:email])
if parent && parent.authenticate(params[:parent][:password])
log_in parent
flash[:notice] = 'Welcome!'
redirect_to root_path
else
flash[:notice] = 'Invalid log in information!'
redirect_to action: :login
end
end
def logout
parent = Parent.find(session[:parent_id])
log_out parent
redirect_to root_path
end
end
Although this is not the main issue, did you write sessions_helper in the helpers directory?
Usually, helper is used to implement for view logic, so if you want to share method in controller, use ActiveSupport::Concern in the concerns directory.

Devise invitable: invite existing user

I am using devise invitable in my application for inviting the users. If the user exists in the database I have to redirect him to signin screen otherwise to the signup screen if he is a new user. Even if I invite the user like:
User.invite!(:email => "jonny#email.com", :name => "Jonny"), the data is getting entered in the database, then the user is always getting redirected to sign in screen. I had written the following for checking the email in invitations controller:
def edit
if User.exists?(:email => params[:email])
redirect_to new_user_session_path
else
redirect_to new_user_registration_path
end
end
Can some help me how I can handle this situation.
For edit it should find a user by id rather than going on to the new_user_session_path. The edit method should contain the following piece of code.
def edit
if User.exists?
#user = User.find(params[:id])
else
redirect_to new_user_registration_path
end
end

How to allow a user to enter a password when deleting an authorization in devise/omniauth

I have a rais 3 app that uses devise and omniauth to allow users to register/login via their twitter account and/or with local login credentials. Everything works fine for registering and logging in. My problem occurs when a user chooses to destroy their twitter authorization without first establishing a local password. If a user destroys their authorizations, then I would like to route them to new_password_path so that they can choose a password for future log-ins.
Here is the controller code:
class AuthenticationsController < ApplicationController
before_filter :authenticate_user!, :except => [:create, :failure]
def create
omniauth = request.env["omniauth.auth"]
authentication = Authentication.find_by_provider_and_uid(omniauth['provider'], omniauth['uid'])
if authentication #existing user is logging-in with existing authentication service
flash[:notice] = "Signed in successfully."
set_home_location_cookies(authentication.user, authentication.user.home_lat, authentication.user.home_lng)
sign_in(:user, authentication.user)
redirect_to root_path
elsif current_user #existing user who is already logged-in is creating a new authentication service for future use
current_user.authentications.create!(:provider => omniauth['provider'], :uid => omniauth['uid'], :token => omniauth['credentials']['token'])
current_user.update_posting_preferences(omniauth['provider'])
flash[:notice] = "Successfully linked to your #{omniauth['provider'].titleize} account."
redirect_to root_path
else #new user is creating a new authentication service and logging in
user = User.new
user.apply_omniauth(omniauth)
if user.save
flash[:notice] = "Signed in successfully."
sign_in(:user, user)
redirect_to root_path
else
session[:omniauth] = omniauth.except('extra')
session[:user_message] = {:success => false, :message => "userSaveError"}
redirect_to new_user_registration_url
end
end
end
def failure
flash[:alert] = "Could not authorize you from your social service."
redirect_to root_path
end
def destroy
#authentication = current_user.authentications.find(params[:id])
current_user.update_posting_preferences(#authentication.provider)
#authentication.destroy
flash[:notice] = "You have successfully destroyed your link to your #{#authentication.provider.titleize} account."
if current_user.authentications.empty? && current_user.encrypted_password.empty?
sign_out
flash[:alert] = "Alert: Your account does not currently have a password for account authorization. You are in danger of losing your account unless you create a new password by using this form."
redirect_to new_password_path(current_user) and return
else
redirect_back_or(root_path)
end
end
The code results in a "could not find valid mapping for nil" error triggered by my redirect_to new_password_path(current_user) and return command
I would greatly appreciate some help figuring out this problem.
Thanks!
OK. I'll admit it. I implemented the authentications controller from a tutorial without studying devise routing to learn what was going on behind the scenes. Last night I reviewed the docs and figured out my problem. What is funny is that the above routine did work on an older version of devise but does not work on devise 1.5.3.
In the destroy action I sign-out the current_user then I try to route to the new_password_path sending in "current_user" as a parameter. Not surprisingly, at that point "current_user" has been nulled out. So, I get the, "could not find a valid mapping for nil" error. Here is my easy fix:
def destroy
#authentication = current_user.authentications.find(params[:id])
user = current_user
current_user.update_posting_preferences(#authentication.provider)
#authentication.destroy
flash[:notice] = "You have successfully destroyed your link to your #{#authentication.provider.titleize} account."
if current_user.authentications.empty? && current_user.encrypted_password.empty?
sign_out
flash[:alert] = "Alert: Your account does not currently have a password for account authorization. You are in danger of losing your account unless you create a new password by using this form."
redirect_to new_password_path(user) and return
else
redirect_back_or(root_path)
end
end

devise+omniauth devise helper like current_user,user_signed_in? not working

I am using devise and create login with Facebook using omniauth, but having problem of lost the devise helper methods access like current_user and user_signed_in? methods are not working.
EDIT
AuthenticationController
def create
omniauth = request.env["omniauth.auth"]
user = User.find_by_provider_and_uid(omniauth["provider"], omniauth["uid"]) || User.create_with_omniauth(omniauth)
session[:user_id] = user.id
redirect_to dashboard_path(user.id), :notice => "Signed in!"
end
redirect_to USercontroller dashboard method
UserController
before_filter :logged_in
def dashboard
#user = User.find(params[:id])
#comment = Comment.new
#comments = #user.comments.all.paginate(:page => params[:page], :per_page => 5)
end
so here control should go to dashboard method after checking logged_in method in ApplicationController
logged_in method in ApplicationController
Application Controller
def logged_in
if user_signed_in?
return true
else
redirect_to root_path
flash[:message] = "please login"
end
end
when I logged in using facebook following code generated at console
Started GET "/users/52/dashboard" for 127.0.0.1 at Thu Mar 29 12:51:55 +0530 2012
Processing by UsersController#dashboard as HTML
Parameters: {"id"=>"52"}
Redirected to http://localhost:3000/
Filter chain halted as :logged_in rendered or redirected
Completed 302 Found in 2ms (ActiveRecord: 0.0ms)
in the above code control is render from logged_in method to root_path but it shold render dashboard_path
So I am guessing User_signed_in? helper is not working I also use current_user in stead of that generate same error
As I see, user_signed_in? is working, but returns false, as for Devise user is not logged in. To fix this, just replace the session id storing with Devise sign_in method in your controller action:
def create
omniauth = request.env["omniauth.auth"]
user = User.find_by_provider_and_uid(omniauth["provider"], omniauth["uid"]) || User.create_with_omniauth(omniauth)
sign_in(:user, user)
# actually if you really really need that id in the session, you can leave this line too :)
session[:user_id] = user.id
redirect_to dashboard_path(user.id), :notice => "Signed in!"
end
After creating the user account via Facebook, how do you sign in the user?
You should still be using devise helpers like sign_in_and_redirect. Something like:
user = User.build_from_omniauth(omniauth)
if user.save
sign_in_and_redirect(:user, user)
end
Then you should be able to use helpers like current_user and user_signed_in? (which just check if current_user is not nil).
Taking a look at your edit, my answer is still valid. What you need to do is use sign_in_and_redirect(:user, user) instead of just setting the id in the session.
You can easily customize where the user is redirected after sign in with devise.
Another thing, remove this logged_in filter, Devise has a authenticate_user! method that you can use as a before_filter. It will redirect the user to the sign in page, and when they login, it will redirect them to the page they were trying to access.
You're using Devise, so try to take advantage of that, and go read the doc ;)

Rails redirect issue - Hartl's Rails Tutorial 10.2.3

I'm a complete noob working through Michael Hartl's (awesome) Rails tutorials, and have an issue with the friendly redirect in Ch.10.2.3. The purpose is to try to store the location, redirect to the sign in page, then redirect back to the original intended destination when sign-in is complete. My problem is that it simply renders the standard user profile page after signing in/creating a session, rather than redirecting.
I have this in the sessions_controller:
def create
user = User.authenticate(params[:session][:email],
params[:session][:password])
if user.nil?
flash.now[:error] = "Invalid email/password combination."
#title = "Sign in"
render 'new'
else
sign_in user
redirect_back_or user
end
end
And this in sessions_helper:
def authenticate
deny_access unless signed_in?
end
def deny_access
store_location
redirect_to signin_path, :notice => "Please sign in to access this page."
end
def redirect_back_or(default)
redirect_to(session[:return_to] || default)
clear_return_to
end
private
def store_location
session[:return_to] = request.fullpath
end
def clear_return_to
session[:return_to] = nil
end
I'm sure I've yet again made a stupid, simple mistake but I can't find it.. help?
The code is available here: https://github.com/railstutorial
Consider making a new git branch (or new project) for yourself that uses just this repository's code. Then you will have a working local version for comparison when things go wrong.