Giter VIP home page Giter VIP logo

cancan's People

Contributors

andhapp avatar bowsersenior avatar davidmikesimon avatar dchelimsky avatar emmanuel avatar fl00r avatar flop avatar funny-falcon avatar jbarreneche avatar kirkconnell avatar manuelmeurer avatar mikepack avatar nandalopes avatar nashby avatar nhocki avatar nickclark avatar ramontayag avatar ryanb avatar schlick avatar spatil avatar spohlenz avatar stefanoverna avatar stellard avatar tanordheim avatar thatothermitch avatar twe4ked avatar tylergannon avatar xinuc avatar yuszuv avatar zliang-min avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

cancan's Issues

Should support load_resource for nested resources

load_resource should try to intelligently load nested resources:

http://localhost:3000/foos/1/bars/3

should result in the functional equivalent of the following:

@foo = Foo.find(params[:foo_id])
@bar = @foo.bars.find(params[:id])

[nested controllers] actions that appear twice

I have
(admin) * controllers/admin/pages_controller.rb
(regular) * controllers/pages_controller.rb

I have a show function in both controllers, but the show function in /admin is only for admins to use.

with "can :show, Page" a regular user is granted access to both show functions. Can I limit that down to only the regular controller?

load_and_authorize_resource exception when resource not found

In an application where it is possible to delete resources, one user may destroy an item while a second user has a link to that resource still up on the browser. When the second user clicks the link, load_and_authorize_resource will cause an exception when trying to create the page. Typical message is "Couldn't find Item with ID=47".

Normally, I'd just intercept the exception and apologize/redirect. But I am thinking that it would be cool if load_and_authorize_resource handled the "not found" case in a more friendly way since this situation can occur naturally, without any hacking or really anything resembling a genuine error, etc.

The "CanCan::AccessDenied" exception type makes handling that case easy enough, so perhaps throwing a specific exception type ("ResourceAuthorization::NotFound" ??) from ResourceAuthorization load_resource would be helpful. That would make it easy to handle the exception in an appropriate way at the application level, or by controller.

Any opinions on this? Am I just being a weenie and should just handle this with a general application-level rescue?

Before filter with load_and_authorize_resource

I know that load_and_authorize_resource calls your records for each restful action but I am having a hard time understanding what it really calls (without adding debugg to each action and check in the console)
Is there a way to let me define my own records and etc without having to do a bunch of before_filters myself?

Also, when using before_filter :this_method, :only => [:create, :update]
Do I need to define the other actions as well since I used a before filter myself?
Or does load_and_authorize_resource continue with it's own filters?

cancan and rails3?

Hi, Ryan!

So beta is out and I'm looking forward to use it in my new project, but I do need some great authorization system like yours cancan is. Are you planning to make it compatible with new rails?

Thanks.

Ivan.

The model function couldn't be applied on the objects inside can and cannot block

User Model

class User < ActiveRecord::Base
  ...
  def role?(role)
    roles.include? role.to_s
  end

  def roles=(roles)
    self.roles_mask = (roles & ROLES).map { |r| 2**ROLES.index(r) }.sum
  end
  
  def roles
    ROLES.reject { |r| ((roles_mask || 0) & 2**ROLES.index(r)).zero? }
  end
  
  def role_symbols
    roles.map(&:to_sym)
  end
end

And Ability

class Ability
  ...
  if user.role? :administrator
    can :manage, :all
    cannot :manage, User do |u|
      u.role? :developer
    end
  end
  ..
end

