Active Admin authentication conflicting with User authentication - ruby-on-rails

Active Admin is a gem used for having an admin dashboard in your application. It uses Devise for logging in users and creates a separate admin_user model for the admins. My application already uses devise and has its users as the user model. Ever since I started using the active admin gem, in my routes file the following line keeps resolving to home#index and not users#dashboard even when my user is logged in. This used to work fine earlier where logged in users were taken to users#dashboard as the root url.
root :to => 'users#dashboard', :constraints => lambda {|r| r.env["warden"].authenticate? }
root :to => 'home#index'
What is happening is that the .authenticate? is checking for the admin_user (belonging to Active Admin) being logged in or not but not my user model which is what I need to check for, so when I am logged in to active admin interface, my site root becomes users#dashboard instead without checking if the user is logged in or not. How can I make .authenticate? check for the user being logged in and not admin_user ?
Any help or clues will be very much appreciated

I was able to solve this. The issue was related to Devise expecting a single user model in the application. Here is how to fix it.
In the config/initializers/devise.rb file, add:
config.scoped_views = true
and
config.default_scope = :user #or whichever is your regular default user model
thats it, warden checks the :user for being logged in and not :admin_user

Why are you using the get "/"? You should remove it. I'm using a definition pretty similar to yours and works fine with me. Use just:
root :to => 'users#dashboard', :constraints => lambda {|r| r.env["warden"].authenticate? }
root :to => 'home#index'

I am not sure, but you can try something like
root :to => proc { |env| [ 302, {'Location'=> env["warden"].authenticate? ? "users/dashboard" : "/home" }, [] ] }

What worked for me is:
constraint = lambda { |request| request.env["warden"].authenticate? and request.env['warden'].user.instance_of?(AdminUser) }

Related

Devise not redirecting where I would expect

Just migrated from Authlogic to Devise, and having a redirect issue.
I have the following:
root :to => "welcome#index"
authenticated :user do
root :to => "dashboard#show"
end
However, after loggin in, I end up on welcome#index, and not on dashboard#show as I would expect.
The devise documentation says:
After signing in a user, confirming the account or updating the
password, Devise will look for a scoped root path to redirect.
Example: For a :user resource, it will use user_root_path if it
exists, otherwise default root_path will be used.
Which only reinforces my expectation.
def after_sign_in_path_for(resource_or_scope)
new_order_path
end
Define this in your applications controller. This will route your user to a particular path after sign_in.
Additional tidbit:
If you want to route the user to a particular page after confirming through email use this in your applications controller.
def after_confirmation_path_for(resource_or_scope)
end
Try this:
resources :dashboard
authenticated :user do
root :to => "dashboard#show"
end
make sure the
root :to => "path"
after the above code and not below that.

Devise set different root path per user type

I've created a devise user model. There are 2 types of user:
customer
admin
I've accomplished bij creating two 'normal' models: customer and admin. These two models are inheriting from the user model, like so:
class Customer < User
Does anyone know how I can setup a root path per type of user. I want something like this:
authenticated :customer do
root :to => "customer/dashboard#index"
end
authenticated :admin do
root :to => "admin/dashboard#index"
end
UPDATE:
I've solved the problem:
root :to => "pages#home", :constraints => lambda { |request|!request.env['warden'].user}
root :to => 'customer/dashboard#index', :constraints => lambda { |request| request.env['warden'].user.type == 'customer' }
root :to => 'admin/dashboard#index', :constraints => lambda { |request| request.env['warden'].user.type == 'admin' }
although an old question, there is no answer and it could be useful for others.
In rails 3.2 (I have never tested it with anything lower) you can do this in your routes.rb file
authenticated :admin_user do
root :to => "admin_main#index"
end
then have your normal root route further down.
This however, doesn't seem to work in rails 4 as it gives Invalid route name, already in use: 'root' (ArgumentError)(as I have just found out and was searching for a solution when I came across this question), if I figure out a way of doing it in rails 4 I will update my answer
Edit:
Ok so for rails 4 the fix is pretty simple but not so apparent right off the bat. all you need to do is make the second root route a named route by adding an as: like this:
authenticated :admin_user do
root :to => "admin_main#index", as: :admin_root
end
this is documented here but note that it seems like only a temporary fix and so is subject to change again in the future
What you could do is have a single root path, say home#index and in the corresponding controller action perform a redirect depending on their user type.
For instance:
def index
if signed_in?
if current_user.is_a_customer?
#redirect to customer root
elsif current_user.is_a_admin?
#redirect to admin root
end
end
end
Using after_sign_in_path_for should be appropriate. So add this to your application_controller.rb:
def after_sign_in_path_for(resource)
if resource.type == 'customer'
your_desired_customer_path
else
your_desired_admin_path
end
end

Rails Devise roots, what's the difference between namespace and authenticated?

In a Rails 3.2 app I have two user models set up using Devise: Admin and User.
I have an Admin-specific root page defined in my routes file.
namespace :admin do
root :to => "pages#welcome"
end
I have also seen this written as
authenticated :user do
root :to => 'pages#welcome'
end
I have not been able to find a clear description of the difference between using namespace and authenticated, and what implications this may have for security.
I'd be very grateful if someone could enlighten me, or point me towards a clear description.
Thanks!
Namespace routes will always exist -- meaning you can always call
/admin and it will route to pages#welcome
Authenticated routes will only exist if the :user is logged in.
I use it to create a root_path that's a dashboard for a logged in user, but the marketing pages#welcome for non logged in:
authenticated :user do
root :to => 'profile#show'
end
root :to => 'pages#welcome'
Here is a link to devise doc for the method authenticated, which should answer your question : http://rdoc.info/github/plataformatec/devise/ActionDispatch/Routing/Mapper#authenticated-instance_method

