【问题标题】:How to manage complex user abilities in Rails with CanCan如何使用 CanCan 在 Rails 中管理复杂的用户能力
【发布时间】:2016-02-29 11:41:39
【问题描述】:

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

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

使用设计 gem 定义的用户模型。那么如何才能最有效地设置一些参数,让我能够定义用户仅查看他们“订阅”的小部件的能力。

CanCan 权限在这里定义:

class Ability
  include CanCan::Ability

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

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

更新:

我的模型现在显示:

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

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

【问题讨论】:

    标签: ruby-on-rails devise cancan


    【解决方案1】:

    您首先需要在用户和小部件之间创建一个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
    

    【讨论】:

    • 我已经发布了我的迁移文件,大概是我添加了一些东西吧?
    • 唯一的数据库索引只是确保您的subscriptions 表中没有重复项。您可以使用add_index(:subscriptions, [:user_id, :widget_id], unique: true) 添加一个。 robots.thoughtbot.com/the-perils-of-uniqueness-validations
    • “显然,这不起作用,因为没有参数可以跟踪哪个用户创建了小部件。” - 这甚至不在最初的问题中。最简单的方法是在 Widget 中添加一个 belongs_to :creator, class: 'User' 和一个 creator_id 列(你可以随意调用它)。
    • 谢谢。问题是用户不创建小部件,他们只是订阅它们,所以很多用户可以订阅同一个小部件。
    • 是的,你会使用上面的关系,你可能想从阅读指南文章开始,弄清楚关系在 Rails 中是如何工作的。 guides.rubyonrails.org/…
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多