rails cancancan has_many через способности

компания.rb:

class Company < ActiveRecord::Base
  has_many :companies_admins, dependent: :destroy
  has_many :supervisors, through: :companies_admins
end

company_admin.rb:

class CompaniesAdmin < ActiveRecord::Base
    belongs_to :company
    belongs_to :supervisor, foreign_key: "admin_id"
end

супервайзер.rb:

class Supervisor < Admin
    has_many :companies_admins, foreign_key: "admin_id"
    has_many :companies, through: :companies_admins, foreign_key: "admin_id"
end

Я использую камень канканкан. Мои способности.rb:

    class Ability
      include CanCan::Ability

      def initialize(user)
        user ||= Admin.new # guest user (not logged in)
        if user.type == "Administrator"
            can :manage, :all
        elsif user.type == "Supervisor"
            can :manage, Company, companies_admins: {supervisor: { :id => user.id } }
        end
  end
end

company_controller.rb:

class CompaniesController < ApplicationController
    load_and_authorize_resource only: [:new, :create, :edit, :update, :index, :show, :destroy]
    load_and_authorize_resource :supervisor
    load_and_authorize_resource through: :supervisor
...
end

Мне нужно руководить только компаниями, способными управлять, с которыми у него есть отношения. Пример: руководитель

companies_admins

когда я открываю страницу компании id=10 получаю отказ в доступе.

Started GET "/companies/10" for 127.0.0.1 at 2016-06-05 14:23:01 +0300
Processing by CompaniesController#show as HTML
  Parameters: {"id"=>"10"}
  Company Load (0.4ms)  SELECT  "companies".* FROM "companies" WHERE "companies"."id" = $1 LIMIT 1  [["id", 10]]
  Admin Load (0.3ms)  SELECT  "admins".* FROM "admins" WHERE "admins"."id" = $1 LIMIT 1  [["id", 4]]
  CompaniesAdmin Load (0.4ms)  SELECT "companies_admins".* FROM "companies_admins" WHERE "companies_admins"."company_id" = $1  [["company_id", 10]]
  Supervisor Load (0.4ms)  SELECT  "admins".* FROM "admins" WHERE "admins"."type" IN ('Supervisor') AND "admins"."id" = $1 LIMIT 1  [["id", 2]]
  Supervisor Load (0.4ms)  SELECT  "admins".* FROM "admins" WHERE "admins"."type" IN ('Supervisor') AND "admins"."id" = $1 LIMIT 1  [["id", 4]]
Redirected to http://localhost:3000/
Completed 302 Found in 20ms (ActiveRecord: 1.9ms)

Вопрос в том, почему? как идентифицировать выражение "включать"?

Редактировать: очень странно, даже администратором мне отказывают в доступе, когда я заменяю :all Company. Почему?

def initialize(user)
    user ||= Admin.new # guest user (not logged in)
    puts user.type
    if user.type == "Administrator"
        can :manage, Company
    elsif user.type == "Supervisor"
        can :show, :all 
    end
end

Started GET "/companies/10" for 127.0.0.1 at 2016-06-05 22:55:49 +0300
Processing by CompaniesController#show as HTML
  Parameters: {"id"=>"10"}
  Admin Load (0.3ms)  SELECT  "admins".* FROM "admins" WHERE "admins"."id" = $1 LIMIT 1  [["id", 1]]
Administrator
Redirected to http://localhost:3000/
Completed 302 Found in 42ms (ActiveRecord: 2.5ms)

в консоли рельсов:

irb(main):005:0> mi = Admin.find(1)
  Admin Load (0.7ms)  SELECT  "admins".* FROM "admins" WHERE "admins"."id" = $1 LIMIT 1  [["id", 1]]
=> #<Administrator id: 1, type: "Administrator", login: "mars", crypted_password: "8d6ff3f5b32b22726a45b1f8fa69519debf9ec8157d78f8e41...", password_salt: "2oMqwXKIukbKpdEXip", persistence_token: "37127e1f262d4efb44bc458df76e110a6ee78969c94c84a43c...", created_at: "2016-06-04 21:11:18", updated_at: "2016-06-05 09:06:15">
irb(main):006:0> comp = Company.find(10)
  Company Load (0.9ms)  SELECT  "companies".* FROM "companies" WHERE "companies"."id" = $1 LIMIT 1  [["id", 10]]
=> #<Company id: 10, parent_id: nil, address_id: 6, name: "test_address"...>
irb(main):007:0> ability = Ability.new(mi)
Administrator
=> #<Ability:0x007f09513a0938 @rules=[#<CanCan::Rule:0x007f09513a0898 @match_all=false, @base_behavior=true, @actions=[:manage], @subjects=[Company(id: integer, parent_id: integer, address_id: integer, name: string, info: string, created_at: datetime, updated_at: datetime, site_link: string, vk_link: string, raiting: float, city_id: integer, paid: integer)], @conditions={}, @block=nil>], @rules_index={Company(id: integer, parent_id: integer, address_id: integer, name: string, info: string, created_at: datetime, updated_at: datetime, site_link: string, vk_link: string, raiting: float, city_id: integer, paid: integer)=>[0]}>
irb(main):008:0> ability.can?(:manage, comp)
=> true

Что я сделал не так?


person Marsel.V    schedule 05.06.2016    source источник


Ответы (1)


хм, это работает:

class Ability
  include CanCan::Ability
  def initialize(user)
    user ||= Admin.new # guest user (not logged in)
    if user.type == "Administrator"
        can :manage, Company
    elsif user.type == "Supervisor"
        can :manage, Company do |comp|
            comp.supervisor_ids.include?(user.id)
        end
    end
  end
end

company_controller.rb:

class CompaniesController < ApplicationController
    load_and_authorize_resource only: [:new, :create, :edit, :update, :index, :show, :destroy]
....
person Marsel.V    schedule 06.06.2016
comment
Теперь это было изменено, как указано здесь: github.com/CanCanCommunity. /канканкан/вики/ - person Ahmad hamza; 05.08.2017