cancan icon indicating copy to clipboard operation
cancan copied to clipboard

Combining conditionless & sql/block rules

Open hungrything opened this issue 12 years ago • 6 comments

cannot :read, Foo
can :read, Foo, ["bar_id = ?", user.bar_id] do |foo|
  foo.bar_id == user.bar_id
end

yields undefined method '%' for ["bar_id = ?", 2]

while

cannot :read, Foo, "true" do |foo|
  true
end
can :read, Foo, ["bar_id = ?", user.bar_id] do |foo|
  foo.bar_id == user.bar_id
end

succeeds.

cancan 1.6.8, activerecord 3.2.6

hungrything avatar Jul 11 '12 19:07 hungrything

I have a similar bug with 1.6.8 and 3.2.6 (see #704). Can you try downgrade to 1.6.7 and check it again? 1.6.7 works for me.

Wolfgang

swobspace avatar Jul 31 '12 05:07 swobspace

Passing conditions with a block is not a good way to declare rules in cancan. What do you really expect from it?

module CanCan
  # This class is used internally and should only be called through Ability.
  # it holds the information about a "can" call made on Ability and provides
  # helpful methods to determine permission checking and conditions hash generation.
  class Rule # :nodoc:

    ...

    def initialize(base_behavior, action, subject, conditions, block)
      raise Error, "You are not able to supply a block with a hash of conditions in #{action} #{subject} ability. Use either one." if conditions.kind_of?(Hash) && !block.nil?
      ...
    end

fillman avatar Aug 04 '12 00:08 fillman

@fillman I'm not sure what you mean. Your code quote is about hash conditions with a block, which is a stated limitation of cancan. Thus we can only pass sql conditions with a block. This has a clear intended use case: Fetching a set of readable objects for display, then determining other allowed actions per item, while iterating. I ran into this using a fairly plain rails_admin setup.

@swobspace yup, 1.6.7 works. could be something that changed around the truthiness sql, 't'='t'. I just use true in my workaround... hmm...

hungrything avatar Aug 07 '12 06:08 hungrything

I'm running into the same issue currently. I have:

can :read, Location
can :manage, Location do |location|
   user.role? :curator, location.city
end

The problem seems to be with this controler_resource.rb:

 def load_collection?
    resource_base.respond_to?(:accessible_by) && !current_ability.has_block?(authorization_action, resource_class)
 end

this means that if I have a block defined then I cannot load a collection. This seems a bit restrictive. I'll try to get a better logic in place and submit a PR

psteininger avatar Jul 18 '13 13:07 psteininger

The issue is caused by an overlap of rules for one action (in this case :index). If I have:

can :read, Location
can :manage, Location do |location|
   user.role? :curator, location.city
end

then :manage includes :index. I tried modifying the gem, but it felt like the fix may affect other areas. So here is a viable workaround:

can :manage, Location
cannot [:create, :update, :destroy], Location do |location|
   !user.role? :curator, location.city
end

basically I add all permissions, but exclude the ones that are only available to :curators. I hope this helps someone in need :).

psteininger avatar Jul 18 '13 15:07 psteininger

Thanks for your submission! The ryanb/cancan repository has been inactive since Sep 06, 2013. Since only Ryan himself has commit permissions, the CanCan project is on a standstill.

CanCan has many open issues, including missing support for Rails 4. To keep CanCan alive, an active fork exists at cancancommunity/cancancan. The new gem is cancancan. More info is available at #994.

If your pull request or issue is still applicable, it would be really appreciated if you resubmit it to CanCanCan.

We hope to see you on the other side!

xhoy avatar Jul 01 '14 07:07 xhoy