收集铁路3中所有路线的第一段

我正在尝试实现路由,其中​​第一个段是配置文件的别名或id:

resources :profiles, :path => '' do ... end 

我需要validation其他(更高)路由的第一段尚未采用别名。 我现在拥有的是:

 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...返回空数组。 但是只有在模型中validation,如果我把它放在视图中只是为了测试它返回所有路径的第一段数组按预期。 我做错了什么或者有更好的解决方案?

我猜你有时间问题。 在生产模式下加载模型时,可能尚未构建Rails.application.routes路由表。 但是,在开发模式下,您的模型可能会在每个请求上重新加载,因此在加载模型并validates调用时将填充Rails.application.routes

 validates :alias, :exclusion => { :in => Rails.application.routes.routes.map { ... } } 

被执行。

一个简单的解决方案是切换到validation方法:

 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路线:您的validation将错过这个新的冲突。 像这样简单:

 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 

在你的config/application.rb就足够了。