Code Monkey home page Code Monkey logo

cancancan's Introduction

CanCanCan

Gem Version Github Actions badge Code Climate Badge

Developer guide | RDocs | Screencast 1 | Screencast 2

CanCanCan is an authorization library for Ruby and Ruby on Rails which restricts what resources a given user is allowed to access.

All permissions can be defined in one or multiple ability files and not duplicated across controllers, views, and database queries, keeping your permissions logic in one place for easy maintenance and testing.

It consists of two main parts:

  1. Authorizations library that allows you to define the rules to access different objects, and provides helpers to check for those permissions.

  2. Rails helpers to simplify the code in Rails Controllers by performing the loading and checking of permissions of models automatically and reduce duplicated code.

Our sponsors


Pennylane


Honeybadger


Goboony


Renuo AG

Do you want to sponsor CanCanCan and show your logo here? Check our Sponsors Page.

Head to our complete Developer Guide to learn how to use CanCanCan in details.

Installation

Add this to your Gemfile:

gem 'cancancan'

and run the bundle install command.

Define Abilities

User permissions are defined in an Ability class.

rails g cancan:ability

Here follows an example of rules defined to read a Post model.

class Ability
  include CanCan::Ability

  def initialize(user)
    can :read, Post, public: true

    return unless user.present?  # additional permissions for logged in users (they can read their own posts)
    can :read, Post, user: user

    return unless user.admin?  # additional permissions for administrators
    can :read, Post
  end
end

Check Abilities

The current user's permissions can then be checked using the can? and cannot? methods in views and controllers.

<% if can? :read, @post %>
  <%= link_to "View", @post %>
<% end %>

Fetching records

One of the key features of CanCanCan, compared to other authorization libraries, is the possibility to retrieve all the objects that the user is authorized to access. The following:

  @posts = Post.accessible_by(current_ability)

will use your rules to ensure that the user retrieves only a list of posts that can be read.

Controller helpers

The authorize! method in the controller will raise an exception if the user is not able to perform the given action.

def show
  @post = Post.find(params[:id])
  authorize! :read, @post
end

Setting this for every action can be tedious, therefore the load_and_authorize_resource method is provided to automatically authorize all actions in a RESTful style resource controller. It will use a before action to load the resource into an instance variable and authorize it for every action.

class PostsController < ApplicationController
  load_and_authorize_resource

  def show
    # @post is already loaded and authorized
  end

  def index
    # @posts is already loaded with all posts the user is authorized to read
  end
end

Documentation

Head to our complete Developer Guide to learn how to use CanCanCan in details.

Questions?

If you have any question or doubt regarding CanCanCan which you cannot find the solution to in the documentation, please open a question on Stackoverflow with tag cancancan

Bugs?

If you find a bug please add an issue on GitHub or fork the project and send a pull request.

Development

CanCanCan uses appraisals to test the code base against multiple versions of Rails, as well as the different model adapters.

When first developing, you need to run bundle install and then bundle exec appraisal install, to install the different sets.

You can then run all appraisal files (like CI does), with appraisal rake or just run a specific set DB='sqlite' bundle exec appraisal activerecord_5.2.2 rake.

If you'd like to run a specific set of tests within a specific file or folder you can use DB='sqlite' SPEC=path/to/file/or/folder bundle exec appraisal activerecord_5.2.2 rake.

If you use RubyMine, you can run RSpec tests by configuring the RSpec configuration template like this: rubymine_rspec.png

See the CONTRIBUTING for more information.

Special Thanks

Thanks to our Sponsors and to all the CanCanCan contributors. See the CHANGELOG for the full list.

cancancan's People

Contributors

alexwayfer avatar allcentury avatar amarshall avatar andhapp avatar bowsersenior avatar bryanrite avatar cefigueiredo avatar coorasse avatar craig1410 avatar eregon avatar funny-falcon avatar ghiculescu avatar jhawthorn avatar jondkinney avatar loremaster avatar lukasbischof avatar marshall-lee avatar mishina2228 avatar nashby avatar nhocki avatar ogerman avatar olleolleolle avatar phaedryx avatar phallguy avatar ryanb avatar s-mage avatar schmijos avatar scpike avatar senjai avatar stellard 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

cancancan's Issues

Adding a scope to load_and_authorize_resource

I know I can work around this fairly easily, I am just wondering if there's something that I missed that would allow me to add a scope in front of the find method of load_resource (and load_and_authorize_resource)

For example, if I were using friendly_id, I would want to add the friendly scope so it would end up looking something like Article.friendly.find(params[:id])

Authorize! on non model backed controllers

Hi all,

I've tried to use cancancan on my rails app and so far it's fine. However, once I tried to apply it to non model backed controllers with non restful resources, I run into several issues.

I use authorize_resource :class => false, which according to the documentation should be calling:

authorize!

on every action in the controller for me automatically.

unfortunately this is not the case and the authorization is only done if I call authorize on every single action in the controller.

Is there a way around this?

DOESN'T WORK:
class DashboardsController < ApplicationController
authorize_resource :class => false
def home
end

WORKS:
class DashboardsController < ApplicationController
authorize_resource :class => false
def home
authorize! :home, :dashboard
end

Add sequel adapter?

