问题描述
我正在尝试实施第一段为配置文件别名或ID的路由:
I'm trying to implement routes where the first segment is the profile's alias or id:
resources :profiles, :path => '' do
...
end
我需要验证其他(较高)路由的第一个路段尚未采用别名。我现在所拥有的是:
And I need to validate that alias is not already taken by first segments of other(higher) routes. What I have now is:
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 ...
返回空数组。但是仅在模型内部验证中,如果我将它放在某个地方以进行测试以按预期返回所有路由的第一段数组。我在做什么错了,或者有更好的解决方案?
In development everything is ok. In production Rails.application.routes.routes.map...
returns empty array. But only inside validation in model, if I put it somewhere in view just to test it returns array of first segments of all routes as expected. What am I doing wrong or maybe there is a better solution?
推荐答案
我猜你有一个计时问题,你在 Rails.application.routes 在生产模式下加载模型时可能尚未构建;但是在开发模式下,您的模型可能会在每次请求时重新加载,因此
Rails.application.routes
将在加载模型并验证
时填充:
I'd guess that you have a timing problem. Your routing table in Rails.application.routes
probably hasn't been built when your model is loaded in production mode; but, in development mode, your model is probably being reloaded on each request so Rails.application.routes
will be populated when your model is loaded and your validates
call:
validates :alias, :exclusion => { :in => Rails.application.routes.routes.map { ... } }
被执行。
一个简单的解决方案是切换到验证方法:
An easy solution would be to switch to a validation method:
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
,直到需要检查别名,到那时,路由将已加载。当然,您可以根据需要缓存路由前缀列表。
This way, you don't look at Rails.application.routes
until you need to check an alias and by that time, the routes will have been loaded. You could, of course, cache the route prefix list if you wanted to.
您还需要在应用程序的初始化阶段添加一些完整性检查。生产环境中的某人可以在添加 / pancakes
路由时添加'pancakes'
作为别名发展中:您的验证将错过这个新的冲突。像这样简单的事情:
You'll also want to add some sanity checking to your application's initialization phase. Someone in your production environment could add, say, 'pancakes'
as their alias while you add a /pancakes
route while developing: your validation will miss this new conflict. Something simple like this:
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
就足够了。
这篇关于收集铁轨中所有路线的第一部分3的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!