Ruby on Rails 5:Pundit复用Devise的stored_location_for重定向及参数问题
完全可以配合使用!参数和实现方案看这里
当然没问题,Devise的位置存储机制和Pundit完全能顺畅配合,我来帮你理清参数逻辑和具体实现步骤:
1. 「resource_or_scope」参数的正确取值
Devise的store_location_for(也就是你封装的store_user_location!底层调用的方法)里的resource_or_scope,核心是用来标识当前认证的用户范围。对于默认的Devise配置(用户模型为User,scope是:user),你有两个靠谱的选择:
- 直接传符号
:user:这是Devise默认的scope标识,和你在Devise回调里用的完全一致,即使用户未登录也能正常工作 - 传
current_user:当前已登录的用户实例,Devise会自动识别其对应的scope
这两个值效果完全相同,推荐用:user更简洁,无需考虑用户是否已登录的状态。
2. 具体实现步骤
假设你已经在ApplicationController里按照Devise Wiki配置了store_user_location!方法,比如:
def store_user_location!(resource_or_scope = :user) store_location_for(resource_or_scope, request.fullpath) end
接下来修改Pundit的user_not_authorized方法,让它复用这个存储机制:
def user_not_authorized # 分场景处理更合理: if user_signed_in? # 用户已登录但无权限:优先重定向到之前存储的位置,没有的话跳首页 redirect_to stored_location_for(:user) || root_path, alert: "你没有权限执行此操作。" else # 用户未登录:先存储当前想访问的页面,再跳登录页(登录后会自动回到这个页面) store_user_location!(:user) # 这里不传参数也可以,因为方法默认就是:user redirect_to new_user_session_path, alert: "请先登录以访问该页面。" end end
3. 确认共享同一存储位置
Devise的stored_location_for(:user)和你在after_sign_in_path_for里用的是同一个方法,它从session的同一个键读取存储路径。不管是Devise自动触发的存储,还是你在Pundit里手动调用store_user_location!存储的内容,都会存在同一个session位置,完全能保证重定向的一致性。
小提示
如果你的store_user_location!方法已经设置了默认参数resource_or_scope = :user,那在Pundit里直接调用store_user_location!就行,不用额外传参,更省事。
内容的提问来源于stack exchange,提问作者chrickso
相关产品推荐
相关产品推荐

