Rails 3.2
I have 2 sets of controllers, one for admin and one for regular users.
When an admin logs in, I want them to go to the index method, in controllers/admin/tickets_contoller.rb
I have the following in my routes.rb:
namespace :admin do
root to: 'tickets#index'
....
and in my application_controller.rb, I have:
def after_sign_in_path_for(resource_or_scope)
if current_user && current_user.current_company
view_context.can? :index, :admin
admin_root_path
end
end
But, when I log in as admin, it seems to be going to the standard tickets_controller, not the admin/tickets_controller
Any suggestions?
Related
I am having an issue with Rails_admin. rails_admin is successfully added to the app and working fine.
Issue is when I am trying to set the routes to a specific role user.
My app consists of several role like user, client, admin etc.
What I want here is only user with role 'admin' can access to rails_admin section by either using "link_to 'rails_admin_path'" or http://127.0.0.1:3000/admin.
Already I am having an admin section so I don't want to add any other login section for rails_admin, just need the features of rails_admin in my admin.
And I've a method called "check_admin" which will check the role of the current_user is admin or not
current_user.check_admin
#routes.rb
Rails.application.routes.draw do
mount RailsAdmin::Engine => '/admin', as: 'rails_admin'
end
Here what my requirement is, the given route can be only accessed by admin user
hints: check_admin or current_user.roles.admin.present?
Solution
routes.rb
authenticate :user, -> (u) { u.roles.admin.present? } do
mount RailsAdmin::Engine => '/admin', as: 'rails_admin'
end
Change route under a condition where it check for the particular role, in my case its "admin".
So the other users who are not an admin can't get an access to rails_admin in anyway
Upon request, expanding on my previous comment...
class AdminController < ApplicationController
before_action :reject_non_admins
def index
end
def show
end
# etc... all the admin CRUD actions
private
def reject_non_admins
unless current_user.check_admin
render "unauthorized.html" and return
end
end
end
so non-admin users are not prevented from accessing the sensitive admin pages, but they're just shown a page that tells them they're not allowed to see the content.
# app/views/admin/unauthorized.html
<p>Sorry, only admins can see this page</p>
The routes configuration is not the correct place to prevent the non-admin user from accessing the page. The routes configuration has no concept of current_user.
It should be done in the controller.
def show
unless current_user.roles.admin.present?
render "unauthorized"
end
# default "show.html will render
end
I am new in ROR and I am using Rails 5 version I have successfully created sign_in functionality from devise.
I am using devise for sign_in, sign_up etc.
I have created three roles: super_admin, manager and moderator.
super_admin have all manage permission but others don't.
get 'manager/dashboard', :as => 'manager_dashboard'
get 'moderator/dashboard', :as => 'moderator_dashboard'
get 'users/dashboard', :as => 'users_dashboard'
root "home#index"
devise_for :users
I want after sign_in redirect to different controller actions using devise.
super_admin after sign_in redirect users#dashboard.
manager after sign_in redirect manager#dashboard.
moderator after sign_in redirect moderator#dashboard.
You want to use after_sign_in_path.
In your ApplicationController, define a method after_sign_path_for(resource):
def after_sign_in_path_for(resource)
if resource.super_admin?
users_dashboard_path
elsif resource.manager?
manager_dashboard_path
else
moderator_dashboard_path
end
end
Here is the situation. I have a multi-tenant rails app using the apartment gem where I need to implement a LinkedIn OmniAuth Strategy.
As you can see by my routes, Devise users, and the associated routes, are only persisted on the individual schemas of the subdomains.
Example Route:
Good: https://frank.example.io/users/sign_in
Bad: https://example.io/users/sign_in
Routes
class SubdomainPresent
def self.matches?(request)
request.subdomain.present?
end
end
class SubdomainBlank
def self.matches?(request)
request.subdomain.blank?
end
end
Rails.application.routes.draw do
constraints(SubdomainPresent) do
...
devise_for :users, controllers: {
omniauth_callbacks: 'omniauth_callbacks'
}
devise_scope :user do
get '/users/:id', to: 'users/registrations#show', as: "show_user"
end
...
end
end
My specific problem is that LinkedIn does not support wildcards with their callback URLs so I am lost on how I might be able to direct users to the right domain after OAuth authentication.
So it turns out the answer was to pass parameters in the authorization link which would eventually get passed to the callback action throught request.env["omniauth.params"]
Authorization Link format:
Here I was having trouble adding the parameters to the Devise URL builder so I just manually added the parameters. This can probably be moved to a url helper
<%= link_to "Connect your Linkedin", "#{omniauth_authorize_path(:user, :linkedin)}?subdomain=#{request.subdomain}" %>
Routes:
Then I defined a route constrained by a blank subdomain pointing to the callback action.
class SubdomainPresent
def self.matches?(request)
request.subdomain.present?
end
end
class SubdomainBlank
def self.matches?(request)
request.subdomain.blank?
end
end
Rails.application.routes.draw do
constraints(SubdomainPresent) do
...
devise_for :users, controllers: {
omniauth_callbacks: 'omniauth_callbacks'
}
resources :users
...
end
constraints(SubdomainBlank) do
root 'welcome#index'
...
devise_scope :user do
get 'linkedin/auth/callback', to: 'omniauth_callbacks#linkedin'
end
...
end
end
Controller:
I used this tutorial to set up my callback controllers: Rails 4 OmniAuth using Devise with Twitter, Facebook and Linkedin. My main objective with the callback controller was to have it reside in in the blank subdomain so I only had to give one call back URL to my LinkedIn Dev App. With this controller I search the omniauth params for the subdomain parameter and use that to switch to the proper schema.
def self.provides_callback_for(provider)
class_eval %Q{
def #{provider}
raise ArgumentError, "you need a subdomain parameter with this route" if request.env["omniauth.params"].empty?
subdomain = request.env["omniauth.params"]["subdomain"]
Apartment::Tenant.switch!(subdomain)
...
end
}
end
could you register each domain as a callback with linked (I guess if you have a lot that becomes unmanageable quickly).. You could cookie the user before sending them to linkedin so when they return you know which subdomain they belong to.
I have a pretty typical situation where I have a '/dashboard' which should render a different view for different user roles (i.e. client, admin, etc.).
I am open to more elegant suggestions but my thought was to have one route definition for dashboard like so:
routes.rb
resource :dashboard
and to have a dashboards_controller.rb like so:
class DashboardsController < ApplicationController
def show
if current_user.has_role?('sysadmin')
// show system admin dashboard
elsif
// show a different dashboard
// etc
end
end
end
Now I would like that each dashboard gets built in its role specific namespaced dashboard_controller, ex: controllers/admin/dashboard_controller.rb. This way, each dashboard can be appropriately built up in the right place.
The way I am trying to do this is to redirect from my main dashboards_controller to the admin/dashboard_controller like so:
redirect_to :controller => 'admin/dashboard_controller', :action => 'index'
But it is not working, presumably because I am not sure how to reference a namespaced controller from here.
How can I achieve this?
(If there is a more elegant solution I am open but I thought this was pretty good).
I am using devise and cancancan.
You can do per-role dashboard, for example:
routes.rb
scope '/:role' do
resources :dashboard
end
resources :dashboard
Then to redirect with the role, just simply:
redirect_to :controller => 'dashboard', :action => 'index', :role => 'admin'
The Better Way
If you want custom dispatch per controller, you should consider using filter. E.g. given admin/dashboard only accessible by admin and user/dashboard only accessible by default user, you may want to create files like this:
routes.rb
namespace 'admin' do
resources :dashboard
end
namespace 'user' do
resources :dashboard
end
Then you create these files:
app/controllers/admin/dashboards_controller.rb
app/controllers/admin/admin_base_controller.rb
app/controllers/user/dashboards_controller.rb
app/controllers/user/user_base_controller.rb
For each files:
# app/controllers/admin/dashboards_controller.rb
class Admin::DashboardsController < Admin::AdminBaseController; end
# app/controllers/admin/admin_base_controller.rb
class Admin::AdminBaseController < ApplicationController
before_action :ensure_admin!
def ensure_admin!
redirect_to controller: 'user/dashboards', action: index unless current_user.has_role?('sysadmin')
end
end
# Now you've got the idea. Similar things for the rest of the files:
# app/controllers/user/dashboards_controller.rb
# app/controllers/user/user_base_controller.rb
Then you can try visiting it at admin/dashboards and user/dashboards, it should be redirected to its role accordingly.
It's good to use named route helpers rather than providing controller and action explicitly.
Consider adding routes as follows:
namespace :admin do
resource :dashboard, controller: 'dashboard '
end
Then you can call :
redirect_to admin_dashboard_url
Remember, it's resource, not resources. So it is going to process dashboard_controller#show, not dashboard_controller#index
Using devise, how do i make my Sign Up as my landing/welcome page and then after sign up they go inside the site to the Profile/signed in area?
I am trying to figure out how to make it like where Facebook their is two sides of the website; the Outside (sign up, about,contact,etc) and The Inside (Profile,sign out,etc) for Users only after sign up or sign in.
Thank you.
P.S. I am new at Ruby on Rails and creating applications but i did do the authentication system with the Rails 3 Tutorial, i understand most things to start using Devise, i jst dont know where to start with this situation.
I was going to use 2 application layouts, 1 before sign up which is layouts/welcome.html.erb with PagesController (about,terms,etc) and the other for signed in users which will be layouts/application.html.erb with ApplicationController (profile,news,add,etc), is this the best steps?
in your routes.rb:
root :to => 'welcome#index'
Where welcome is the controller and index is the action.
In your application controller:
def after_sign_in_path_for(user)
"/url_you_want_to_redirect_to/"
end
This my new and updated way using Rails 3.1.0 and Devise 1.5.0:
routes.rb
root :to => "pages#redirect_to_sign_up"
devise_for :users do
get "welcome" => "devise/registrations#new", :as => :new_user_registration
get "account_settings" => "devise/registrations#edit"
get "sign_in" => "devise/sessions#new"
get "sign_out" => "devise/sessions#destroy"
get "new_password", :to => "devise/passwords#new"
end
match 'home', :to => "user_pages#home"
namespace :user do
root :to => "user_pages#home"
end
application_controller.rb
class ApplicationController < ActionController::Base
protect_from_forgery
protected
def after_sign_in_path_for(resource)
stored_location_for(:user) || root_path
end
private
def after_sign_out_path_for(resource)
stored_location_for(:user) || root_path
end
end
pages_controller.rb
class PagesController < ApplicationController
def redirect_to_sign_up
if signed_in?.blank?
redirect_to new_user_registration_path
else
redirect_to home_path
end
end
end
user_pages_controller.rb
class UserPagesController < ApplicationController
before_filter :authenticate_user!
def home
end
def profile
end
end
I find it easiest to root to the desired authenticated landing page and just use a before_filter to force the user to sign in/sign up first via a before_filter.
In this case, let's say your "signed in area" is a controller/action called profile/index.
In your routes.rb, set the root to profile/index.
root :to => 'profile#index'
Then in your profile_controller, set the following before_filter.
before_filter :authenticate_user!
This will automatically push a logged in user (or one that logged in earlier and set a Remember Me cookie) straight to the profile page. Any unauthenticated users will automatically end up on Sign In. You'll want a link (or separate tab) on that page to Sign Up as well.
On the root page check to see if the user is signed in, and redirect based on that.
redirect_to sign_up_path if current_user.nil?
Alternatively, you could render different templates instead of a redirect, but I think it's cleaner to have a 1:1 mapping between urls and pages.
Another approach is to modify devise. Edit devise_gem_path/lib/devise/failure_app.rb and replace the two occurrences in the redirect_url method of:
:"new_#{scope}_session_path"
with:
:"new_#{scope}_registration_path"
A less destructive solution would make redirect_url's response more configurable.