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
Related
I am using devise for user registration/login, after the user has successfully signed up, I want to show a page/a dialog box and redirect to another page based on user response. How can I do that?
User Model (By devise)
username
password
Student Model
name
student_id
Teacher Model
name
grade
First_page:
signup signin links
Signup link will show the devise views/devise/registrations/new.html.erb page.
After successful signup, it takes the user to root page. I have defined the root page in routes.rb:
` Rails.application.routes.draw do
devise_for :users
resources :students, :teachers
# For details on the DSL available within this file, see http://guides.rubyonrails.org/routing.html
root to: "students#index"
end `
At this point, the application doesn't have any idea who the user is.
So, I want to get the identity information(student/teacher) from the user.
How will I get this information?
Student/Teacher controller:
`class StudentsController < ApplicationController
before_action :authenticate_user!, only: [:new, :create]
def index
#students = Student.all
end
def new
#student = Student.new
end
def create
current_user.create_student(student_params)
redirect_to root_path
end
private
def student_params
params.require(:student).permit(:name, :skypid)
end
end`
After the user has successfully signed in, I want to ask if the user is a student or teacher. Based on what they select, redirect them to a student form page or teacher form page.
How can I do that in rails?
Thank you
You can write a custom after_sign_in_path_for function in your ApplicationController assuming you're using all the default Devise controllers otherwise. Any named path helper or other route that it returns will be where the user is redirected, so you could do something simple like always redirect to a selection page that presents the options and handles the choice on a subsequent action:
def after_sign_in_path_for(resource)
user_type_selection_path # whatever route in your app manages the selection
end
Alternately, you could invoke a custom method on the user model in that function to make a choice right there:
def after_sign_in_path_for(resource)
resource.student? ? student_path : teacher_path
end
You could hybridize these of course as well to do the latter when the selection has already been made and redirect otherwise, with something similar to the following:
def after_sign_in_path_for(resource)
if resource.user_type_chosen?
resource.student? ? student_path : teacher_path
else
user_type_selection_path
end
Bear in mind that none of those functions or paths are real, since I can't be more specific on the information you've provided, but hopefully this gets you headed in the right direction. The after_sign_in_path_for hook is your primary tool here, unless you get into the world of overriding the default devise controllers and interrupting the usual workflow there to accommodate this step, which doesn't seem strictly necessary by your description.
I'm using ActiveAdmin with no default namespace (config.default_namespace = false). I have a User Resource without namespace as well as an User Resource in the :admin namespace. Both use custom update methods to achieve different behavior (users can change their own data, while admins can reset the password of any user).
This is the "default" user:
ActiveAdmin.register User do
actions :show, :edit, :update
menu false
permit_params ...
controller do
def update
# change account data
...
end
end
form do |f|
...
end
end
And this is the admin User:
ActiveAdmin.register User, namespace: :admin do
actions :all
menu
permit_params ...
controller do
def create
# invitation code
...
end
def update
# password reset code
...
end
end
index do
...
end
filter ...
form partial: 'form'
end
Changing the user data works just fine, as well as inviting new users. The problem is the password reset. When submitting the corresponding form (route /admin/users/[id]/edit), the update of the non-namespaced users is called (same as when submitting /users/[id]/edit) instead of the update in my :admin namespace User resource.
Is this a bug or did I misconfigure something? I'm honestly stumped by this behavior, I don't even know how to proceed with debugging this.
The problem wasn't due to the namespaces, but because of my form...
I'm using semantic_form_for, which automatically configures everything based on the model. Since it receives an User, the form action will always send the data to the default User route instead of the :admin route. Manually setting the url fixed the problem.
I am building a rails app and I use Devise for authentication. I want to show a product first page when user comes to www.mydomain.com instead of www.mydomain.com/users/sign_in which is devise default!
I will also want to show a different root view when user is logged in. This feels like a very common use case, is there a easy way to do this? Is this there in documentation or can anyone help me with this?
You can use the authenticated route helper provided by Devise to add a constraint on the routes so that they are only available to logged in users:
Rails.application.routes.draw do
devise_for :users
authenticated :user do
root 'secret#index', as: :authenticated_root
end
root "home#index"
end
The advantage over #Sergio Tulentsev's answer is that this does not cause a redirect or require any additional logic in the controller.
However the reason your app is redirecting to /users/sign_in is most likely that you are using before_action :authenticate_user! in your ApplicationController so that the controller handling the root path is requiring authentication and redirecting to the sign in. You can fix this (while retaining a secure by default setup) by skipping the callback:
class HomeController < ApplicationController
skip_before_action :authenticate_user!
# ...
end
This applies to any controller that should not require authentication. You can skip specific actions by using the only and except options. Just remember that whitelists are more secure than blacklists.
I'd do this way, have a single route for root path:
# routes.rb
root to: 'home#index'
Then check for current user and decide which page to show.
class HomeController < ApplicationController
def index
if current_user
redirect_to some_page_path
# or render some content directly in this response
render :some_view
else # no logged-in user
# same, render or redirect
end
end
end
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?
I need a 'Contact' link for both authenticated and unauthenticated users that will send them to
new_user_widget_path(current_user)
This doesn't work for unauthenticated users of course because there is no current user. The method I've been using to solve this problem is to have two routes:
resources :widgets, only: :new
resources :users do
resources :widgets
end
The only purpose of the first route is to provide redirection in the unauthenticated case, and then redirect that user to the new widget page once he signs in.
class WidgetsController < ApplicationController
before_filter :authenticate_user!
def new
redirect_to new_user_widget_path(current_user)
end
end
This works perfectly well, but I'm curious, has anyone come across a more elegant solution to this problem?
I don't think there is anything particularly wrong with your approach. An alternative is to have a guest user. In my app, if a user requests a page with needs authentication, I redirect them to the login page, and then redirect them to the page they were trying to go once they log in. If you have a system like this, you can check if the guest id is in the full path and replace it with the now logged in current_user id.
User is not signed in and but you want proper redirection. In the view you can do this:
new_user_widget_path(current_user || "_")
And then add this to application_controller.rb
def stored_location_for(resource_or_scope)
if path = super
prefix = polymorphic_path(current_user.class)
path.gsub!("#{prefix}/_", "#{prefix}/#{current_user.id}")
end
end
which replaces the underscore with correct ID.
This is implemented on top of Devise's stored_location_for method but it can easily be adapted to other authentication setups.