Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP

Loading…

Solves problem when authorizing new action. #754

Merged
merged 1 commit into from

2 participants

@Serabe

Given two models Category and Projects. A Category has_many
projects and Project belongs_to a category. Furthermore,
projects are shallow nested resources in a category.

Let's say that a user can edit certain category's projects
(and only one category can be edited by each user [1]), this is
expressed with the following line in Ability model:

can :new, :projects, category_id: user.category_id

Given the old implementation, we get that any user can 'new'
(though not 'create') a project in any category:

def assign_attributes(resource)
  resource.send("#{parent_name}=", parent_resource) if @options[:singleton] && parent_resource
  initial_attributes.each do |attr_name, value|
    resource.send("#{attr_name}=", value)
  end
  resource
end

In this case, category_id in project would get overwritten
inside the initial_attributes loop and authorization would pass.
I consider this a buggy behaviour.

[1] User belongs_to a category, and a Category has many
users. On the other hand, there might be users without
any category.

@Serabe Serabe Solves problem when authorizing new action.
Given two models Category and Projects. A Category has_many
projects and Project belongs_to a category. Furthermore,
projects are shallow nested resources in a category.

Let's say that a user can edit certain category's projects
(and only one category can be edited by each user [1]), this is
expressed with the following line in Ability model:

can :new, :projects, category_id: user.category_id

Given the old implementation, we get that any user can 'new'
(though not 'create') a project in any category:

```ruby
def assign_attributes(resource)
  resource.send("#{parent_name}=", parent_resource) if @options[:singleton] && parent_resource
  initial_attributes.each do |attr_name, value|
    resource.send("#{attr_name}=", value)
  end
  resource
end
```

In this case, category_id in project would get overwritten
inside the initial_attributes loop and authorization would pass.
I consider this a buggy behaviour.

[1] User belongs_to a category, and a Category has many
users. On the other hand, there might be users without
any category.

Conflicts:
	spec/cancan/controller_resource_spec.rb
1f7e4c8
@ryanb ryanb merged commit 68ea78b into ryanb:2.0

1 check passed

Details default The Travis build passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Commits on Oct 4, 2012
  1. @Serabe

    Solves problem when authorizing new action.

    Serabe authored
    Given two models Category and Projects. A Category has_many
    projects and Project belongs_to a category. Furthermore,
    projects are shallow nested resources in a category.
    
    Let's say that a user can edit certain category's projects
    (and only one category can be edited by each user [1]), this is
    expressed with the following line in Ability model:
    
    can :new, :projects, category_id: user.category_id
    
    Given the old implementation, we get that any user can 'new'
    (though not 'create') a project in any category:
    
    ```ruby
    def assign_attributes(resource)
      resource.send("#{parent_name}=", parent_resource) if @options[:singleton] && parent_resource
      initial_attributes.each do |attr_name, value|
        resource.send("#{attr_name}=", value)
      end
      resource
    end
    ```
    
    In this case, category_id in project would get overwritten
    inside the initial_attributes loop and authorization would pass.
    I consider this a buggy behaviour.
    
    [1] User belongs_to a category, and a Category has many
    users. On the other hand, there might be users without
    any category.
    
    Conflicts:
    	spec/cancan/controller_resource_spec.rb
This page is out of date. Refresh to see the latest.
View
3  lib/cancan/controller_resource.rb
@@ -85,10 +85,11 @@ def build_resource
end
def assign_attributes(resource)
- resource.send("#{parent_name}=", parent_resource) if @options[:singleton] && parent_resource
initial_attributes.each do |attr_name, value|
resource.send("#{attr_name}=", value)
end
+
+ resource.send("#{parent_name}=", parent_resource) if @options[:singleton] && parent_resource
resource
end
View
18 spec/cancan/controller_resource_spec.rb
@@ -284,10 +284,26 @@ class CustomModel
CanCan::ControllerResource.new(@controller, :category, :load => true).process
CanCan::ControllerResource.new(@controller, :project, :load => true, :through => :category).process
project = @controller.instance_variable_get(:@project)
- project.new_record?.should eq(true)
+ project.should be_new_record
project.name.should eq('foo')
end
+ it "does not overrides an attribute if it is based on parent resource" do
+ user = double('user')
+ user.should_receive(:category_id).and_return nil
+ @ability = Ability.new user
+ @ability.can :new, :projects, :category_id => user.category_id
+ category = Category.create!
+ @controller.instance_variable_set(:@category, category)
+
+ @params.merge! :action => 'new', :category_id => category.id
+ CanCan::ControllerResource.new(@controller, :category, :load => true).process
+ CanCan::ControllerResource.new(@controller, :project, :load => true, :through => :category, :singleton => true).process
+ project = @controller.instance_variable_get(:@project)
+ project.category_id.should_not be_nil
+ project.category.should eq(category)
+ end
+
it "authorizes nested resource through parent association on index action" do
pending
@params.merge!(:action => "index")
Something went wrong with that request. Please try again.