如何在ApplicationController中正确插值控制器名与Action?
解决动态调用Policy方法的插值问题
嘿,我之前也踩过类似的动态方法调用坑,咱们一步步来搞定它!
你现在的核心问题是Ruby不允许直接通过字符串插值来调用方法——比如你可能尝试过写类似 Policy.new(current_user.role)."#{controller_name}_#{action_name}" 这样的代码,这肯定会触发语法错误;就算给对象加了括号,也绕不开“点运算符后不能直接跟字符串”的语法限制,而硬编码能正常运行,正是因为它符合Ruby标准的方法调用语法。
正确的解决方式:用send动态调用方法
Ruby提供了send(或更安全的public_send)方法,专门用来处理动态方法调用,它可以接收字符串或符号类型的方法名参数。
你可以在ApplicationController里这么写:
def authorize_action # 初始化Policy实例 policy = Policy.new(current_user.role) # 动态拼接控制器名+动作名的方法(比如wiki_show) target_method = "#{controller_name}_#{action_name}" # 调用动态方法并校验权限 unless policy.send(target_method) # 权限不足时的处理逻辑,比如跳转或提示 redirect_to root_path, alert: "你没有权限执行此操作" end end
额外的安全校验(可选)
如果担心某些控制器/动作没有对应的Policy方法,可以先判断方法是否存在,避免抛出NoMethodError:
def authorize_action policy = Policy.new(current_user.role) target_method = "#{controller_name}_#{action_name}" if policy.respond_to?(target_method, include_private: false) unless policy.send(target_method) redirect_to root_path, alert: "你没有权限执行此操作" end else # 处理未定义权限方法的情况,比如抛出提示或默认拒绝 raise "未针对#{target_method}定义权限规则" end end
为什么硬编码能行?
当你硬编码Policy.new(current_user.role).wiki_show时,Ruby直接识别出wiki_show是方法名,符合标准的方法调用语法;而动态拼接的字符串必须通过send方法转成Ruby能识别的方法调用指令,这就是两者的本质区别。
内容的提问来源于stack exchange,提问作者oneWorkingHeadphone
相关产品推荐
相关产品推荐

