You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何将Rails中的Shortlist模型以只读权限共享给其他Devise用户?

第一步:调整关联结构,新增角色区分

原有纯HABTM关联的中间表无法存储额外的角色字段,无法区分用户是所有者还是只读共享用户,需要改为has_many :through关联,新增中间表存储角色信息:

  1. 生成中间表迁移:
    执行命令:
    rails g migration CreateShortlistUsers shortlist:references user:references role:string
    迁移文件生成后执行rails db:migrate完成表结构更新。
  2. 新增中间表模型 app/models/shortlist_user.rb:
class ShortlistUser < ApplicationRecord
  belongs_to :shortlist
  belongs_to :user

  # 限制角色仅可为所有者或只读浏览者
  validates :role, inclusion: { in: %w[owner viewer] }
end
  1. 更新Shortlist和User模型的关联配置:
# app/models/shortlist.rb
class Shortlist < ApplicationRecord
  has_many :shortlist_users
  has_many :users, through: :shortlist_users
  # 快速关联所有者和只读浏览者
  has_many :owners, -> { where(shortlist_users: { role: 'owner' }) }, through: :shortlist_users, source: :user
  has_many :viewers, -> { where(shortlist_users: { role: 'viewer' }) }, through: :shortlist_users, source: :user
end
# app/models/user.rb
class User < ApplicationRecord
  devise :database_authenticatable, :registerable, :recoverable, :rememberable, :validatable
  has_many :shortlist_users
  has_many :shortlists, through: :shortlist_users
  # 区分用户自己创建的和被共享的shortlist
  has_many :owned_shortlists, -> { where(shortlist_users: { role: 'owner' }) }, through: :shortlist_users, source: :shortlist
  has_many :shared_shortlists, -> { where(shortlist_users: { role: 'viewer' }) }, through: :shortlist_users, source: :shortlist
end
  1. 兼容历史数据:
    如果已有存量用户和shortlist的关联数据,执行数据迁移把原有关联全部设置为owner角色:
Shortlist.find_each do |shortlist|
  shortlist.owners << shortlist.users
end
  1. 调整业务逻辑:
  • 创建shortlist时,给当前用户绑定owner角色:@shortlist.owners << current_user
  • 共享shortlist时,给被共享用户绑定viewer角色:@shortlist.viewers << target_user

第二步:配置CanCanCan权限规则

  1. 安装CanCanCan后执行rails g cancan:ability生成权限配置文件,更新app/models/ability.rb:
class Ability
  include CanCan::Ability

  def initialize(user)
    # 未登录用户默认赋空用户对象
    user ||= User.new

    # 所有者拥有shortlist的全部操作权限
    can :manage, Shortlist, shortlist_users: { user_id: user.id, role: 'owner' }
    # 被共享的浏览者仅拥有只读权限
    can :read, Shortlist, shortlist_users: { user_id: user.id, role: 'viewer' }
  end
end
  1. 控制器启用权限校验:
    在ShortlistsController中加入自动权限校验,无需手动修改原有业务逻辑即可完成权限拦截:
class ShortlistsController < ApplicationController
  # 自动加载资源并校验权限,会自动拦截无权限的操作请求
  load_and_authorize_resource

  def index
    # 无需手动查询,@shortlists会自动加载为当前用户有权限访问的所有shortlist
    # 如果需要手动查询可以使用:@shortlists = current_user.shortlists.accessible_by(current_ability)
  end

  # 其余新增、编辑、删除等动作无需额外修改,CanCanCan会自动校验权限
end
  1. 自定义权限异常提示(可选):
    在app/controllers/application_controller.rb中加入权限异常捕获,自定义跳转逻辑和提示:
rescue_from CanCan::AccessDenied do |exception|
  redirect_to root_path, alert: '你没有权限执行该操作'
end

第三步:视图层权限判断(可选)

可以在视图中根据用户权限隐藏无权限的操作按钮,避免用户点击后出现403:

<% if can? :update, @shortlist %>
  <%= link_to '编辑Shortlist', edit_shortlist_path(@shortlist), class: 'btn btn-primary' %>
<% end %>
<% if can? :destroy, @shortlist %>
  <%= link_to '删除Shortlist', shortlist_path(@shortlist), method: :delete, class: 'btn btn-danger' %>
<% end %>

内容的提问来源于stack exchange,提问作者Stephen Lead

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.05 02:03:01