Trying to set root to devise/sessions#new results in routes mapping error

Going demented with an issue here :-(
My requirement is as follows,
If a user visits myapp.com the root of my app is defaulted to promotional pages & sign-up form. This is achieved by checking for the presence of a subdomain.
If the user is not logged in and tries to visit their account at test.myapp.com they will be directed to test.myapp.com/users/sign_in -aka- devise/sessions#new
If the user is logged in (devise) and visits test.myapp.com the root of the application will be the application dashboard.
Here is what I am trying to use in my routes.rb
constraints(Subdomain) do
authenticated do
root :to => 'dashboard#index'
end
root :to => 'devise/sessions#new'
end
root :to => 'promo_pages#index'
Currently I have the following, you will note that the devise bit is not included.
constraints(Subdomain) do
authenticated do
root :to => 'dashboard#index'
end
end
root :to => 'promo_pages#index'
My problem with the latter is that when a user who is not logged in first visits test.myapp.com they are redirected to test.myapp.com/users/sign_in and an error message is displayed saying "You need to sign in or sign up before continuing." This is because I am enforcing a logon requirement for the dashboard pages.
However I don't want the user to get an error message the first time they visit the page, as it is ugly and makes it look like they have done something wrong when they have not.
My expectation is that if the user is not logged in then they will be directed straight to the logon page and not get an error notification. But when I use my amended version the following happens,
I can visit myapp.com just fine and it is routed to the promo pages
but if I try to visit test.myapp.com I get the following message in the browser
**Unknown action**
Could not find devise mapping for path "/". Maybe you forgot to wrap your route inside the scope block? For example: devise_scope :user do match "/some/route" => "some_devise_controller" end
Please advise what I am doing wrong (if anything) as I am going crackers trying to understand what to do.
Ps: I have found similar errors in stackoverflow and various googling but the solutions just don't seem to work for me. I expect that the solution to the problem lies in the error message that I have included above, but I can't figure out how to apply it.
Finally here is the log entry version of the error above, it is in an easier to read form.
Started GET "/" for 127.0.0.1 at 2012-01-15 21:44:42 +0000
Processing by Devise::SessionsController#new as HTML
[Devise] Could not find devise mapping for path "/".
Maybe you forgot to wrap your route inside the scope block? For example:
devise_scope :user do
match "/some/route" => "some_devise_controller"
end
Completed 404 Not Found in 1ms
AbstractController::ActionNotFound (Could not find devise mapping for path "/".
Maybe you forgot to wrap your route inside the scope block? For example:
devise_scope :user do
match "/some/route" => "some_devise_controller"
end
):
All help is appreciated, and additional details can be provided.
Thanks for reading
Update
I have just noticed that the 'authenticated' check does not appear to be working.
If it was working correctly then when using the second batch of working config, the logged in user visiting test.myapp.com would always be directed to the promo_pages, whereas at the moment he is able to access the dashboard..
I found the devise 'authenticated' method here
https://github.com/plataformatec/devise/pull/1147
Without the constraint, this will cause a Could not find devise mapping for path "/" error. This simple addition fixed it.
devise_scope :user do
authenticated :user do
root :to => 'dashboard#index'
end
unauthenticated :user do
root :to => 'devise/sessions#new'
end
root :to => 'dashboard#index'
end
I have got it sorted,
Ok, firstly the reason I was getting the devise error was that I needed to place the devise root statement inside the "devise_for :users" block
Secondly,
The authenticated check was not working because I failed to include a scope as I was under the mistaken impression it was not necessary.
Here is the finalised code, note that in rails routing the priority is based on order of creation, first created is highest priority. Thus in this case the promo_pages controller is only considered root if nothing else was previously specified.
constraints(Subdomain) do
authenticated :user do
root :to => 'dashboard#index'
end
unauthenticated :user do
root :to => 'devise/sessions#new'
end
end
root :to => 'promo_pages#index'

Active Admin Causing Issues with having different 'root' for logged in and logged out users with Devise [duplicate]

Active Admin is a gem used for having an admin dashboard in your application. It uses Devise for logging in users and creates a separate admin_user model for the admins. My application already uses devise and has its users as the user model. Ever since I started using the active admin gem, in my routes file the following line keeps resolving to home#index and not users#dashboard even when my user is logged in. This used to work fine earlier where logged in users were taken to users#dashboard as the root url.
root :to => 'users#dashboard', :constraints => lambda {|r| r.env["warden"].authenticate? }
root :to => 'home#index'
What is happening is that the .authenticate? is checking for the admin_user (belonging to Active Admin) being logged in or not but not my user model which is what I need to check for, so when I am logged in to active admin interface, my site root becomes users#dashboard instead without checking if the user is logged in or not. How can I make .authenticate? check for the user being logged in and not admin_user ?
Any help or clues will be very much appreciated
I was able to solve this. The issue was related to Devise expecting a single user model in the application. Here is how to fix it.
In the config/initializers/devise.rb file, add:
config.scoped_views = true
and
config.default_scope = :user #or whichever is your regular default user model
thats it, warden checks the :user for being logged in and not :admin_user
Why are you using the get "/"? You should remove it. I'm using a definition pretty similar to yours and works fine with me. Use just:
root :to => 'users#dashboard', :constraints => lambda {|r| r.env["warden"].authenticate? }
root :to => 'home#index'
I am not sure, but you can try something like
root :to => proc { |env| [ 302, {'Location'=> env["warden"].authenticate? ? "users/dashboard" : "/home" }, [] ] }
What worked for me is:
constraint = lambda { |request| request.env["warden"].authenticate? and request.env['warden'].user.instance_of?(AdminUser) }

Resources