#192 Authorization with CanCan
Dec 14, 2009 | 15 minutes | Plugins, Authorization
CanCan is a simple authorization plugin that offers a lot of flexibility. See how to use it in this episode.
- Download:
- source code
- mp4
- m4v
- webm
- ogv
I've been using CanCan on my latest project, with our easy_roles gem doing the user side role storage.
easy_roles supports bitmask storage and serialize.
Check it out at http://github.com/platform45/easy_roles
CanCan + easy_roles = Complete roles based authorization!
thanks!
>Keep the "authentication-casts" coming
>have a full authenticated application
Say it with me: "Authorization"
NOT authentication.
Thanks Ryan, both for another wonderful screencast and for your new authorization plugin. I like the expressiveness it gives to the code.
Hey Ryan,
CanCan looks fantastic. Nice job! I love how simple and declarative it is. Thanks for taking the time to write something like this up.
@Jamie, Felipe, Stephen, thanks! Fixed. :)
@Nicholas, no, since the the comment.user will be nil for guests and therefore not match User.new.
Thanks for one of the reasons that mondays are nice!
:)
Keep up the good work, really appreciate it! It's the only screencast that I follow.
Now I'll see if I can use CanCan on one project I'm working on...
It looks very nice but i am wondering how you can hide parts of the page which are not bind to an action, like a formfield or an extra navigation?
Great work as always Ryan!
I was wondering how would I implement something like this with accounts? I have many sub-domains (accounts) and a user can be a manager in one account and a rep in the other. Is there a way to send in Initialze(user, account)?
Thanks!
This is great, I was looking for something like this and just found it..
Thanks for making it simple and straight
This is great! I'm pretty new to rails, but you make your presentations so clear and easy to understand. Such a task could be pretty hefty if your not used to some of the ideas you explain in this article but this code makes it seem so simple. Thanks!!
Someone can tell me if something like this in rails?
RBAC paradigm [2]
[1] http://nomadblue.com/projects/django-rbac/
[2] http://en.wikipedia.org/wiki/Role-based_access_control
I like the way you do this : Tap ! VOILA !
RailsCasts is getting better and better!
I'm wondering if there's a way to do dynamics role from the website. For example as an owner of my company I want to create and give access to my finance manager to manage all of my employees' salaries. Not from the code or constant, but dynamically from a website.
Very nicely done Ryan. I truly appreciate all the hard work you put into this website for us. Thank you!
Wow, the Ability class looks complicated! ... and that's only three roles! I dread what it would look like with more roles.
I'm also afraid that removing all that instantiating from the Controller code would be confusing for other developers who look at my code.
Okay, you made me fall in love with Declarative Authorization, and I got it working. So I have three questions about CanCan.
1.) It strikes me that CanCan is very similar to DA. What are the key 2 differences between CanCan and DA? What does 'heavy' mean?
2.) You showed us two controllers: comments & articles. I would love to see the users controller and see if you are able to use the current_user method there. I had to turn off the auto-model-loading functionality in my user controller when using DA.
3.) In comment 29 of episode 188 Jochen Kempf shared a way to 'control non-action related content'. Does CanCan have a solution for this?
Hi Ryan!
Thanks for doing a screencast on this. I haven't had the time to dig deep into CanCan but from what I saw earlier it seemed very nice. Now, after watching this video it will definitely be my main authorization tool! I really like it's simplicity, productivity and approach to handling authorization.
I tried it out and it works fantastic. I have one question though. I noticed the ability.rb file could become quite long, depending on the amount of roles and models you want to authorize. Do you have any recommendation (or would you not recommend it) to put each "role" in it's own file? Like maybe: lib/roles/user.rb moderator.rb admin.rb etc. and then load them in? If you would separate them, how would you organize this? (just looking for some conventions) ;)
Thanks again.
I am looking forward to using this in my future applications!
hi ryan,
first thanks for the cancan.
question, in your example there are multiple blogs/subdomains, can i set up cancan where a user can have different roles depending on the group/blog/subdomain he/she is a member of?
to brute force this, i would have a user, group, and groupmembership table where groupmembership table would contain user_id, group_id, and role_id. can cancan make this easier?
thanks!
What I want to know is if the action name is "update_article" instead of "update", the following code can still work?
<% if can? :update_article, @article %>
<%= link_to "Edit", edit_article_path(@article) %>
<% end %>
I like the idea of declarative authorization and I plan to implement it on my front-end application. However I feel that CanCan makes one incorrect and oversimplifying assumption: that (for example) the :update action applied to an object in one controller is the same as :update applied via a different controller.
Of course I am talking about the case of MyObjectsController vrs Admin::MyObjectsController.
I am sold on using separate Admin:: controllers due to vast differences in the interface for admin/non-admin usage. That leaves me needing to authorize actions based not just on the model and user (as CanCan seems to do,) but also on what controller is selected.
Am I missing something? Have I overlooked a simple way to use CanCan's ability definitions to limit actions by controller?
Great plugin! However, I am having trouble using it on a controller without a companion model. For instance, I have a Calendar controller that builds and displays a calendar but there is not Calendar model for CanCan to lock onto. So I'm getting a "uninitialized constant" error when it tries to create a Calendar model.
I realize that I should probably not be calling "load_and_authorize_resource" but I'm not sure how else to get CanCan to secure the controller. Any tips on using CanCan without a model?
Re: my previous post ( RnR Tom Dec 22, 2009 at 17:41)
A simple solution is available at:
http://wiki.github.com/ryanb/cancan/authorization-for-namespaced-controllers
Woooo that's THE plugin 2009 ! ;) I love it.
I facing a small problem (for me).
In my UserController I have load_and_authorize_resource and
def edit
@user = current_user
end
And of course I get a exception when a non authenticate user try to access to /users/:id/edit because it's trying to load the user in load_and_authorize_resource.
So where is my mistake ? :S
Is it not possible to check the right before loading the ressources into load_and_authorize_resource ?
Cancan is so great and fast to implement !!! :)
Thanks
AccessControl all the way.
http://github.com/Adman65/AccessControl
FYI, Looks like the repo moved to: https://github.com/jingtian/AccessControl
I get undefined method `can?' for #<ActionView::Base:0x56ab314> in the my contoller. What's wrong?
Lets say i have the article model like in the example and i want that every user is only able to see his own articles and admins can see all articles. How would i do that with cancan ?
I got some problems using cancan.
Its working ok, but after ive installed the gems, this is the output of my rake gems:install:
sudo rake gems:install
(in /Users/tscolari/Projetos/skeleton)
rake aborted!
uninitialized constant ApplicationController::CanCan
(See full trace by running task with --trace)
First of all, great plugin Ryan! I have a question (probably too simple): I used the :nested option for nested resources, now how do I get the instances of those resources in my Ability class, specifically for the block:
can :action, Model do |model| ...
great plugin Ryan, during evaluation of it I have created an advanced structure for rights management (have a look at http://niczsoft.com/2010/01/complex-associations-in-rails-activerecord/) and there I have a problem with deep nesting and activerecord, maybe complex associations might be covered by one of next railscasts ?
very nice gem ryan, well done. However, does the gem now supports nested roles e.g. being able to declare one role as part of another role? This would be useful for situations like you a reader_guest, and an editor_guest; the editor_guest can then 'contain' the reader_guest.
Declarative auth supports this; but cancan is so much simpler. Thanks again
I know there are many "authentication" plugins and gems, but it would be just GREAT if you add all of "needed" basic gems to your one-stop nifty generators!
1. authentication w/ full functionalities
2. layout w/ decent style(s)
Thanks!!!!
once CanCan is added to a project,
there are problems with my user edit link.
<%= link_to "Edit Profile", edit_user_path (:current) %>
error
Couldn't find User with ID=current
Anybody know any fix's?
cannot :index, User
why does this block all users
if I have added
can :manage, :all if user.role == "admin"
Admin user should be able to view index, right?
http://stackoverflow.com/users/283179
Hi Ryan,
Thanks again for the great screencast! Question about the Ability class, you are doing a check for role?, but what if there's a many to many user-role relationship? Does cancan know to check all the roles? or should Ability.rb be updated to user.roles?
I keep getting undefined method `role?' for #<User:0x1032be9a0>
my guess is it's because the user has many roles so user.role? really should be user.roles?, but that doesn't work either.
I'm going to dig into the cancan code and see what i can dig up.
Thanks,
John
Ryan, why does the method "load_resource" is called from the method "load_and_authorize_resource" in the "resource_authorization.rb" file?
It was causing me some problems when I try to call a controller without a model like ApplicationController or when I use it to manage a model within an other controller, so I tried to take it out and everything seems to work.
Thanks.
Very very useful plugin!!!
Only one thing I've found...
I got this error:
wrong number of arguments (1 for 0)
app/models/ability.rb:6:in `role?'
app/models/ability.rb:6:in `initialize'
ability.rb (line 6):
if user.role? :admin
user.rb:
def role?
roles.include? role.to_s
end
So the error seems to be in user.rb but no luck :(
Could you help me or say me what's wrong?
Thanks a lot!!!!!
Question: Does it work with Rails 3 ?
Great, but what about Aegis?
http://github.com/makandra/aegis
It seems to have put all the pieces together in a very practical way also...
i have done everything in this tutorial up to adding the load_and_authorize_resource line to my controller, which causes this error:
undefined local variable or method `load_and_authorize_resource' for GameController:Class
if i only include CanCan in my ability.rb file then I don't see how it is included into the app unless I include the ability.rb file or tell it to load somewhere
Great plugin! One question: how can it be applied to a controller that have no model?
OK, I figured it out: Let say I have a modeless controller, "MymodelessController" with some_action action. 1. In MymodelessController class use instead of load_and_authorize_resource ,
authorize_resource :resource => :mymodeless
2. in ability.rb refer to it as: if user.role?(:power_user) can :some_action, :mymodeless Thanks Ryan, indeed, a great plugin!!!
Great, plug-in/gem, Ryan.
Now, is it just me, or is the matching_can_definition() method in the Ability module doing the wrong thing by traversing the rules in reverse order?
I mean, shouldn't it traverse the can definitions in the order they were declared in the Ability#initialize method?
Great screen cast but I agree with the other guys about the database design being bad. Definitely fine for really simple purposes, but it's not scalable. I wrote a post on how to set up Devise and CanCan, while implementing the typical User HABTM Role relationship. Would love everyone's feedback. Here is the link - http://www.tonyamoyal.com/2010/07/28/rails-authentication-with-devise-and-cancan-customizing-devise-controllers/
HI
Thanks for the great plugin, i have watched the vedio and i have tried to use cancan but i keep getting a "wrong number of arguments (1 for 0)" when i try to use the can? or load_and_authorize_resource
what could be the problem? i used them the same way you did.
Might have been useful to show that you can use the "authorize_resource" filter instead of "load_and_auth..". For my particular app I needed to be in control of the loading and it was only after monkey-patching it that I browsed the gem code and saw that I could use the other filter. Lovely gem, made my life easy.
Nice gem, Ryan. Simple to use and allows plain ol' Ruby in the access rules. Reminds me a lot of the Aegis gem from Makandra.
Sometimes I prefer to return the proper 403 HTTP code instead of redirecting to the homepage. Here's how, if others want to:
1. Create a public/403.html file
2. Replace the rescue_from statement in ApplicationController with:
rescue_from CanCan::AccessDenied do |exception|
render :file => "#{RAILS_ROOT}/public/403.html", :status => 403
end
Hi Ryan, nice work but i need the permission logic in the database, i can't figured out how to make the models (rol and permission). You can help me?
Thanx
Well, the post is in reality the freshest on this noteworthy topic. I harmonize with your conclusions and will thirstily look forward to your future updates. Saying thanks will not just be sufficient, for the exceptional lucidity in your writing
Many thanks Ryan - a gem of a gem.
One thing:
I'm having problems getting cucumber to recognise cancan authorisations. Capybara says the correct user (with correct roles) is logged in, but displays the cancan "not authorized" message. Accessing the same page outside of cucumber, with the same account, offers access.
Any ideas what I'm missing? I've tried everything I can think of and I'm pretty stumped. If you have any suggestions I'd be really appreciative. Relevant code here: http://dpaste.com/242546/
I'm trying to test a rails helper using CanCan but keep getting an undefined method error:
"undefined method `can?' for #<Spec::Rails::Example::HelperExampleGroup::HelperObject:0x10359ab38>"
Rspec view tests that call the same helper method run, but not the helper test. For now, I've mocked the 'can?' method, but I'd rather have CanCan called. Can this be done?
Regarding my previous post (#122): I've realized that I don't need can? available to my rspec HelperExampleGroup::HelperObject. It's better for testing the view helper that I mock the can? method. Thanks.
great gem. I prefer to write the links a little shorter:
<%= if can? :update, Article then link_to "Edit", edit_article_path(article) end %>
Not sure if this will help anyone but I spent a couple of hours figuring it out.
If you make a custom action like
can :assign_roles, User
then the :manage ability for User will also allow them to assign roles.
I had assumed that :manage was just an alias for :index, :show, :new, :create, :edit, :update, and :delete but after scratching my head for a couple of hours I realized that :manage causes the can? method to return true for any action.
I suppose if you could alias the crud actions in the ability initialize block like
alias_action :index, :show, :new, :create, :edit, :update, :delete, :to => :crud
then you could use
can :crud, User
and
can :assign_roles, User
separately.
I haven't tested it but I think it should work.
Hi Ryan,
Just checking this cool gem. One question though... In case of a CanCan::AccessDenied, how can I redirect to the previous page instead of root?
I tried:
https://gist.github.com/794752
That doesn't work.
Thanks
Ryan I found this CanCan through your great Railscasts. I really enjoy them! Thanks!
Do you know if anyone has used CanCan with a 3 Model setup, like Users, Roles and Resources? User has many :roles and many :resources through :roles. Resource has many :roles and has many :users through :roles. Roles has BT to user and resource.
Seems like another layer to me.
Insights/thoughts would be so appreciated. Thanks Again!
Ryan,
I am working on SaaS based Application and I have company_id in all tables for multi-tenancy.
How can I use cancan for this application?
Hello, I notice the article id that you have in your video is 53582982. Is that the actual id of the article in the database or is it encrypted? If it's encrypted, did you use a gem for it?
Thanks,
Kyle H.
Today I needed to implement role-based authorization. I reviewed a few gems, and the cancan gem looked like the easiest to implement (and it had the most downloads and most forks on github).
It was a true pleasure to integrate this into my app! Works like a charm. Simple, and effective.
Now I need to remove the old half-finished, hard-coded authorization logic, and that may actually be more work!
Thanks Ryan, love your screencasts. This gem was so easy to use, I didn't even bother watching the screencast :-)
is it possible to add a 'can' ability to a whole namespace?
Hi,
I am using cancan 1.6.7 on a Rails 2.2.3 app.
My ability class is as follows:
When loading a page, I am getting the following error:
NameError in AController#edit
uninitialized constant CanCan::Ability::I18n
Any one knows why?
Thanks.
Nice! But I'm wondering, is there a reason not to do authorization from scratch? In all my apps now I've got user.admin field (or UserRole model when in one that need more privileges). Then I just use a before_filter to check whether user has given privileges, and skip_before_filter in controllers where certain authorization is not needed. Are there any disadvantages of that method?
Ryan, as you're a big fan of writing authentication from scratch, I'd really like to know your opinion on whether there is a good reason to not to do this for authentication.
I personally don't think there is. I worked on a rails app where I built the authorisation from scratch with the roles hardcoded and denormalized in a string in my user model.
Hi Ryan - I wanted to clarify how the object is used in can?. For example...say you have "@users.each do |u|"...with can? inside the loop. I notice many examples freely use either "User" or "u" as the object in can?. Is there a difference? It seems like calling the model as the object "can? :edit, User" would signify "current_user can edit users" whereas "can? :edit, u" would signify "current_user can edit this user"...since u is specific to a record and User is general to the model. Maybe Im putting too much thought in to this. Just wanted to clarify.
THANKS FOR CREATING CANCAN!
Are there any gotcha for using authorize_resource as opposed to load and authorize_resource? I'm getting different behaviour, where load and authorize works, but authorize does not prevent access to a resouce.
I posted a question on this: http://stackoverflow.com/questions/12860146/cancan-not-preventing-access-when-it-should
I have no clue why this is behaving in such a way!
In addition to this, does anyone know how we can authorise child objects based on an association of the parent? I also posted about this here:
http://stackoverflow.com/questions/12885246/authorising-child-objects-through-a-parents-association-using-cancan
The docs breifly discuss this under "Accessing parent ability" (https://github.com/ryanb/cancan/wiki/Nested-Resources) but no mention of associations is made.
I am having problems to use CanCan's accessible_by method. If you have the time please take a look at this Stackoverflow question: http://stackoverflow.com/questions/14138408/cancan-accessibly-by-returns-different-responses-in-spec-and-controller
CanCan + Devise = awesomeness.
Ryan, any chance of updating this episode?
I second this
Hi Ryan,
Thanks for sharing all your free railcasts.
I have a question:-
Since you can intercept the incoming request and process the Ability why not process the rendered page and automatically filter out all the links and actions that would be routed to incoming resources that are protected ?
Any suggestions how to do this ?
Best regards ozpoz
I am using cancan for assigning roles to user.
I have category and subcategory table and another table shop.
Each shop have many categories and categories have many subcategories.
The user belongs to one shop and how can i say in ability the user of this shop can edit the subcategories that belongs to the category of that shop.
Ryan,
Are you planning on doing an update for Rails 4 compatibility?
cheers.
d
It looks like he doesn't support it anymore.
This fork works for Rails 4. https://github.com/neubloc/cancan/
How can I get cancan to lookup activerecords when I'm using the has_permalink gem?
If I access a url by it's has_permalink ID, example - articles/my-article-name/edit I get an error saying it can't find an article with that ID but when I access the article using the ID number it works fine.
Can anyone please help me with this question on defining multiples roles depending on instances of a single model?
http://stackoverflow.com/questions/18482747/rails-using-cancan-to-define-multiple-roles-depending-on-instances-of-single-mo/18486809?noredirect=1#18486809
Thanks Ryan , I find it's very useful to use it with rolify gem
https://github.com/EppO/rolify
https://github.com/EppO/rolify/wiki/Tutorial
Thanks a lot, Rayan. You do great job with RailsCasts. This website is the most useful source about rails.
Anyway, function
load_and_authorize_resource
not works properly with Rails4. There isForbiddenAttributesError
generated sometimes. To solve it we should type this code into our applicationControllerFYI: Ryan is way too busy to maintain this gem so the community has taken it over and is keeping it updated. You can find the latest version here:
https://github.com/cancancommunity/cancancan
El vídeo me da error, he seguido un vídeo gratuito de la plataforma Ruby on Rails donde emplea otra gema llamada GitHub pero está explicado en español, para aquellos que deseen información en español.
Gracias
hello thanks for the gem Ryan.
you asked for comments & feedbacks here it is: i found it (the video) a little confusing some parts where rushed in explanation, but in any case, i will try the documentation and then ask questions if need be.