我尝试实施第一段是个人资料别名或ID的路线:
resources :profiles, :path => '' do
...
end
我需要验证其他(更高)路由的第一段尚未采用别名。我现在拥有的是:
validates :alias, :exclusion => {:in => Rails.application.routes.routes.map{|r| r.path.spec.to_s.split('(').first.split('/').second}.compact.uniq },
....
在开发过程中一切都很好。在生产中Rails.application.routes.routes.map...
返回空数组。但是只有在模型中进行验证,如果我把它放在视图中只是为了测试它会返回所有路径的第一段数组,如预期的那样。我做错了什么或者有更好的解决方案?
答案 0 :(得分:1)
我猜你有时间问题。在生产模式下加载模型时,可能尚未构建Rails.application.routes
中的路由表;但是,在开发模式下,您的模型可能会在每个请求中重新加载,因此在加载模型和Rails.application.routes
调用时将填充validates
:
validates :alias, :exclusion => { :in => Rails.application.routes.routes.map { ... } }
已执行。
一个简单的解决方案是切换到验证方法:
class Model < ActiveRecord::Base
validate :alias_isnt_a_route, :if => :alias_changed?
private
def alias_isnt_a_route
routes = Rails.application.routes.routes.map { ... }
if(routes.include?(alias))
errors.add(:alias, "Alias #{alias} is already used for a route")
end
end
这样,在需要检查别名之前,不要查看Rails.application.routes
,到那时,路由将被加载。当然,您可以根据需要缓存路由前缀列表。
您还需要在应用程序的初始化阶段添加一些健全性检查。在开发时添加'pancakes'
路由时,生产环境中的某个人可以添加/pancakes
作为别名:您的验证将错过此新冲突。像这样简单:
config.after_initialize do
Rails.application.reload_routes! # Make sure the routes have been loaded.
# Compare all the existing aliases against the route prefixes and raise an
# exception if there is a conflict.
end
<{1>}中的就足够了。