The error: undefined method `role?' for #Array:0xb6f01f0c

Superclass vs. Module

This is an architecture or interface question, and possibly irrelevant, but I'm curious: is there a reason a standard Ability class includes a CanCan::Ability module instead of inheriting from a CanCan::Ability parent class? To me the latter seems more natural. Is there another way CanCan can be used that is facilitated by the module design?

can action throws an array

I don't really know what I'm doing wrong, but I had this


if user.role?(:user)
        can :create, Album
        can :manage, Album do |album|
          album.try(:user) == user
        end

but the ability was returning an array so I got an "unknown method "user" for array" error. I debugged and notice that it was sending the action, and the object as elements... for example


can? :update, @album

was [:update, Album] and not just the album.

I had to add another variable to the block to make it work, so I ended up with something like this


if user.role?(:user)
        can :create, Album
        can :manage, Album do |act, album|
          album.try(:user) == user
        end

I don't really know why that happens and I was actually hoping you had an idea xD

Thanks,

:message option for load_and_authorize_resource and authorize_resource

It would be great if CanCan::ResourceAuthorization#authorize_resource respected a :message option so that custom messages can be set for whole controllers.

CanCan::ResourceAuthorization
  def authorize_resource
    if @controller.cannot?(params[:action].to_sym, resource.model_instance || resource.model_class)
      @options[:message].present? ? @controller.unauthorized!(@options[:message]) : @controller.unauthorized!
    end
  end
end

Then in whichever controller you want to apply a custom message to:

load_and_authorize_resource :message => "Please log in to continue."

or even just:

authorize_resource :message => "You must log in first."

can with multiple actions or classes

This example is provided in the documentation for specifying multiple actions and classes.

can [:update, :destroy], [Article, Comment]

However it still needs to be implemented.

CanCan and InheritedResources

Hi Ryan,

I was trying to use CanCan with Inherited Resources but I got to a problem when using the "authorize_resource" alone, without "load_resource".

This method ends up counting on an instance variable @model but that doesn't get set when using Inherited Resources until you call the "resource" helper (lazy loading). The way to make it work would be fetching it from the "resource" helper.

What do you think of adding a param/option to "authorize_resource" which would allow determining an alternative strategy of fetching the resource?

Thanks,
Marcelo Silveira

Define abilities with "cannot"

Sometimes it would be convenient to use a "cannot" expression for defining abilities. For example.

can :read, :all
cannot :read, [Order, Account]

The question is, should I allow blocks to be passed to this variation? At first I thought it would be confusing but I can think of some use cases now.

cannot :read, Product do |product|
  product.invisible?
end

Use the association name for nested resource?

Suppose I have the follow model:

class Post < ActiveRecord::Base
  belongs_to :owner, :class_name => 'User'
end

And the following controller:

class PostsController < < ApplicationController
  load_and_authorize_resource :nested => :user

  .....
end

While this works, it'd be neat if CanCan could initialise an @owner variable (rather than @user).

I imagine that this could be achieved by changing CanCan such that load_and_authorize_resource :nested => :owner achieves this, or perhaps adding an extra option to the hash, such as :renamings => { :user => :owner }

Is this reasonable / feasible? (I can try to write the patch).

How to deal with guest users?

I got

def initialize(user)
 user ||= login_as_trial_user
 
  private
  def login_as_trial_user
    name = "anonymous_#{Time.now.to_i + rand}"
    if User.find_by_username(name)
      UserSession.create(User.find_by_username(name),true)
    else
      guest_role = User.create(:username => name, :password => name, :password_confirmation => name, :role => "guest", :email => "[email protected]")
      UserSession.create(guest_role, true)
    end
    @current_user_session = UserSession.find
    guest_role
  end

This is in the Ability.rb
Is that the correct way to go? Or should one use a before_filter in application_controller.rb so current_user is always set?
The problem is that SOMETIMES you don't need the current_user, and therefore it's uncessary to do a query for every request.

This way it only do it when the ability gets called.
:-) But I am trying to figure out wether this is the right approach?

load_and_authorize_resource doesn't work in namespaced model

LOG:
Processing Admin::ComentariosController#index (for 127.0.0.1 at 2009-12-14 11:04:05) [GET]
Parameters: {"action"=>"index", "controller"=>"admin/comentarios"}
Admin::Config Load (0.4ms) SELECT * FROM admin_configs LIMIT 1

NameError (uninitialized constant Comentario):
cancan (1.0.0) [v] lib/cancan/controller_resource.rb:10:in model_class' cancan (1.0.0) [v] lib/cancan/resource_authorization.rb:27:inauthorize_resource'
cancan (1.0.0) [v] lib/cancan/controller_additions.rb:103:in `authorize_resource'

Rendered rescues/_trace (42.5ms)
Rendered rescues/_request_and_response (1.2ms)
Rendering rescues/layout (internal_server_error)

CONTROLLER: Admin::ComentariosController
MODEL: Admin::Comentario

I guess issue is in resource_authorization.rb line 45..47:
def model_name
params[:controller].split('/').last.singularize
end

this do "admin/comentarios" became Comentario, but it isn't the real name "Admin::Comentario"

