Struggling with some more advanced authorizations using CanCan

139 Views Asked by At

Brand new to both Ruby and Rails here, and I just got started on my first project. Went through the new tutorial on Lynda first, then started a new project where I'm so far using RailsAdmin, CanCan and Devise.

Trying to do some more advanced authorization with CanCan, and I'm struggling a bit figuring out how to do this. For a normal user I'm now doing:

can :access, :rails_admin
can :dashboard
can :read, [Company, ProductCategory]
can [:read, :update], User, :id => user.id
can :manage, [Product, Catalog], :company_id => user.company.id
can :manage, [Image, Video, Document, Link]
cannot :export, :all

Which is working great, but I'm struggling a bit with images, videos, documents and links. These all belong_to a Product or a Catalog, and doing it the way I'm doing it above gives the user access to any file. So ideally I would want something like:

can :manage, [Image, Video, Document, Link], :product.company_id => user.company.id

But obviously I can't do that since there is no :product, but just the :product_id of the product the file belongs to. So how would I access the company id of the product referred to by the :product_id on the files?

In addition to that a company can be a subcompany of another company (which can be a subcompany of another company etc etc). So how would I do something like:

can :manage [Product, Catalog], [:company_id, :company.company.id, :company.company.company.id (etc)] => user.company.id

Basically a user should be able to manage products and catalogs that belong to their company, or that belong to any subcompany of their company.


EDITED for clarity and simplification

Company1 has sub-company Company2, Company2 has sub-company Company3 and Company3 has sub-company Company4.

User belongs to Company2 (not Company1).

User should then manage all Companies starting at Company2, meaning it should be able to manage Company2, Company3 and Company4, but not Company1.

So I tried adding:

can :manage, Company, :company_id => user.company.id
can :manage, Company, :company => { :company_id => user.company.id }
can :manage, Company, :company => { :company => { :company_id => user.company.id } } 

So the 2 first lines here seem to work, and I can see both Company2 and Company3. But Company4 - which is supposed to be handled by the third line - does not seem to show in the listing nor can it be managed by this user.

So… Why isn't that line working? And how can I get this all on one line and handled unlimited levels of companies instead of adding one line for each new level I add?

1

There are 1 best solutions below

8
On

First part:

Assumptions:

  • User belongs to Company
  • Product belongs to Company
  • Image belongs to Product
  • Document belongs to Catalog

These all permissions are affordable, by the third parameter of can method, e.g:

can :manage, Image, :product => { :company => user.company_id  }

If company has many catalogs:

can :manage, Document, :catalog => { :company => user.company_id  }

or if product has many catalogs:

can :manage, Document, :catalog => { :product => { :company => user.company_id  } }

Second part:

Assumptions:

  • Company model has company_id to meet the requirement "Company has many Companies has many Companies etc"

So that, this if the first part (User can manage Companies):

can :manage, [Product, Catalog], :company_id => user.company_id

and that's all. It is not important here how nested is the companies tree, the significant part is user always belongs to an Company and it doesn't matter if it's Company or Subcompany of Company.