如何以只读模式与其他 Devise 用户共享 Rails 模型?

How to share a Rails model with other Devise users in read-only mode?

在 Rails 5 应用程序中,我有一个 shortlist 模型与 user 模型的 HABTM 关系,用户由 Devise 控制。这一切都按预期工作,每个用户都可以看到他们自己的候选名单(仅)。

class Shortlist < ApplicationRecord
  has_and_belongs_to_many :users
 ...

class User < ApplicationRecord
  devise :database_authenticatable, :registerable, :recoverable, :rememberable, :validatable
  has_and_belongs_to_many :shortlists
  ...

class ShortlistsController < ApplicationController
  def index
    @shortlists = current_user.shortlists
    ...

现在我希望允许用户与其他用户“共享”候选名单,他们将对共享的候选名单具有只读访问权限。

我可以将第二个用户添加到候选名单 (@shortlist.users << User.second),但这会给他们完整的读写权限。

cancancan gem 看起来很有前途,但我不确定如何配置这些功能,让 User1 完全控制他们的候选名单,并为 User2 提供对候选名单的只读访问权限User1 与他们分享。

如何限制第二个用户具有只读访问权限?

作为解决方法,我在候选名单上添加了一个 owner 标志,在创建候选名单时计算为 current_user.id。这使我能够区分所有者和查看者。

在保存入围名单之前,我检查是否 @shortlist.owner == current_user.id 如果没有则显示错误消息。

这很好用,但我很想知道是否有更简单的方法。

您将 owner_id 列添加到候选列表 table 的解决方案实际上是一个很好的解决方案,因为它可以让您有效地渴望加载关联并且处理起来不那么麻烦。

如果您也想通过连接跟踪创建记录的用户 table,那可以通过角色系统实现,但会笨重得多。 Rolify gem 就是一个通用角色系统的例子。

你应该做的一件事是使用 has_many through: 而不是 the near useless has_and_belongs_to_many:

class Shortlist < ApplicationRecord
  belongs_to :owner, 
    class_name: 'User'
  has_many :shares
end

# rails g model user:belongs_to shortlist:belongs_to
class Share < ApplicationRecord
  belongs_to :user
  belongs_to :shortlist
end

class User < ApplicationRecord
  has_many :shortlists, 
    foreign_key: :owner_id
  has_many :shares
  has_many :lists_shared_with_me,
    through: :shares,
    source: :shortlists 
end

这让您可以向 table 添加额外的列,例如可以让您授予其他用户编辑候选名单或自动到期日期的权利的标志。您还可以为每个共享生成唯一的 URL,以跟踪正在使用的“共享”。 None 使用 HABTM 是可能的。