Rails_admin with devise - ruby-on-rails

I have Rails_admin installed with devise and I want to restrict the /admin dashboard to only admins. For the moment my code looks like :
config.authenticate_with do
warden.authenticate! scope: :user
end
config.current_user_method(&:current_user)
As you can see users can get in to the dashboard so I want only the users with a boolean true in the admin column of the user table to get access to the dashboard.
How would you suggest I do this ?

If you dont want to use cancan you can do this:
config.authorize_with do
redirect_to main_app.root_path unless current_user.try(:admin?)
end
I use this and it works fine.

I would recommend you to use an authorization gem called cancancan (is the updated version of cancan) it's super easy to use and it will let you to give certain permissions to different kind of users. If you don't know nothing about this gem i will recommend you to see this railscasts that will teach you how to use it properly.
So after you installed the cancancan gem in the ability.rb file you just need to do something like this to limit the admin access
models/ability.rb
class Ability
include CanCan::Ability
def initialize(user)
user ||= User.new # guest user (not logged in)
if user && user.admin?
can :access, :rails_admin # only allow admin users to access Rails Admin
can :dashboard
can :manage, :all
else
can :read, :all # allow everyone to read everything
end
end
end
And don't forget to tell to the rails_admin gem that you are using cancancan to validate the authorization
config/initializers/rails_admin.rb
RailsAdmin.config do |config|
## == Cancan ==
config.authorize_with :cancan
end
To user the "user.admin?" method you must create it into the user model, but it will only work if you have a role model that has_many users and users belongs_to role otherwise you will need other way to verify the role, so it will be something like this
models/role.rb
has_many :users
models/user.rb
belongs_to :role
def admin?
role_id == 0 # If you have id == 0 for admin
end
Also i will recommend you to use a role model or enum to manage the different roles with ease.
I hope it helps :D

Related

RailsAdmin + Devise + CanCanCan role not works without :manage :all