i don't have a patch yet, i'm just reporting.

!can? v.s. cannot?

Any reason why you opted to go with !can? rather than a cannot? method?

def cannot?(*args)
  !can?(*args)
end

??

Example application

Create a separate example application repository (cancan_example) which is a simple Rails application to demonstrate basic functionality of CanCan.

This application should also be fully tested showing how one would test with CanCan.

How can I use CanCan on a controller without a companion Model?

I have a calendar controller which builds and displays a calendar but there is no Calendar model. When I use "load_and_authorize_resource" on the controller it fails with a "uninitialized constant" error. I realize that I probably shouldn't use "load_and_authorize_resource" in this case but I don't really know how to get CanCan to secure the controller otherwise.

Am I missing something simple?
See: http://railscasts.com/episodes/192-authorization-with-cancan questions 42 & 44 for more detail and another viewpoint.

can? with additional parameters

I'm wondering why we cannot (or should not) pass in additional parameters to can?, eg
can? :manage, result, arbitrary_parameter1, arbitrary_parameter2

can :manage, Result do |action, result, arb_param1, arb_param2|
  arb_param1 == 'blue' || arb_param2 == 42
end

This seems like a more flexible version of Accessing Request Data because the arbitrary parameters don't have to be included in the ApplicationController code.

Gist example of CAN? with arbitrary parameters

cancan + cucumber documentation

I just got cancan running in my cucumber features, and thought it would be helpful to include a few notes in either the wiki or the readme for those unused to rescuing from features.

Specifically, "rescue_from CanCan::AccessDenied {}" does not work in cucumber unless you allow rails to rescue from exceptions. It took me quite a while to figure out what the problem was, first of all, and that cucumber allows you to tag individual scenarios with @allow-rescue. Do you have a preferred way of integrating cancan into features?

Testing documentation

I should add a bit of documentation about testing the CanCan ability model. One can use the can? method on this directly to check the abilities.

ability = Ability.new(some_user) # assuming I change to initialize instead of prepare method
assert ability.can?(:update, some_article)

Consider adding RSpec matchers for the can/cannot methods as well.

can and define abilities with attributes

Hi

i was trying to do something like this

can :manage, Comment do |comment|
      comment.try(:user) == user
end

so, an user only can manage its own comments, but then in a view i use

- if can? :update, Comment
      = link_to t('edit'), edit_request_comment_path(comment.commentable, comment)
  
(I'm using haml)

when i'm logged the link doesn't appear even is a current user's comment, so i'm a little confused about that...

and even worse, i can edit other user's comments inserting the corresponding URL in the browser without raise any exception

i'm using rails 2.3.5, i don't know what's happening here... i hope you can help me

greetings

(PS: excuse me if my english is not good enough, i hope that i made my point)

unexpected nil object : rails 3.beta + rspec 2.0.0.a9 + ruby 1.9.2-head + cancan 1.0.2

I'm not sure if it's an issue with rspec --pre or with cancan on 1.9.2. I figured I'd file it here, in case there's a workaround or fixes that can help the gems interoperate. When running my specs I get an unexpected nil object error.

This works in rails 2.3.5, rspec-rails 1.3.2, ruby 1.8.7-p249

1) User can update itself
 Failure/Error: a = Ability.new(u)
 You have a nil object when you didn't expect it!
 You might have expected an instance of ActiveRecord::Base.
 The error occurred while evaluating nil.[]
 # /Users/sax/.rvm/gems/ruby-1.9.2-head/gems/activesupport-3.0.0.beta/lib/active_support/core_ext/module/introspection.rb:9:in `parent_name'
 # /Users/sax/.rvm/gems/ruby-1.9.2-head/gems/activesupport-3.0.0.beta/lib/active_support/core_ext/module/introspection.rb:31:in `parent'
 # /Users/sax/.rvm/gems/ruby-1.9.2-head/gems/activesupport-3.0.0.beta/lib/active_support/dependencies.rb:102:in `const_missing'
 # /Users/sax/Projects/personal/dblf/spec/models/user_spec.rb:6:in `block (2 levels) in <top (required)>'

# ability.rb
class Ability
   include CanCan::Ability

   def initialize(user)
     user ||= User.new

     if user.role? :admin
       can :manage, :all
     else
       can :manage, User do |action, u|
         action != :destroy && u == user
       end
     end
     end
   end

