I'm following the tutorial from Ryan B, but I got something wrong when trying to inspect the user's role.
Why I got a nil initialize parameter when I inspect it. Are there any connection between the initialize parameter with the Person Object, in Ryan's tutorial is using 'user' parameter on initialize method and User Model. Am I forgetting something basic here? These are my codes, Thanks!
class Ability
include CanCan::Ability
def initialize(person)
raise person.inspect
can :read, :all
end
end
Most likely there is no logged in user when you are running this code. You need to create some sort of guest user to check permissions against non logged in users
def initialize(person)
user ||= User.new
if user.role? :somerole
can :read, :all
else
#whatever guest can do
end
end
Related
In my project, I have a user class working with Devise authentication. Each user have one role associated with. For exemple, a manager is the role #1.
Role is a class and there is an association beetween role and user based on role_id. So a manager will have a role_id of 1.
I installed cancancan gem to manage permission for each user. Only a manager can create user account. So, I wrote this in the ability class:
def initialize(user)
user ||= User.new # guest user (not logged in)
if user.role_id == 1
can :manage, :user
else
cannot :manage, :user
end
end
In my user controller, I have this:
def new
#user = User.new
authorize! :manage, #user
end
The problem is when I login with my manager and try to access to new user page, I receive the message from cancancan saying that I don't have the permission to access the page.
I don't know if it's my condition or when I'm trying to access to user.role_id or...
Thanks for your help.
See cancancan gem : https://github.com/CanCanCommunity/cancancan
Edit:
It's normal if my IDE says that it cannot find current_user?
Also, if you check on github, there is an example of how to use cancancan:
As you see, there is an #article after the read permission. So I don't think I need to put current_user instead of #user
Finally:
Problem was the :user that was not correct. When it's a model, you need to write a capital letter first for the name of the model without ":". So instead of :user, it should be User
current_user relies on a Rails session. Since this is your #new action on your Users Controller, you don't have an active session, thus no current_user.
I'm working on my abilities model on my Rails app to define my user authorization/abilities using cancancan. At the moment, here's what my ability.rb file looks like this:
class Ability
include CanCan::Ability
def initialize(user)
user ||= User.new # guest user (not logged in)
if user.admin?
can :manage, :all
else
can :manage, Application
can :read, User
end
end
end
I'm testing my app now. when I log into an account that doesn't have the admin boolean and go to to say /users, they can access that page, but clicking the show buttons or anything else leads them to the root page and says that they don't have permission. Currently I have an Applications controller/model (poor naming convention, realized later). But I simply wanted to make it so that any user who has a boolean FALSE for if they're admin has different abilities. I want the admin? true person to be able to do anything, but I want everyone else to be only able to SEE THEIR OWN own application (not everything entered by all users), only be able to create one application, and only be able to see their own information on the user show page, and only be able to edit their own user information. Can anyone explain how to specify for the things only the users create and such? Thank you!
define role column into your database and insert following line into your model
generate migration:
class AddRoleToUser < ActiveRecord::Migration
def change
add_column :users, :role, :integer
end
end
insert this into your model like (User.rb)
enum role: [:Admin, :Client, :Enduser, :ClientUser, :Moderator]
then you can manage your permission using cancancan
class Ability
include CanCan::Ability
def initialize(user)
user ||= User.new # guest user (not logged in)
if user.admin?
can :manage, :all
else
can [:new,:create, :update, :destroy], User
end
end
end
In my ability.rb file, how can I set it so that only defined users can do things, else (an undefined/not logged in user) cannot do anything?
Example:
def initialize(user)
user ||= User.new #not logged in user
if user.admin_user?
can :manage, :all
else
#can't do anything. Cannot view, edit, or update.
end
end
Thanks!
I've never really used CanCan, but I looked over the docs, and I don't think you need to explicitly define what the user can't do.
You should just be able do something like this in your controller:
if cannot? :destroy, #project
# redirect the user or do something else to disallow access
end
cannot? should return true if the user wasn't assigned a role that has any abilities defined. Conversely can? would return false.
You could try a simple conditional set in your initialize function:
# app/models/ability.rb
def initialize(user)
if user && user.admin_user?
# Abilities for registered admin users
can :manage, :all
elsif user
# Abilities for registered users
can :read, :all
else
# Abilities for no user
end
end
When initialize is called, user will likely (depending on your authentication solution) be nil for not logged in users, which will trigger the last branch.
I was wondering how I can define an ability class and serve that ability class depending on the user that has logged in.
I am using Active Admin, Can Can and Devise and I have successfully created a User and an AdminUser models.
I have this in my ability.rb
class Ability
include CanCan::Ability
def initialize(user)
user ||= User.new
if (user)
can :manage, Item
end
end
end
Now I have used this wiki entry to determine that we can indeed define a custom ability file and use that instead of the ability.rb:
https://github.com/ryanb/cancan/wiki/changing-defaults
But what I wanted to do is, be able to use ability.rb if a "non-admin user" is signed in and a custom abilty if a user admin is signed in.
Side Question: Could it be done such that I don't need a custom one and I could set permissions in one ability.rb file?
I've never really used ActiveAdmin, so I'm not entirely sure if I'm missing something, but it doesn't seem like that framework relies on CanCan. That's why I'm assuming you're defining a current_ability method like explained in the wiki and it's instantiated with Ability.new(current_user).
If that's the case, and your current_user can be either a User or an AdminUser, then there's no problem in checking for that in the Ability class:
class Ability
include CanCan::Ability
def initialize(user)
user ||= User.new
if user.kind_of? AdminUser
can :manage, Item
elsif user.kind_of? User
can :read, Item
end
end
end
You can simply take a look at the user's type and change the rules accordingly. You can also use is_a? instead of kind_of? for stricter checking, but it's probably not required and might cause issues if you decide to do inheritance later on.
Another way you could check is by defining an admin? method in both models. This might be a better way to do it, since explicit type checking is not very popular in ruby -- it often limits your choices. It might look like this:
class User < ActiveRecord::Base
def admin?
false
end
end
class AdminUser < ActiveRecord::Base
def admin?
true
end
end
class Ability
include CanCan::Ability
def initialize(user)
user ||= User.new
if user.admin?
can :manage, Item
else
can :read, Item
end
end
end
Please, give me any idea about a little problem: in my Rails 3 app I need current_user always be NOT nil. I'm using Devise and CanCan for auth system and I thinking about how to implement "guest" user. For roles like "admin" it works fine ( if current_user.is? :admin), but if user is not logged in I wish to check not user_signed_in?, but the same way (if current_user.is? :guest) for example.
I think I need to put somthing creating current_user object ib before_filters of Application_Controller, but I dont' know how to create this global thing right way.
Thanks for any answers!
You could try it like this:
if current_user.try(:is?, :admin)
So it won't matter if current_user is nil
If you are using 'CanCan' you should be adding functionality like you mentioned into you Abilities class. For example:
class Ability
include CanCan::Ability
def initialize(user)
user ||= User.new
can :manage, :all if user.is? :admin
can :read, :all if user.is? :guest
end
end
For more information take a look through the Wiki or watch the screen cast:
https://github.com/ryanb/cancan/wiki
http://railscasts.com/episodes/192-authorization-with-cancan