如何将Rails中的Shortlist模型以只读权限共享给其他Devise用户?
第一步:调整关联结构,新增角色区分
原有纯HABTM关联的中间表无法存储额外的角色字段,无法区分用户是所有者还是只读共享用户,需要改为has_many :through关联,新增中间表存储角色信息:
- 生成中间表迁移:
执行命令:rails g migration CreateShortlistUsers shortlist:references user:references role:string
迁移文件生成后执行rails db:migrate完成表结构更新。 - 新增中间表模型
app/models/shortlist_user.rb:
class ShortlistUser < ApplicationRecord belongs_to :shortlist belongs_to :user # 限制角色仅可为所有者或只读浏览者 validates :role, inclusion: { in: %w[owner viewer] } end
- 更新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
- 兼容历史数据:
如果已有存量用户和shortlist的关联数据,执行数据迁移把原有关联全部设置为owner角色:
Shortlist.find_each do |shortlist| shortlist.owners << shortlist.users end
- 调整业务逻辑:
- 创建shortlist时,给当前用户绑定
owner角色:@shortlist.owners << current_user - 共享shortlist时,给被共享用户绑定
viewer角色:@shortlist.viewers << target_user
第二步:配置CanCanCan权限规则
- 安装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
- 控制器启用权限校验:
在ShortlistsController中加入自动权限校验,无需手动修改原有业务逻辑即可完成权限拦截:
class ShortlistsController < ApplicationController # 自动加载资源并校验权限,会自动拦截无权限的操作请求 load_and_authorize_resource def index # 无需手动查询,@shortlists会自动加载为当前用户有权限访问的所有shortlist # 如果需要手动查询可以使用:@shortlists = current_user.shortlists.accessible_by(current_ability) end # 其余新增、编辑、删除等动作无需额外修改,CanCanCan会自动校验权限 end
- 自定义权限异常提示(可选):
在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
相关产品推荐
相关产品推荐

