Rails I18n URL生成器异常咨询:传入Record对象时路由匹配失败,为何未遵循默认行为?
咱们先把问题的根儿捋清楚:你遇到的报错,核心原因是路由参数的绑定顺序被默认的locale参数抢占了。
为什么会出错?
你的路由最外层用了scope "/:locale",意味着所有路由的第一个动态参数都是:locale。同时你在default_url_options里设置了{ locale: I18n.locale },这会自动给所有URL生成请求添加上locale参数。
当你调用edit_user_registration_path(current_user)时,Rails的路由助手会遵循「未指定名的参数优先绑定到路由中最靠前的动态参数」的规则——它把current_user这个对象直接赋值给了第一个动态参数:locale,而不是你预期的:id参数。这就导致locale变成了一个User实例,完全不符合路由里locale: /#{I18n.available_locales.join("|")}/的正则约束,自然就抛出了路由匹配错误。
为什么正常场景能工作?
你调用edit_user_registration_path(id:9)时,明确指定了:id参数的值,此时路由助手会用default_url_options里的I18n.locale填充:locale参数,:id参数也正确匹配,所以能生成符合规则的URL。
解决方案
这里给你几个实用的解决办法:
显式指定参数名(最推荐):
调用路由助手时,明确把ActiveRecord对象绑定到:id参数,避免参数被错误赋值。比如:edit_user_registration_path(id: current_user)Rails会自动把
current_user转换成它的to_param值(默认是id),同时locale参数由default_url_options自动填充,完美解决问题。封装自定义路由助手(可选,简化调用):
如果不想每次都写id:,可以在app/helpers/application_helper.rb里封装一个自定义助手:def edit_user_registration_for(user) edit_user_registration_path(id: user) end之后直接调用
edit_user_registration_for(current_user)就可以了。调整路由参数顺序(不推荐):
如果你把:id放在:locale前面,确实能让对象自动绑定到:id,但这会改变URL结构(变成/:id/:locale/...),不符合I18n URL的常规设计,所以不建议这么做。
内容的提问来源于stack exchange,提问作者georges