# user_spec.rb
 require 'spec_helper'
   describe User do
     it "can update itself" do
       u = Factory(:user)
       puts u
       a = Ability.new(u)
       a.can?(:update, u).should be_true
     end
   end

Don't load resource if it is already loaded

The resource should not be loaded if the instance variable is already set. This way one can override the resource loading on specific actions using before filters.

class BooksController < ApplicationController
  before_filter :find_book_by_permalink, :only => :show
  load_and_authorize_resource
  
  private
  
  def find_book_by_permalink
    @book = Book.find_by_permalink!(params[:id)
  end
end

Here the resource will not be loaded for the show action since it has already been loaded. This could work for nesting too.

load_and_authorize_resource and mongo_mapper

Hello,
I have tried to load one active record model and many mongo mapper objects like this

load_and_authorize_resource :nested => [:contact, :buy, :criteria]
:contact -> activerecord
:buy, :criteria -> mongomapper

but only the :contact is loaded correctly, for the rest of the models I get instead of Buy object an Enumeration object.

Does anyone has played with cancan and mongo to give some hint?

Controller without model

Is there any way that it is possible to authorize a controller that does not have a model pair?

Can't use return inside of blocks defining abilities

If you try to write following ability:

can :manage, Project do |action, project|
    unless project
        return false
    end
    # ...
end

ActiveSupport throws the following error:

Cannot yield from a Proc type filter. The Proc must take two arguments and execute #call on the second argument.

I'm guess this is due to return in the block returning from the method in ActiveSupport since it's a Proc and not a lambda.

It would be great if return was supported inside of the can blocks.

use Ability#initialize instead of prepare

Use Ability#initialize instead of Ability#prepare. This way it follows Ruby's convention better and simplifies the current_ability method in the controller.

My original reason for not defaulting to initialize is because I didn't want it to interfere with an existing initialize method which one may be using. For example, if someone wants to turn the Ability class into an ActiveRecord object which is stored in the database they should be able to.

However this would still be possible with initialize. One would simply need to override the current_ability method in the controller and setup the Ability class the way they want.

authorization in Web Services

Do you think is a good idea to return status code 403 when something is not authorized? I think this should be specially important when using cancan for Web Services authorization. And in that case, what kind of response should be rendered to the Web Service (for example, on a .xml request)?

AccessDenied exception params

It would be quite convenient to have the denied controller & action names in the exception, so that it would be

  • possile to log what failed
  • let the user know what failed exactly
  • and apply proper return_to routing

While the first two points seem to be also addressed by #33 (http://github.com/ryanb/cancan/issues/#issue/33) -- albeit not fully, the thrid one remains entirely on my wish-list.

user.can?

Why there is no such method for user? I wrote a small mixin http://gist.github.com/305797. Please have a look at it. And now:

class User

  include CanCan::Authoritative

end

What do you think?

Custom objects in abilities

There are times one needs to set permission on something which doesn't have to do with a model or ruby class. Perhaps there's a page which displays general statistics about the site. One should be able to use a symbol or any other object when defining abilities, and then it will only match that same object.

can :read, :stats
can? :read, :stats # => true

If one passes a block to this, then no additional objects should be passed since we aren't dealign with a class here.

can :read, :stats do
  # ...
end

So in this case the block is a little pointless since you can define conditions in an "if" condition outside of this. The only real difference is the block gets executed on each check.

The :stats symbol could be any object, so in theory this could be used to match a specific record in the database. However, I recommend using the block for performance reasons.

can :manage, user.profile # don't do this
can(:manage, Profile) { |profile| user.profile == profile } # do this

This will lead to better performance since you are only loading the record object when performing the check and not on every request.

This should be mentioned in the documentation.

undefined method `cannot?'

I'm trying to authorize a controller that does not have a model. When I try to load the controller "/calendar/patient_calendar", I get the error:
undefined method `cannot?' for CalendarController:Class

Here's my controller:

class CalendarController < ApplicationController
  layout "users"
  before_filter(:only => :patient_calendar) { unauthorized! if cannot? :read, :patient_calendar }

  def patient_calendar
  end

  def public_calendar
  end

end

And here are my abilities:

class Ability
  include CanCan::Ability

  def initialize(user)

    if user.nil?
      can :create, [Message, Gwapp]
      can :read, :public_calendar
    elsif user.user_type == "admin"
      can :manage, :all
    end

  end
end

Any idea what's going on?

Finding records without find method.

The load_resource method should support finding database records by other columns than the id - eg. it should be possible to let it do MyModel.find_by_permalink!(params[:id]).

Authorizing namespaced

In my routes I have:

map.resources :articles   # the public actions for articles
map.namespace :admin do |admin|
  admin.resources :articles   # the administrative pages for articles
end

It appears that both of these pick up the abilities defined in:

can :read Article

I want to set different permissions for each of the resources. So, I may give a reviewer the right to view all articles in the public side, but may not want to let him view any articles in the admin section (perhaps I expose more sensitive data about the article in the admin section).

I tried obvious things like:

can :read, AdminArticle
can :read, Admin::Article
can :read, Admin/Article

All of those tries threw errors. Any idea how this might be able to be accomplished?

Nil passed to can block for :index object

I wish that 'can' sent something other than nil to the block when there is no instance variable. Example:

can :read, Article do |article|
  # If this is the :index action, article will be nil
  # but if it is the :show action, article will be @article instance
  article && article.user == user  # or alternately article.try(:user) == user
end

The problem I have is that the following block of code above returns unauthorized for the :index action because nil.user != user

So, I either have to split out the index/show actions (a little less DRY and more clutter) or do something like this:

  article.nil? || article.user == user

That block of code will authorize both the index & show action. However, I'm uncomfortable authorizing article.nil? as that could exist in the show action and not be what I want (as there are many reasons, not always good, that the article instance variable could be nil).

I wonder if it would be better to pass a Class object to the block for the index action. Then the block check would be:

  article.is_a?(Article) || article.user == user

Of course, you might still need to test for nil, but then your testing for an error condition not a valid condition.

I'm not set on my proposed solution, just uncomfortable with nil representing a valid authorized state.

Am I missing something, Ryan?

Controller without model - reloaded

Hey guys,

IMHO cancan is lacking one important functionality: Right now there seems to be no way to use cancan for controllers without corresponding models.
Possible scenarios in which this feature is necessary:

  • ReportsController
  • AdminController
  • .....and possibly some other scenarios I can't think of now.

This guy here: http://github.com/ryanb/cancan/issues/closed#issue/30
had the same question, but I couldnt find the "existing issue" he is talking about.

Any plans to implement this feature any time soon?

Alias Action overwriting

If I do something like

alias_action :home, :to => :read

it overwrites the previous aliases for :read

On lib/cancan/ability.rb:159 I think the arrays should be merged like:
aliased_actions[target] = args | (aliased_actions[target] ||= [])

Add authorize method to controller

Currently this is a very common pattern in the controller.

unauthorized! if cannot? :update, @project

This could be more concise with an authorize method.

authorize :update, @project

I'm on the fence with this one. It does make it cleaner but feels to go against the grain and simplicity of CanCan since it doesn't use the can? method. I'm also unsure of the exact name of the method. Calling it authorize would be ideal but it isn't consistent with unauthorized!.

I would love to hear feedback. What is your opinion?

Refactor Ability#can? method

The can? method is currently one of the most complex methods in CanCan. It could use some refactoring! Splitting it up into some private methods would probably be best.

Alternatively I could create a separate AbilityCheck object which would reduce the amount of parameter passing across methods, but I'm concerned about performance since the can? method is triggered frequently in many applications.

I wonder if I can move some of the checking logic to up-front inside the can call. I'll have to look into that as well.

controller param from route with custom controller option set

in rails 2.3.5 controller with a custom controller option in the routes, the controller has the format
:controller => "NameSpace::MyController" instead of :controller => "name_space/my_controller"

in routes
map.resource "name", :controller => "NameSpace::MyController"

this raises an exception in controller_resource in model_instance, because of resource_authorization on line 51 ...

NameError: `@NameSpace::MyController' is not allowed as an instance variable name in ancan-1.0.2/lib/cancan/controller_resource.rb:27

Should support load_resource for nested shallow resources

It appears that the :nested option only works for nested resources that aren't shallow. This is obviously a difficult problem to solve. It would be cool if it loaded the parent resource that the nested one belongs to and then checked the authorization.

implementing user groups?

Is there a way to implement permissions not just on the user account level but also on user groups?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.