在Ruby on Rails中创建新资源时,验证没有路由重叠

时间:2009-07-13 23:57:34

标签: ruby-on-rails rest routing permalink-fu

我在Rails应用程序中使用文本永久链接作为资源ID,为路由设置了RESTful设置。

此外,还有一些特殊的命名路由与命名资源重叠,例如:

# bunch of special URLs for one off views to be exposed, not RESTful
map.connect '/products/specials', :controller => 'products', :action => 'specials'
map.connect '/products/new-in-stock', :controller => 'products', :action => 'new_in_stock'

# the real resource where the products are exposed at
map.resources :products

Product模型使用permalink_fu根据名称生成永久链接,ProductsController在访问时对永久链接字段执行查找。一切正常。

但是,当在数据库中创建新的Product记录时,我想验证生成的永久链接与特殊网址重叠。

如果用户尝试创建名为specialsnew-in-stock的产品,或者甚至是newedit等正常的Rails RESTful资源方法,我希望控制器能够查找路由配置,在模型对象上设置错误,对新记录的验证失败,而不是保存它。

我可以硬编码已知的非法永久链接名称列表,但这样做似乎很麻烦。我宁愿挂钩路由来自动完成。

(控制器和型号名称已更改,以保护无辜并使其更容易回答,实际设置比此示例更复杂)

3 个答案:

答案 0 :(得分:1)

嗯,这很有效,但我不确定它有多漂亮。主要问题是将控制器/路由逻辑混合到模型中。基本上,您可以在模型上添加自定义验证以进行检查。这是使用未记录的路由方法,所以我不确定它将来会有多稳定。有人有更好的想法吗?

class Product < ActiveRecord::Base
  #... other logic and stuff here...

  validate :generated_permalink_is_not_reserved

  def generated_permalink_is_not_reserved
    create_unique_permalink # permalink_fu method to set up permalink
    #TODO feels really ugly having controller/routing logic in the model. Maybe extract this out and inject it somehow so the model doesn't depend on routing
    unless ActionController::Routing::Routes.recognize_path("/products/#{permalink}", :method => :get) == {:controller => 'products', :id => permalink, :action => 'show'}
      errors.add(:name, "is reserved")
    end
  end
end

答案 1 :(得分:0)

您可以使用原本不存在的路线。这样,如果有人为标题选择了保留字,它就没有任何区别。

map.product_view '/product_view/:permalink', :controller => 'products', :action => 'view'

在你的意见中:

product_view_path(:permalink => @product.permalink)

答案 2 :(得分:0)

出于这样的原因,自行明确管理URI是一种更好的做法,并避免意外暴露您不想要的路由。