I apologize in advance for my English and knowledge of ruby :)
I making admin panel with RailsAdmin, authentication with Devise, authorisation with CanCanCan, so, I have three boolean fields in User:
add_column :users, :superadmin_role, :boolean, default: false
enter code hereadd_column :users, :manager_role, :boolean, default:
So, in ability.rb i have this:
class Ability
include CanCan::Ability
def initialize(user)
user ||= User.new # guest user (not logged in)
can :access, :dashboard # allow access to dashboard
can :access, :rails_admin # access Rails Admin for Admin-users
if user.superadmin_role?
can :manage, :all
end # role works correct
if user.manager_role?
can :read, :all
end #role works incorrect
end
end
SUPERADMIN_ROLE works correct and allow to enter to RailsAdmin and etc., but MANAGER_ROLE is doesn't work - when user try enter in Dashboard, there is an Access Denied error message is showing:
How to provide access for manager_role to dashboard and RailsAdmin interface - have broke the whole brain.
I will be glad to any help (ready code, links #where to read and etc) and constructive criticism
cancancan2 needs a different adapter for RailsAdmin. Please look at this issue: https://github.com/CanCanCommunity/cancancan/issues/413 and this issue: https://github.com/sferik/rails_admin/issues/2901.
On the first link you will find the code needed to create an adapter.

fetching logged in user associated record in rails_admin

I have installed rails_admin gem without any error its display models crud too,but i have requirement in which i need to show current_user logged in associated data
e.g User has many Books so in rails admin i want only that user book but currently it's showing all users books which is default behaviour of rails_admin
i have also try to use cancancan gem for achieve same thing but its not working my rails_admin initializers config as below
rails_admin.rb
RailsAdmin.config do |config|
### Popular gems integration
## == Devise ==
config.authenticate_with do
warden.authenticate! scope: :user
end
config.current_user_method(&:current_user)
config.parent_controller = 'ApplicationController'
## == Cancan ==
config.authorize_with :cancan,UserAbility
## == Pundit ==
# config.authorize_with :pundit
config.included_models = ["Book","User"]
config.actions do
dashboard # mandatory
index # mandatory
new
export
bulk_delete
show
edit
delete
show_in_app
end
end
UserAbility Class is implemented as below
class UserAbility
include CanCan::Ability
def initialize(user)
# Define abilities for the passed in user here. For example:
if user.present?
can :access, :dashboard
can :manage, :Book,id:user.id
end
end
end
Instead of can :manage, :Book,id:user.id, try using:
can :read, Book, user_id: user.id
So the abilities together look like:
can :access, :rails_admin
can :dashboard
can :read, Book, user_id: user.id
I think you're misunderstanding the scope of Rails Admin. In essence, it's a snapshot of your database, and is meant for more administrative operations like querying your database for something specific.
The only thing you'd reasonably be able to do is to look up all Books for a given user, with the default falling to all books for all users. Filters exist within the display to be able to narrow down based on a user's specific credentials, such as user name, email, or ID.
For a conceptual check, a user in Rails Admin isn't treated or regarded the same as a user in your application. Instead, think of using Rails Admin as a way to check the data in your database as opposed to showing data for a specific, authenticated person.
As you describe, the more appropriate Rails way to do this would be to create a controller and route for this data, and to simply use current_user.books to get all of the books for the current user.

How do I set admin credentials for rails_admin?

After installing and setting up devise for user login I went ahead and added the rails_admin gem. Now if I go too localhost:3000/admin I can access the admin dashboard but How do I add admin authentication so you would need to enter admin credentials to access the admin dashboard?
I would recommend you to use an authorization gem called cancancan (is the updated version of cancan) it's super easy to use and it will let you to give certain permissions to different kind of users. If you don't know nothing about this gem i will recommend you to see this railscasts that will teach you how to use it properly.
So after you installed the cancancan gem in the ability.rb file you just need to do something like this to limit the admin access
models/ability.rb
class Ability
include CanCan::Ability
def initialize(user)
user ||= User.new # guest user (not logged in)
if user && user.admin?
can :access, :rails_admin # only allow admin users to access Rails Admin
can :dashboard
can :manage, :all
else
can :read, :all # allow everyone to read everything
end
end
end
And don't forget to tell to the rails_admin gem that you are using cancancan to validate the authorization
config/initializers/rails_admin.rb
RailsAdmin.config do |config|
## == Cancan ==
config.authorize_with :cancan
end
To user the "user.admin?" method you must create it into the user model, but it will only work if you have a role model that has_many users and users belongs_to role otherwise you will need other way to verify the role, so it will be something like this
models/role.rb
has_many :users
models/user.rb
belongs_to :role
def admin?
role_id == 0 # If you have id == 0 for admin
end
Also i will recommend you to use a role model or enum to manage the different roles with ease.
I hope it helps :D
In your routes.rb
authenticate :admin do
mount RailsAdmin::Engine => 'rails_admin', as: :rails_admin
end
Provide your user with an admin role such that you can test, e.g. user.admin?.
Configure rails_admin to inherit from your application controller and to catch any access other than a signed in admin user.
#config/initializers/rails_admin.rb
RailsAdmin.config do |config|
...
config.parent_controller = 'ApplicationController'
config.authenticate_with do
# current_user = User.find_by_id(session[:user_id])
raise InvalidAdminAccess, 'Access denied.' unless current_user.try(:admin?)
end
end
Define the InvalidAdminAccess error class in
# app/errors/invalid_admin_access.rb
class InvalidAdminAccess < StandardError
end
Catch the error in your application controller
# app/controllers/application_controller.rb
class ApplicationController < ActionController::Base
...
rescue_from InvalidAdminAccess do |exception|
respond_to do |format|
format.json { head :forbidden, content_type: 'text/html' }
format.html { redirect_to main_app.root_url, alert: exception.message }
format.js { head :forbidden, content_type: 'text/html' }
end
end
end
In this way, when there is incorrect access, rails_admin triggers an exception that is caught and handled by the application controller.

Understanding CanCan Ability and Users

I have Rails Admin with CanCan support in my rails app. I'm confused on one issue though. How does CanCan know what user is signed in? For example, my users can have different roles and through CanCan I assign roles for certain access into each table. When I go to localhost:3000/admin, I receive the error
CanCan::AccessDenied in RailsAdmin::MainController#dashboard
My Ability.rb file
def initialize(user)
if user and user.role.eql? :super_admin
can :manage, :all # allow superadmins to do anything
elsif user and user.role.eql? :admin
can :manage, [Location, School] # allow admins to manage only Locations and Schools
end
end
So what do I do so that user's have the ability to sign in into Rails Admin? Do I have to manually create it?
By default, CanCan will use whatever is returned by current_user. If you are using Devise within a namespace though (admin for example) then Devise actually will use current_admin_user instead. You can either create a current_user method in your ApplicationController (or some other base controller) that returns current_admin_user or overwrite the current_ability method to instantiate the Ability with current_admin_user instead.
(this is all assuming your Devise is using a namespace. By default Devise will use current_user)
You need to have a current_user method available in your controller. Assuming you have that, if you aren't signed you won't have access to a current user, so you'll need to assign a user in your ability file if it doesn't exist. In your initialize method, add user ||= User.new to make the assignment if a user doesn't already exist.
def initialize(user)
user ||= User.new
if user and user.role.eql? :super_admin
can :manage, :all # allow superadmins to do anything
elsif user and user.role.eql? :admin
can :manage, [Location, School] # allow admins to manage only Locations and Schools
end
end

Configuring Admin in Rails_admin

So I've implemented the rails admin gem, and even with the cancan gem, I can't figure out a way to password protect localhost:3000/admin
Could someone give me a step by step guide for doing this? I can't really find a view or controller for the admin panel, so I'm not sure how to password protect it.
This page describes how you should be using Cancan : https://github.com/sferik/rails_admin/wiki/CanCan
# in config/initializers/rails_admin.rb
RailsAdmin.config do |config|
config.authorize_with :cancan
end
Their ability.rb example may be a bit more than you need this is mine :
class Ability
include CanCan::Ability
def initialize(user)
user ||= User.new # guest user (not logged in)
if user.has_role? :admin
can :manage, :all
can :access, :rails_admin # grant access to rails_admin
can :dashboard # grant access to the dashboard
end
end
end
You must then give the admin role to a user.
you can do this at the rails console as so :
user = User.find(1) #find user with ID 1
user.add_role :admin #assign role
user.has_role? :admin #should evaluate to True

Resources