Im thinking if it's possible to add the adapter for Sequel:
ryanb/cancan#884
It looks like it passes all the tests. I dunno if it passes on this branch/fork.

Problem in CanCan::Rule.matches_conditions?

I found something wrong in https://github.com/CanCanCommunity/cancancan/blob/master/lib/cancan/rule.rb#L33, which not calling a block when:


    can :index, Subject do |subject|
      // Some condition
    end

Which always return true during can?(:index, Subject), even codition return false. After I change the method into:


    def matches_conditions?(action, subject, extra_args)
      if @match_all
        call_block_with_all(action, subject, extra_args)
      elsif @block && subject_class?(subject)
        @block.call(subject, *extra_args)
      elsif @conditions.kind_of?(Hash) && subject.class == Hash
        nested_subject_matches_conditions?(subject)
      elsif @conditions.kind_of?(Hash) && !subject_class?(subject)
        matches_conditions_hash?(subject)
      else
        # Don't stop at "cannot" definitions when there are conditions.
        conditions_empty? ? true : @base_behavior
      end
    end

Now, it return the right response for that ability.

Can you explain why your revert my wiki changes?

First you delete an entire article of me saying the contents of this article is better off inside the other wiki pages, so far so good (even if it'd have been better to edit the article with the edit proposal at top and let me move/delete it).

Then I do that and you still revert the changes to the other wiki articles without a reason:

https://github.com/CanCanCommunity/cancancan/wiki/Checking-Abilities/_compare/e9763a6b899a2fb203abeb1366bc2b3600029ea7...fdb694a184c4ab69e50d8d216af5c4d96686c66e

https://github.com/CanCanCommunity/cancancan/wiki/Checking-Abilities/_history

At least provide an explanation because that sends a wrong signal, something like "please don't contribute".

Defining ability on specific instance in MongoDB

Hi,
I can't figure out what is going on here. I am trying to define the ability for a user to update their own user details. I'm following the wiki.

This is my ability.rb:

class Ability
  include CanCan::Ability

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

    if user.admin?
      can :manage, User
    else
      can [:read, :update], User, id: '51524f53745448da24000003' # THIS DOESN'T WORK
      # can [:read, :update], User, id: user.id # THIS WORKS
    end

  end
end

When I define the id: as user.id instead of the Mongo id it works, which is really weird. Could it be something to do with Mongo?

I am using better_errors to inspect the CanCan::AccessDenied when I make a request to http://localhost:3001/users/51524f53745448da24000003/edit and this is what it shows:

Local Variables

action  :edit
subject #<User _id: 51524f53745448da24000003, created_at: 2013-03-27 01:45:55 UTC, updated_at: 2014-06-03 04:56:25 UTC, name: "Dave", email: "[email protected]", encrypted_password: "$2a$10$RDVcNWyxAOglTtFwPobPw.ZIFV5JL0zoart7r.ausx1VIlB2b7yeq", reset_password_token: nil, reset_password_sent_at: nil, remember_created_at: nil, sign_in_count: 18, current_sign_in_at: 2014-06-03 04:15:50 UTC, last_sign_in_at: 2014-05-28 22:55:02 UTC, current_sign_in_ip: "127.0.0.1", last_sign_in_ip: "127.0.0.1", authentication_token: "cpGcucqF5B1nNzKvYs3Q", role: "user", active: true, contributors: ["", "522d56d6745448a573000076", "522d572c745448a57300007d"], run_harvests: nil>
args         []
message     nil

Instance Variables

@rules  [#<CanCan::Rule:0x007f9df4970ee8 @conditions={:id=>"51524f53745448da24000003"}, @base_behavior=true, @expanded_actions=[:read, :index, :show, :update, :edit], @block=nil, @actions=[:read, :update], @match_all=false, @subjects=[User]>, #<CanCan::Rule:0x007f9df4970d30 @conditions={:id=>"522e8549745448bb70000003"}, @base_behavior=true, @expanded_actions=[:edit], @block=nil, @actions=[:edit], @match_all=false, @subjects=[Source]>]

Notice that conditions.id of the User rule has the correct id. However, the local variable args is an empty array, surely this should be id: '51524f53745448da24000003'?

I realise that hard-coding the id is really bad, but I'm trying to understand why it's not working rather than use this in the real world.

Note, that I used to be using cancan, when I couldn't get past this issue I tried using cancancan but have exactly the same issue.

Thanks,
Dave

load_and_authorize_resource through: :current_user, singleton: true

For the sake of an example I'm using a singleton profile for the current user

require 'spec_helper'

class Profile < Struct.new(:user); end

class ProfilesController < ApplicationController
  load_and_authorize_resource through: :current_user, singleton: true
end

describe ProfilesController do
  login_user # macro which sets :current_user for devise
  before do
    @routes.draw do
      resource :profile
    end
  end

  describe 'GET new' do
    it 'assigns a new profile to @profile' do
      get :new
      expect(assigns :profile).to be_a Profile
    end
  end
end

results in

ProfilesController GET new assigns a new profile to @profile
  Failure/Error: get :new
  NoMethodError:
    undefined method `current_user=' for #<struct Profile user={}>

https://github.com/CanCanCommunity/cancancan/blob/master/lib/cancan/controller_resource.rb#L90 tries to use profile.current_user=, but it isn't defined on the profile model.

Is there an option to override the parent_name to user

Joined tables from namespaces break ability conditions accessible_by

I have two tables that are joined - both tables are name-spaced.

When I define an ability that sets up a nested condition - the accessible_by method fails with this error (uninitialized constant):

1) CanCan::ModelAdapters::ActiveRecordAdapter fetches all namespace::table_x when one is related by table_y
 Failure/Error: expect(Namespace::TableX.accessible_by(ability)).to eq([table_x])
 NameError:
   uninitialized constant TableZ
 # ./lib/cancan/model_adapters/active_record_adapter.rb:71:in `block in tableized_conditions'
 # ./lib/cancan/model_adapters/active_record_adapter.rb:67:in `each'
 # ./lib/cancan/model_adapters/active_record_adapter.rb:67:in `inject'
 # ./lib/cancan/model_adapters/active_record_adapter.rb:67:in `tableized_conditions'
 # ./lib/cancan/model_adapters/active_record_adapter.rb:57:in `conditions'
 # ./lib/cancan/model_adapters/active_record_adapter.rb:105:in `database_records'
 # ./lib/cancan/model_additions.rb:23:in `accessible_by'
 # ./spec/cancan/model_adapters/active_record_adapter_spec.rb:98:in `block (2 levels) in <top (required)>'

I have a proposed fix - but not 100% sure if it is the "right" way to fix things". I'll be submitting a pull request that includes a test that would fail prior to the fix and the fix.

Problem with custom actions

Suppose I have the following:

# routes.rb

resources :plans do
  collection do
    get 'requested'
    get 'pending'
  end
end

# PlansController

load_and_authorize_resource 

def requested
  ...
  render :index
end

def pending
  ...
  render :index
end

# Ability

can :requested, Plan, dept_id: 304
can :pending, Plan, status: 'sent'

Where 'request' and 'pending' are two collection actions which should list the plans based on the respective filter. Problem is, if I don't add:

can :index, Plan

I get nothing. If I add this, it will show everything in both actions. In this cases, it seems that CanCan locks the actions, but is ignoring the conditions.

Any idea on how to solve this? Am I doing it wrong or not understanding something?

Thanks in advance.

How to authorize index only for users that can update other users?

Hello,

I want it so that my index action is only accessible by those who can update other users (other users can only update themselves).

This is what I tried:

# ability
if user.name == "A"
  can :read, User, id: user.id      # User A can read itself
elsif user.name == "B"
  can :read, User, id: user.id      # User B can read itself
  can :update, User, id: user.id    # User B can update itself
elsif user.name == "C"
  can :read, User                   # User C can read everyone
  can :update, User                 # User C can update everyone
end

# controller
def index
  authorize! :update, User
  respond_with @users
end

The problem is that both user B & C can list the index action, but I want only the user C to be able to do it. What did I do wrong? Am I supposed to do User.all.each{ |u| authorize!(:update, u) } instead?

Additional infos: ryanb/cancan#615

Missing from cause SQL exception when plucking columns

After switching from CanCan, I noticed (Rails 3.2.17) that my queries of the below were failing:

SomeModel.where(admin_id: Admin.accessible_by(current_ability, :read))

Would throw an exception of the form:

ActiveRecord::StatementInvalid: PG::UndefinedTable: ERROR: missing FROM-clause entry for table "customers"
LINE 1: ..." ON "roles"."id" = "users_roles"."role_id" WHERE "customers...
^
: SELECT "users"."id" FROM "users" INNER JOIN "users_roles" ON "users_roles"."user_id" = "users"."id" INNER JOIN "roles" ON "roles"."id" = "users_roles"."role_id" WHERE "customers"."id" IN (1) AND (((roles.name = 'admin') AND (roles.resource_type IS NULL) AND (roles.resource_id IS NULL)))

Admin is using Rolify to generate the admin role in the query above and the query is scoped by the current customer_id as defined by the ability:

can [:read, :update], Admin, customers: {id: user.customer_ids}

The query itself actually succeeds however and returns records, and as a workaround I have been able to do:

SomeModel.where(admin_id: Admin.accessible_by(current_ability, :read).map(&:id))

But it obviously has performance implications opposed to using raw SQL.

Reverting to CanCan 1.6.10 seems to work as well.

Cannot compile on windows due to KGIO dependency

I tried to install cancancan on my windows machine and when I tried to run bundle install, I got an error when kgio-2.9.2 tried to install. After doing some research, I found that KGIO doesn't work on windows.

Does cancancan depend on KGIO? I didn't see it in the dependencies. If not, is there something strange going on?

Thanks!

Alex

Need appraisal files for Rails 3.1+

Unfortunately supermodel is locked at ~> 3.0.0 so I can't do it (re: #13)

Need to pull supermodel out, probably using a proper dummy rails app, and convert the spec_helper to using the dummy app rather than supermodel and with_model.

This will doubly allow us to do some capybara integration tests for better testing.

Parameter authorization

Is there are some work planed on parameter authorization feature?

Article I found (http://hawkins.io/2012/07/parameter_authorization_in_rails_apis/) helps to deal with that issue, but I would like to have this embedded in the cancancan as a part of it's DSL.

I know that the original cancan have some functionality of that feature in the branch 2.0.

PS. https://github.com/CanCanCommunity/cancancan#strong-parameters is great, but I guess it should be moved to the Ability class, so it will be isolated from the controller, and incapsulated in one place, for easier overview of permissions and consistency between actions and controllers.

can :manage, @entity vs can :manage, Entity, id: @entity.id

Hi,

First, i've just found out this fork of cancan. AWESOME ! So thanks for keeping cancan alive.
Now on to the issue.

I've tried defining two abilities as follow:

can :manage, Entity, id: @entity.id
can :manage, @entity

They seem to be identical in what they do but they actually aren't. I see the difference when i do:

Entity.accessible_by(current_ability)

Using the first definition, i get a list containing my entity.
using the second one i get an empty list (and the executed SQL has that strange 't'='f' condition in it)

It would be great if both those abilities worked the same way. I like using Entity.accessible_by as a generic way to get my entities. Depending on the user, the entity may not always be the same (i'm using a polymorphic association) so the above statements aren't actually the same in my case (@entity can either be a TypeOneEntity or a TypeTwoEntity).

Thanks

Hash conditions containing symbols problem

Hello,

I found this blog post that explain the problem I'm having:

http://www.tigraine.at/2014/03/13/cancan-beware-of-symbol-conditions

Basically, if you look at the following rules:

can :manage, Item, user: { role: :admin }  #1
can :manage, Item, user: { role: 'admin' } #2

With both rules Item.accessible_by(current_ability) will return the correct results. But only the 2nd rule will work with can? :manage, Item.accessible_by(current_ability).first

This is because the symbols are not translated to a string the usual way rails does.

Not sure if really a bug or a not.

[EDIT] I believe this is a bug, just because of the unexpected behavior.

Separate ActiveRecord 3 & 4 Model Adapters

There are too many differences in the way AR 3 and 4 work and the active_record_model_adapter code is too complex already. Lets extract out a separate AR 4 and AR 3 adapter (perhaps inheriting from the same parent).

This does, to an extent still rely on #14 and getting some proper testing done, but work can begin on both.

Issues that deal with AR 4 specific logic will be useful for the AR4 adapter:
#26
#39

Overriding abilities

I'm in the process of migrating from CanCan to CanCanCan and have run into an issue. I'm not sure if it was always resident in CanCan and my tests were faulty, or introduced in CanCanCan. Regardless, its an open question.

I have an ability file that looks something like this:

class Ability
  include CanCan::Ability
  def initialize(user)
  @user = user
    send(user.role)
  end

  def employee
    can [:update], User, id: @user.id
    ...other universal rules
  end

  def admin
    employee
    can [:update], User, company_id: @user.company_id
  end
end

My expectation would be that the :update rule is rewritten for the higher role, but its not. I have to do the following:

  def admin
    employee
    cannot[:update], User
    can [:update], User, company_id: @user.company_id
  end

Which is pretty gross.
Thoughts?

"can :manage, Model, id: 23" allows :new action when it shouldn't

Hello,

If I have the following ability.

can :manage, Model, id: 23

With the wollowing controller:

class ModelsController < ApplicationController
  load_and_authorize_resource
  respond_to :html

  def new
    respond_with @model
  end

Then I can happily naviguate to new_models_path (/models/new), but I shouldn't be able to do that., because I only have the rights to manage a single entity. If I change :manage for [:read, :update, :destroy] then it works as expected.

I found out that inside new, @model is set to the model I have right access to... this looks like a bug too.

List users which can do an action

Hi Cancancan Community,
I don't if it's better to put this question/bug/issue/request here on Stackoverflow but the problem is really simple:
how to obtain a list of users which "can do an action"? Is it possibile with the current version?
If not would be great to be able to do that

load_and_authorize_resource and new with params causes ActiveModel::ForbiddenAttributesError

I create example app: https://github.com/znz/rails4-cancancan-example

In the app, http://localhost:3000/comments/new?comment%5Bpost_id%5D=1 causes ActiveModel::ForbiddenAttributesError.

In lib/cancan/controller_resource.rb,
resource_params called from build_resource returns params['comment'] directly instead of comment_params (includes permit) because param_actions does not include :new.

For now, I will use post_id=1 instead of comment[post_id]=1 and set comment.post_id = params[:post_id] in CommentController#new.

SQL error when two rules refer to the :read action with hash parameters

Hello,

When you have the following:

# Models
class Item
  has_many :permissions, as: :subject
end
class Permission
  belongs_to :user
  belongs_to :subject, polymorphic: true
  # db field 'action'
end

# Ability
alias_action :read, :update, :destroy, to: :modify
can :read,   Item, permissions: { action: 'read',   user_id: user.id }
can :modify, Item, permissions: { action: 'modify', user_id: user.id }

Trying to do Item.accessible_by(current_ability) fails with the following error:

Mysql2::Error: Unknown column 'permissions.action' in 'where clause': SELECT `items`.* FROM `items`  WHERE ((`permissions`.`action` = 'modify' AND `permissions`.`user_id` = 14) OR (`permissions`.`action` = 'read' AND `permissions`.`user_id` = 14))

To fix it, you can do one of the following:

  • Remove the :read action from the :modify alias
  • Remove the can :read, ... rule
  • Use can [:read, :update, :destroy], ... instead of can :modify

This only seem to happen with :read, I couldn't reproduce with :update.

See #74 for more informations.

Rails 4 support

In Rails 4 there is a problem using load_and_authorize_resource, it throws a ActiveModel::ForbiddenAttributesError.

Using accessible_by with overriding roles

I am having trouble using cancancan to select records based on abilities.

My ability.rb file looks like this:

    can :read, Business if user.admin?

    can :read, Business, Business.user_related(user) do
      Business.user_related(user).any?
    end

My controller tries this:

@businesses = Business.accessible_by(current_ability, :read)

If I comment out the top rule, everything seems to work. That is, I can load businesses produced by the Business.user_related scope. But if I include the top rule I get the error: "Unable to merge an Active Record scope with other conditions. Instead use a hash or SQL for read Business ability."

If the user is an admin, cancancan doesn't need to consult the database at all - they have access to all businesses. How can I express this in ability.rb?

Problem detecting hashes in extract_subjects

In ability.rb, line 288 the function keys is called on the subject to figure out whether it's a hash.

In my app I have a model called Key and another one that has_many :keys. This causes cancan to fail there with undefined method key?.

Maybe cancan should check the subject's class rather than whether the method exists?

Bug with nested resource when 'user_id' is not submitted

Hello,

Backporting issue from ryanb/cancan#774

In the following configuration:

class ItemsController < ApplicationController
  load_resource :user
  load_and_authorize_resource :item, :through => :user

  def create
    @item.save
  end
end

ItemsController#create is called through a HTTP POST to a classic route like /users/4/items.

If we submit params like { :user_id => 4, :title => 'test' } to #create, everything works fine.

Now if we submit params like { :title => 'test' } to #create, then what happen is that the created items belongs to the currently logged user.

This is because in ControllerResource#build_resource, when #assign_attributes calls #initial_attributes the latter ends up assigning 'user_id' the nested resource.

Ironically, without the #assign_attributes call everything would be working fine as it'd build the resource through its parent and thus user_id would be correctly set.

I know that theorically I'd be sending user_id to build this resource, but I thought cancan's load_resource :through would do the equivalent of @user.items.build(params[:item]) which would work, but apparently that's not the case.

"user" parameter is nil

I am using Rails 4.0.1 and ruby 2.1.1. I am trying to integrate cancan with rails_admin. My application_controller.rb looks like this

helper_method :current_user

private

def current_user
  @current_user ||= User.find_by(email: session[:user_id]) if session[:user_id]
end 

My current_user helper method is working fine from rest of the application. My ability.rb looks like this

class Ablity
  include CanCan::Ability

   def initialize(user)
     if user
       can :access, :rails_admin
     end
   end
end

Control is not going inside the if condition at all, which means the "user" parameter is "nil". When I try to access rails_admin I get a CanCan::AccessDenied exception. Where am I going wrong?

Change references to CanCan class to CanCanCan

now that this is a gem called cancancan it seems like the documentation is either incorrect or confusing in several locations

there should be at least a short transition guide, going from cancan to cancancan

for example, do you need to change the include

include CanCan::Ability

to

include CanCanCan::Ability

because as of writing, it said CanCan::Ability but this seems incorrect.

param_actions should include :new?

When load_resource is invoked by a new action it initialises the object with parameters, as cancan always did. At the moment this doesn't work because the params_method machinery - for which we thank you very much - is only invoked for actions that are in param_actions, and :new is not one of them.

Initialising a new object without populating it from params would probably break a lot of code so I suggest that we apply the strong_parameters mechanism on new as well.

[BUG] `undefined method `define' for RSpec::Matchers:Module`

Upon this line in my spec_helper:

require 'cancan/matchers'

I get this:

/Users/jaiken/.rvm/gems/ruby-2.0.0-p247@pws/gems/cancancan-1.7.0/lib/cancan/matchers.rb:2:in `<top (required)>': undefined method `define' for RSpec::Matchers:Module (NoMethodError)
    from /Users/jaiken/.rvm/gems/ruby-2.0.0-p247@pws/gems/activesupport-3.2.17/lib/active_support/dependencies.rb:251:in `require'
    from /Users/jaiken/.rvm/gems/ruby-2.0.0-p247@pws/gems/activesupport-3.2.17/lib/active_support/dependencies.rb:251:in `block in require'
    from /Users/jaiken/.rvm/gems/ruby-2.0.0-p247@pws/gems/activesupport-3.2.17/lib/active_support/dependencies.rb:236:in `load_dependency'
    from /Users/jaiken/.rvm/gems/ruby-2.0.0-p247@pws/gems/activesupport-3.2.17/lib/active_support/dependencies.rb:251:in `require'
    from /Users/jaiken/projects/phrg/pws/spec/spec_helper.rb:12:in `<top (required)>'
    from /Users/jaiken/projects/phrg/pws/spec/models/agent_originator_spec.rb:1:in `require'
    from /Users/jaiken/projects/phrg/pws/spec/models/agent_originator_spec.rb:1:in `<top (required)>'
    from /Users/jaiken/.rvm/gems/ruby-2.0.0-p247@pws/gems/rspec-core-2.14.8/lib/rspec/core/configuration.rb:896:in `load'
    from /Users/jaiken/.rvm/gems/ruby-2.0.0-p247@pws/gems/rspec-core-2.14.8/lib/rspec/core/configuration.rb:896:in `block in load_spec_files'
    from /Users/jaiken/.rvm/gems/ruby-2.0.0-p247@pws/gems/rspec-core-2.14.8/lib/rspec/core/configuration.rb:896:in `each'
    from /Users/jaiken/.rvm/gems/ruby-2.0.0-p247@pws/gems/rspec-core-2.14.8/lib/rspec/core/configuration.rb:896:in `load_spec_files'
    from /Users/jaiken/.rvm/gems/ruby-2.0.0-p247@pws/gems/rspec-core-2.14.8/lib/rspec/core/command_line.rb:22:in `run'
    from /Users/jaiken/.rvm/gems/ruby-2.0.0-p247@pws/gems/rspec-core-2.14.8/lib/rspec/core/runner.rb:80:in `run'
    from /Users/jaiken/.rvm/gems/ruby-2.0.0-p247@pws/gems/rspec-core-2.14.8/lib/rspec/core/runner.rb:17:in `block in autorun'

cancancan 1.70
Rails 3.2.17
Rspec 2.14.1

Undefined method `class_name` for nil:NilClass within ability.rb

I am using load_and_authorise_resource for my BoomsController and my BlastsController.

Blasts have many booms, Booms have many keywords.

Since the addition of the ability for Blast, I cannot access the index page for blasts. I get the error:

undefined method `class_name' for nil:NilClass

lib/cancan/model_adapters/active_record_adapter.rb
def tableized_conditions(conditions, model_class = @model_class)
return conditions unless conditions.kind_of? Hash
conditions.inject({}) do |result_hash, (name, value)|
if value.kind_of? Hash
value = value.dup
association_class = model_class.reflect_on_association(name).class_name.constantize
nested = value.inject({}) do |nested,(k,v)|
if v.kind_of? Hash
value.delete(k)
nested[k] = v
else

      can :create, Boom
      can :manage, Boom, :keyword => { :organization => { :id => Organization.with_role(:operator, user).pluck(:id) } }

      can :create, Blast
      can :manage, Blast, :boom => { :keyword => { :organization => { :id => Organization.with_role(:operator, user).pluck(:id) } } }

Upgrading from normal cancan

Hi,
Quick question. I started using cancan (Gem lock says v1.6) with my own Rails 4 app and set all the abilities up. I'm getting this error:

The can? and cannot? call cannot be used with a raw sql 'can' definition. The checking code cannot be determined for :new

I'm pretty sure that has to do with the use of Rails 4.

Q1 : Is it a strong parameter issue ?
Q2: How to upgrade to cancancan from cancan 1.6. Does it suffice to remove the gem/replace it with the cancancan or do i have to delete some initializers too ?

Thanks in advance,

Nested attributes problem

Hello!
I'm trying to use CanCan in my new project. Let's say we have two models - Event and Band. Event has many Bands and it's possible to create a new ones using nested_attributes and fields_for forms.

Everything works great when cancan is turned off. However, if i'll enable it for events_controller and add a new band using nested_fields, i'm getting:

Couldn't find Band with id=0

which is rised by @event = Event.new(event_params) line in create method. It happens only when i'm trying to create a new event. When event exists and i'm creating a band in event edit form - no exception is thrown.

My ability.rb file looks like that:

class Ability
  include CanCan::Ability

  def initialize(user)
    user ||= User.new # guest user (not logged in)

    # Guests
    can :read, :all

# Members
    unless user.new_record?
      can [:edit, :update, :new, :create], Event, user_id: user.id
      can [:edit, :update, :new, :create], Band
    end
  end
end

Have you any idea what am i doing wrong here? Thanks in advance.

load_and_authorize through when no index ability on parent fails

#ability
can :show, Parent
can :index, Child
#controller
load_and_authorize_resource :parent
load_and_authorize_resource :child, :through => :parent

def index
end

The index action fails on not having the ability to :index Parent.
Access denied on index {#<Parent ..

Stepping through the code, Parent is authorized on :show first which is correct.

When authorizing Child:

    def authorize_resource
      unless skip?(:authorize)
        @controller.authorize!(authorization_action, resource_instance || resource_class_with_parent)
      end
    end

resource_instance is nil and resource_class_with_parent returns a hash:

subject_hash =  resource_class_with_parent
=> {<#Parent instance..> => Child(class) }

Child is then ignored completely when matching the rule

    def nested_subject_matches_conditions?(subject_hash)
      parent, child = subject_hash.first
      matches_conditions_hash?(parent, @conditions[parent.class.name.downcase.to_sym] || {})
    end

It would appear this subject notation has to do with nesting and is no longer being used. resource_class_with_parent is not used anywhere else.

defining authorize_resource to return the resource class instead solves this issue.

    def authorize_resource
      unless skip?(:authorize)
        @controller.authorize!(authorization_action, resource_instance || resource_class)
      end
    end

The tests do not indicate an reason why this should not be the case all of the time. Is this behaviour intended?

accessible_by Ignores Explicit ActiveRecord select()

I'm using cancancan to get an index of objects from my database. In this case, each object has a very large text field (in some cases >1MB) that I don't need for the index option. I have found that this means that doing the index for some customers right now takes >7s!

Since all I need is a selection of info about each item in the database (e.g. title), I wanted to select only e.g. the title and id. However, since cancancan uses includes (not joins) internally, the select is completely ignored and there's no way to NOT select that large text field.

May I propose that, when using accessible_by, cancancan should use joins instead such that those using the gem can ignore large fields that may slow things down?

I believe the relevant line is here: https://github.com/CanCanCommunity/cancancan/blob/develop/lib/cancan/model_adapters/active_record_adapter.rb#L104

I'm happy to provide a PR if I can get a hint about how I might know at that point of the code how we're doing an accessible_by instead of a normal permissions check.

Extract Adapter Specific Code

In lib/cancan/rule.rb:114, there is ActiveRecord specific code which should really be in a adapter. The context of the code is too complex to refactor it into the adapter though... so that whole method needs to be broken down as well.

As discovered in #13 ... I guarded it so that datamapper and mongoid would work as a temporary solution.

authorize_resource with multiple classes(Models) ?

Rails 4 + Cancan

ability.rb
if user.is_sys_admin?
can :manage, [MdmArea, MdmCity, MdmCountry, MdmState] #Model Array
end

mdm_controller.rb

authorize_resource ['MdmCountry', 'MdmState', 'MdmCity', 'MdmArea'] # Not working

Please solve this ? or any solution
Thanks

Compatibility with disable_implicit_join_references

Hi,

It seems that using Entity.accessible_by(current_ability) with a nested condition like so: {group: { familly_id: 3 }} gets me the following deprecation warning:

DEPRECATION WARNING: It looks like you are eager loading table(s) (one of: entities, groups) that are referenced in a string SQL snippet. For example:

    Post.includes(:comments).where("comments.title = 'foo'")

Currently, Active Record recognizes the table in the string, and knows to JOIN the comments table to the query, rather than loading comments in a separate query. However, doing this without writing a full-blown SQL parser is inherently flawed. Since we don't want to write an SQL parser, we are removing this functionality. From now on, you must explicitly tell Active Record when you are referencing a table from a string:

    Post.includes(:comments).where("comments.title = 'foo'").references(:comments)

If you don't rely on implicit join references you can disable the feature entirely by setting `config.active_record.disable_implicit_join_references = true`. (called from block in <module:IRB> at /usr/local/rvm/rubies/ruby-2.1.0/lib/ruby/2.1.0/irb/inspector.rb:122)

So i tried activating the above config and well, as expected, the requests fails because of a missing FROM-clause.

I tried using a scope but it doesn't seem to be compatible with accessible_by

Unpermitted parameters: roles (Role Based Authorization) - Rails 4 - Ruby 2.1

I using this guide (https://github.com/CanCanCommunity/cancancan/wiki/Role-Based-Authorization) to using a bitmask (I added a column named "roles_mask" to user model).

I have this files involved:

  1. user.rb (https://gist.github.com/geoom/9340643)
  2. new.html.erb (https://gist.github.com/geoom/9369397)

I folowed word by word of this guide except the lines that I wrote for indicate that roles is a accessible attribute:

class ApplicationController < ActionController::Base
  protect_from_forgery with: :exception
  before_filter :configure_permitted_parameters, if: :devise_controller?

  def configure_permitted_parameters
    devise_parameter_sanitizer.for(:sign_up) { |u| u.permit(:email, :password, :password_confirmation, :roles) }
  end
end

When create a user, all fields are captured except :roles_mask =/, I don't understand why roles field is not captured. I think there's something that I don't achieve to see. I got a message "Unpermitted parameters: roles" in trace.

screenshot from 2014-03-05 10 22 30

Undefined method `accessible_by' for Model:Class

@models = Model.accessible_by(current_ability) gives me:
"NoMethodError at /models".

What am I doing wrong?

I am on Linux 3.2.0-60-generic #91-Ubuntu with ruby 2.1.1p76 (2014-02-24 revision 45161) [x86_64-linux] , Rails 4.0.3 and 'mongoid', :github=>"mongoid/mongoid".

This is the Gemfile:
source 'https://rubygems.org'
gem 'rails', '4.0.3'
gem 'sass-rails', '> 4.0.0'
gem 'uglifier', '>= 1.3.0'
gem 'coffee-rails', '
> 4.0.0'
gem 'jquery-rails'
gem 'jquery-ui-rails'
gem 'turbolinks'
gem 'jbuilder', '> 1.2'
gem 'bootstrap-sass'
gem 'cancancan', '
> 1.7'
gem 'country_select'
gem 'devise'
gem 'mongoid', :github=>"mongoid/mongoid"
gem 'figaro'
gem 'rolify'
gem 'simple_form'
gem "kaminari"
group :development do
gem 'better_errors'
gem 'binding_of_caller', :platforms=>[:mri_19, :mri_20, :rbx]
gem 'quiet_assets'
gem 'rails_layout'
end
group :production do
gem 'unicorn'
end
group :doc do

bundle exec rake doc:rails generates the API under doc/api.

gem 'sdoc', require: false
end
gem 'debugger', group: [:development, :test]

Need help.

Need help with complex index action.

Hi All,
I posted a few days ago and the comments helped me move forward on this project. Seems like everything is working but since Index uses a block (I think that's what I got from this) I might need some fancier filtering code.
I've read these posts but only went so far to conclude that I need to potentially add sql statements into the blocks:
ryanb/cancan#209 (comment)
ryanb/cancan@9d91545
https://github.com/ryanb/cancan/wiki/authorizing-controller-actions
http://stackoverflow.com/questions/16470869/cancan-not-filtering-products-in-index

My problem is filtering out index's for people that have PageRights that let them edit, are owners, or if the page is public. I'd like to do this filtering in the controller before the view.

Anyway a user can have an :editor, :admin, :guest as a role
A Page can be owned by a user, and has a public flag (aka guests can read it)
Only admin/editors are allowed to create pages/edit etc..
So for this I created a PageRights model that belongs to Page and User and has a right in it that I created aliases for index.

Code follows:
PageController

  # before_filter :authenticate_user!, only: [:new, :create, :edit, :update, :destroy]
  before_filter :new_page, only: [:create]
  before_filter :find_page, only: [:edit, :update, :destroy]
  load_and_authorize_resource #:only => [:new, :create, :edit, :update, :destroy]

  def index
    @pages = Page.all
  end

Page

class Page < ActiveRecord::Base
  extend FriendlyId
  belongs_to :use
  has_many :page_rights
  has_many :users, through: :page_rights

  friendly_id :title, use: :slugged
  validates_presence_of :title, :body, :slug
  acts_as_taggable
  has_paper_trail

  validates_inclusion_of :public_flag, :in => [true, false]
end

User

require 'role_model'
require 'typus/orm/active_record/instance_methods'

class User < ActiveRecord::Base
  before_save :default_role
  has_many :page_rights
  has_many :pages, through: :page_rights
  has_many :pages
  # Include default devise modules. Others available are:
  # :confirmable, :lockable, :timeoutable and :omniauthable
  devise :database_authenticatable, :registerable,
         :recoverable, :rememberable, :trackable, :validatable,
         :omniauthable
  include RoleModel

  roles_attribute :roles_mask

  roles :admin, :editor, :super_admin

  include Typus::Orm::ActiveRecord::InstanceMethods

    # If DeviseUser#locale is not found, we will use the default one.
  def locale
    ::I18n.locale
  end

  def role
    Typus.master_role
  end

  private

    def default_role
      self.roles << :editor
    end
end

Ability

class Ability
  include CanCan::Ability

  def initialize(user)
    alias_action :show, :index, :update, :edit, :to => :edit_page #page_right allows users to edit_page
    alias_action :show, :index, :update, :edit, :new, :destroy, :to => :crud_page
    user ||= User.new # guest user (not logged in)

    if user.has_role? :super_admin
      can :manage, :all
    elsif user.has_role? :admin
      can :manage, Page
    else
      can :read, Page do |page|
        page.public_flag
      end

      if user.has_role? :editor
        can :manage, Page, :user_id => user.id
        can :create, Page
        can :edit_page, Page do |page|
          check_page_rights(user, page, 'edit_page')
        end
        can :crud_page, Page do |page|
          check_page_rights(user, page, 'crud_page')
        end
      end
    end

  end

  def check_page_rights(user, page, current_right)
    common_page_right = page.page_rights && user.page_rights
    if common_page_right.present? && common_page_right.first.right.present?
      common_page_right.first.right == current_right
    end
  end

end

I'm stuck for this so any help is appreciated. I had an SO question a while back to no avail. I realize this is less then an issue and more of a Q so if there is a better place for this let me know.

accessible_by Produces Incorrect Query For Self Referential Models

A Company has many Customer's and many Employee's. Company's and Employee's belong to User's so they can sign into our system. An Employee should be able to read a Company's Employee's and Customer's.

I expect Employee.accessible_by(Ability.new(user)).to_sql to produce the same SQL structure as Customer.accessible_by(Ability.new(user)).to_sql, however, it is missing the joins. It should reference the Company's collection and then refer back to the Employee's collection, just like the Customer query does.

class User < ActiveRecord::Base
  has_many :companies
  has_many :customers
  has_many :employees
end

class Company < ActiveRecord::Base
  has_many :customers
  has_many :employees
  belongs_to :user
end

class Customer < ActiveRecord::Base
  belongs_to :company
  belongs_to :user
end

class Employee < ActiveRecord::Base
  belongs_to :company
  belongs_to :user
end

class Ability
  include CanCan::Ability

  def initialize(user)
    can :read, Customer, company: { employees: { user_id: user_id } }
    can :read, Employee, company: { employees: { user_id: user_id } }
  end
end

> Employee.accessible_by(Ability.new(user)).to_sql
=> "SELECT `employees`.* FROM `employees`  WHERE `employees`.`user_id` = 16"

> Customer.accessible_by(Ability.new(user)).to_sql
=> "SELECT `customers`.`id` AS t0_r0, `customers`.`company_id` AS t0_r1, `customers`.`user_id` 
AS t0_r2, `companies`.`id` AS t1_r0, `companies`.`user_id` AS t1_r1, `employees`.`id` AS t2_r0, 
`employees`.`company_id` AS t2_r1, `employees`.`permissions` AS t2_r2, `employees`.`user_id` AS
 t2_r3 FROM `customers` LEFT OUTER JOIN `companies` ON `companies`.`id` = 
`customers`.`company_id` LEFT OUTER JOIN `employees` ON `employees`.`company_id` = 
`companies`.`id` WHERE `employees`.`user_id` = 16"

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.