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

发布于 2024-07-27 23:56:08 字数 1047 浏览 4 评论 0原文

我在 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 记录时,我想验证生成的永久链接是否与特殊 URL 重叠。

如果用户尝试创建名为 specialsnew-in-stock 的产品,甚至是普通的 Rails RESTful 资源方法,例如 new编辑,我希望控制器查找路由配置,在模型对象上设置错误,使新记录验证失败,并且不保存它。

我可以硬编码已知非法永久链接名称的列表,但这样做似乎很混乱。 我更喜欢连接到路由以自动完成此操作。

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

I've got a RESTful setup for the routes in a Rails app using text permalinks as the ID for resources.

In addition, there are a few special named routes as well which overlap with the named resource e.g.:

# 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

The Product model is using permalink_fu to generate permalinks based on the name, and ProductsController does a lookup on the permalink field when accessing. That all works fine.

However when creating new Product records in the database, I want to validate that the generated permalink does not overlap with a special URL.

If a user tries to create a product named specials or new-in-stock or even a normal Rails RESTful resource method like new or edit, I want the controller to lookup the routing configuration, set errors on the model object, fail validation for the new record, and not save it.

I could hard code a list of known illegal permalink names, but it seems messy to do it that way. I'd prefer to hook into the routing to do it automatically.

(controller and model names changed to protect the innocent and make it easier to answer, the actual setup is more complicated than this example)

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

爱给你人给你 2024-08-03 23:56:08

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

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

Well, this works, but I'm not sure how pretty it is. Main issue is mixing controller/routing logic into the model. Basically, you can add a custom validation on the model to check it. This is using undocumented routing methods, so I'm not sure how stable it'll be going forward. Anyone got better ideas?

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
少跟Wǒ拽 2024-08-03 23:56:08

您可以使用原本不存在的路线。 这样,无论是否有人为标题选择保留字,都不会产生任何影响。

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

在您看来:

product_view_path(:permalink => @product.permalink)

You can use a route that would not otherwise exist. This way it won't make any difference if someone chooses a reserved word for a title or not.

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

And in your views:

product_view_path(:permalink => @product.permalink)
情释 2024-08-03 23:56:08

出于此类原因,最好自己显式管理 URI,并避免意外暴露您不希望的路由。

It's a better practice to manage URIs explicitly yourself for reasons like this, and to avoid accidentally exposing routes you don't want to.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文