Ive setup a application with two basic user roles.
A admin who can manage everything and a normal user and can create things (jobs & clients) but can not delete.
I'm a bit stumped though as to how can assign roles to the users. I assume it would be a case of adding a role column to my database? As user's are only created by the admin user. I need to add some sort of collection select to my form?
Can anyone point me in the right direction?
Edit: I tried the One role per user instructions as detailed on the cancan wiki here but i'm recieving the error uninitialized constant User::ROLES
Found an answer :)
I inserted this code..
ROLES = %w[admin user]
def role_symbols
[role.to_sym]
end
Into my User model and put <%= f.collection_select :role, User::ROLES, :to_s, :humanize %> into my form :)
Related
So I'll go straight to the point.
I'm using the ActiveAdmin gem, so I have the AdminUser model in my app... now I got a requirement from my client where a "super admin" must be able to control the permissions of other administrators.
So, for example, if I have the resources: Message, Client and Country, the "super admin" should be able to assign to an AdminUser the task of managing messages, to another one the task of managing clients and to another one the task to managing countries.
For this I was thinking about adding several boolean attributes to the admin_users table. For example, a boolean attribute called "super_admin" would be used to determine if this AdminUser can change the permissions of other AdminUsers, another attribute called message would be used to determine if this AdminUser has control (can edit, read, delete, etc.) over the messages, another attribute called country would be used to determine if this AdminUser has control (can edit, read, delete, etc.) over the countries and so on...
What's the problem? I can't access to current_admin_user in models, so I can't do something like this:
ActiveAdmin.register Message do
if (current_admin_user.message)
permit_params Commune.attribute_names.map(&:to_sym)
end
end
So what can I do? I must build this functionality!
edit
I found this gem that adds roles to active admin https://github.com/yhirano55/active_admin_role
why it needs to be in model ? Code looks like it should be placed in controller, permit_params...
I would use pundit. I can see can can was updated 5 years ago. They are similiar.
pundit repo: https://github.com/varvet/pundit
It uses policies, so you create policy for every model.
class PostPolicy < ApplicationPolicy
def update?
user.admin? or not record.published?
end
end
where you can check your flags on update or create or show or anything...
In action you use something like this authorize #post, :update?
Quote from their doc
In this case, you can imagine that authorize would have done something like this:
unless PostPolicy.new(current_user, #post).update?
raise Pundit::NotAuthorizedError, "not allowed to update? this #{#post.inspect}"
end
Hope it will help
P.S It you need more complex solution. I would create Role model, where I could specify model, read, write permissions. I would link it with my user to has_many roles, and in my policy do something like this:
class PostPolicy < ApplicationPolicy
def get_role
user.roles.where(model: "Post").first
end
def update?
user.get_role.write? or not record.published?
end
end
Or maybe there is better way to use it somehow in policy model...
I'm trying to create admin roles that can go in and change other users information. I've already got everything set up pretty much except that I can't get the edit method to select the correct user to update.
Looking in the devise code, it looks like I need to update the resource to be the user of the profile that's being selected instead of the current user (which would be the admin).
How do I go about updating the resource that is sent into the devise edit view and update action? It looks like it might have something to do with this
def authenticate_scope!
send(:"authenticate_#{resource_name}!", :force => true)
self.resource = send(:"current_#{resource_name}")
end
So for example, what I want to do is
def update_resource
self.resource = User.find(params[:id])
end
Is this possible?
How to achieve simple scoping in your views such as:
<% if #user.admin %>
where "admin" is the following scope in user.rb:
scope :admin, where(role: "admin")
there is a column Role which is a string in the Users table
I've done the same thing before with another Model (but not a devise user model) to which I could later call
<% if objective.completed %>
right after calling an each method in the objectives.
However
When I do the exact same thing to a user model I get an
undefined method `admin' for #<User:0x00000107e39038>
How could I make it work? I've been digging for hours.
For a no scope workaround try:
<% if #user.role == "admin" %>
You simply can't use scopes this way. Scopes are used as class methods, so if you run
User.admin
it returns list of users matching given condition. What you need is an instance method. Add it to your user.rb file:
def admin?
admin == 'admin'
end
and you will be able to use it in your view:
- if #user.admin?
anyways, you should definitely reconsider storing roles as string in users table. Try to create another table called roles.
Scopes are usually class level methods, having said that, how can you access it with an instance. I think, that is why the error says undefined method.
I have built a small ruby webservice, in this I have implemented cancan authorization.
I followed this tutorial. The problem is that, I can't find out the way to assign at the user, when they do the registration to my site, the base role level.
I find out to do this with a checkbox, but it's not what I want. My idea was to put this assignment directly into the registrations_controller, but I failed to save the role.
I hope that somebody can help me.
Thank you.
This is what worked for me
user.rb:
after_create :default_role
private
def default_role
self.roles << Role.where(:name => 'User').first
end
I had the same problem, but I am using embedded association from rbates:
http://railscasts.com/episodes/189-embedded-association
user.rb:
before_create :default_role
private
def default_role
self.roles = ['client']
end
Works like a charm, but pay attention that the hook is before_create, not after_create, because the before_create runs just before the insert operation.
The after_create is after the insert operation, which in my case is late.
I have rebuild the migration, I have unified the user and role tables, so now I can assign all without problem.
Thank you.
I am trying to figure out how to redirect users on certain URL based on their role, after they log to the Ruby/Rails3 application.
So far, I have used authlogic gem for authentification and cancan gem for role setting.
Roles are just like this (defined in app/models/user.rb):
class User < ActiveRecord::Base
acts_as_authentic
ROLES = %w[admin customer demo]
end
Now there is app/controllers/user_session_controller.rb which is taking care of logins.
I would like to make something like this:
for r in User.role
if r == "admin"
redirect_to admins_url
else
redirect_to users_url
end
end
This is not working because of the following error:
"undefined method `role' for #<Class:0xb5bb6e88>"
Is there a simple or elegant way how to redirect users to the certain URLs according to their roles?
(Roles are defined in mysql column 'role' in the users table.)
The for r in User.role is confusing. Are you trying to access the array of ROLES defined on the class or are you trying to access the role value of the current user?
If you are trying to access the array of ROLES, then use User::ROLES.
Using authlogic, one typically defines the current_user in the application_controller. So the role of the current user can be found using current_user.role
So your code could look something like
if current_user.role == "admin"
redirect_to admins_url
else
redirect_to users_url
end
You should definitely check out CanCan. It is a pretty logical way to manage user roles and abilities.