收集所有路由的第一部分在轨道3(Collecting first segments of all r

2019-09-17 18:10发布

我想实现的路线,其中第一部分是配置文件的别名或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...返回空数组。 但是,只有在内部模型验证,如果我把它放在鉴于只是为了测试它返回的所有路由的第一环节的阵列预期。 我在做什么错误或者也许有更好的解决办法?

Answer 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

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



文章来源: Collecting first segments of all routes in rails 3