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

时间:2012-06-03 19:28:28

标签: ruby-on-rails ruby-on-rails-3 validation routes ruby-on-rails-3.2

我尝试实施第一段是个人资料别名或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...返回空数组。但是只有在模型中进行验证,如果我把它放在视图中只是为了测试它会返回所有路径的第一段数组,如预期的那样。我做错了什么或者有更好的解决方案?

1 个答案:

答案 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>}中的

就足够了。