如何使用CanCan管理Rails中复杂的用户能力

时间:2016-02-29 11:41:40

标签: ruby-on-rails devise cancan

我正在尝试创建一个Web应用程序,用户可以在其中选择一个可以选择多个小部件的仪表板。我有以下多对多:

class CreateWidgets < ActiveRecord::Migration
  def change
    create_table :widgets do |t|
      t.string :name
      t.timestamps null: false
    end

    create_table :users_widgets, id: false do |t|
      t.belongs_to :user, index: true
      t.belongs_to :widget, index: true
    end
  end    
end

使用设计宝石定义的用户模型。那么我怎样才能最有效地设置一些参数,这些参数允许我定义用户只能看到他们“订阅”的小部件的能力。

CanCan权限在此处定义:

class Ability
  include CanCan::Ability

  def initialize(user)
    can :read, Widget, :user_id => user.id
  end
end

显然,这不起作用,因为没有参数可以跟踪哪个用户创建了窗口小部件。那么如何设置Widget / User模型?可能会向用户模型添加权利列表?它可能是一大堆bool属性,每种类型的小部件都有一个,但显然,这可能会有点混乱,我应该如何以安全意识的方式解决这个问题?

更新

我的模特现在读到:

class User < ActiveRecord::Base
  has_many :subscriptions
  has_many :widgets, through: :subscriptions
end

class Widget < ActiveRecord::Base
  has_many :subscriptions
  has_many :users, through: :subscriptions
end

class Subscription < ActiveRecord::Base
  belongs_to :user
  belongs_to :widget
  # make sure you add a unique DB index as well.
  validates_uniqueness_of :user_id, scope: :widget_id
end

和我的model/ability.rb文件显示为:

class Ability
    include CanCan::Ability

    def initialize(user)
        can :read, Widget do |widget|
            widget.subscriptions.where(user: user).any?
        end
    end
end

但它仍然不起作用,我预计这是由于有关唯一数据库索引注释的说明,但我不确定要为此添加什么?

1 个答案:

答案 0 :(得分:3)

首先需要在User和Widget之间创建many to many join model

class User < ActiveRecord::Base
  has_many :subscriptions
  has_many :widgets, through: :subscriptions
end

class Widget < ActiveRecord::Base
  has_many :subscriptions
  has_many :users, through: :subscriptions
end

class Subscription < ActiveRecord::Base
  belongs_to :user
  belongs_to :widget
  # make sure you add a unique DB index as well.
  validates_uniqueness_of :user_id, scope: :widget_id
end

然后,您可以通过将块传递给can

进行授权
can :read, Widget do |widget|
  widget.subscriptions.where(user: user).any?
end