如何将资源映射到rails中的多个帮助程序?

时间:2013-10-08 18:49:17

标签: ruby-on-rails ruby routes nested-resources named-routing

我有一个Profile模型,它由Customer和Vendor模型继承。 个人档案has_many:帖子。

当我这样做时

form_for [ @profile, @post ] do |f|

form_for将实际调用customer_posts_path或vendor_posts_path而不是callind profile_posts_path。

由于我想拥有像'/ foo','/ bar'这样的网址,其中 foo bar 是用户名,我写了这样的路由:

resources :profiles, path: '/', constraints: { id: /[A-Z0-9\-\+\.]+/i } do
    resources :posts
end

resources :customers, path: '/', constraints: { id: /[A-Z0-9\-\+\.]+/i } do
    resources :posts
end

resources :vendors, path: '/', constraints: { id: /[A-Z0-9\-\+\.]+/i } do
    resources :posts
end

这样,'/ foo'的所有请求都将由ProfilesController处理(它是列表中的第一个),并且将生成路径助手,以便form_for可以工作。

然而,即使它有效,这也远非理想。有明显的重复。如果我需要添加另一个嵌套资源,我将不得不添加它。

所以我像这样重构它(我知道这很糟糕,但它确实有效):

profile_block = Proc.new do
    resources :posts
end
resources :profiles, path: '/', constraints: { id: /[A-Z0-9\-\+\.]+/i }, &profile_block
resources :customer, path: '/', constraints: { id: /[A-Z0-9\-\+\.]+/i }, &profile_block
resources :vendor, path: '/', constraints: { id: /[A-Z0-9\-\+\.]+/i }, &profile_block

但这仍然很可怕。我真正喜欢的是 as 参数是一个数组,所以我可以这样做:

resources :profiles, path: '/', constraints: { id: /[A-Z0-9\-\+\.]+/i }, as: [ 'profiles', 'customers', 'vendors' ] do
    ...
end

是否有可能实现类似的目标?一切都将映射到同一个控制器。行动中没有重复。任何创建命名路由的方法,无需调用资源匹配或其他任何内容......

提前致谢

修改 帖子和个人资料之间的关系在不久的将来可能会变得多态。因此,AJcodex提出的最后解决方案将会破裂。

我发现这令人沮丧,我可能会为下一个轨道请求此功能

1 个答案:

答案 0 :(得分:1)

一些选项:

  1. 使用符号form_for([:profile, @post]) do |f|

  2. 别名其他方法。看到这个添加路线: How to define own routing helpers in rails 3?

    alias_method :customers_path, :profiles_path
    
  3. 迭代路线中的符号

  4. 在routes.rb

    [ :profiles, :customers, :vendors ].each do |name|
      resources name, path: '/', constraints: { id: /[A-Z0-9\-\+\.]+/i }, as: name do
        resources :posts
      end
    end
    

    您应该考虑使用客户端框架,因为这样您就可以将面向客户端的路由与API路由分开。服务器的RESTful请求,用户的虚URL。

    修改

    您是否有理由要求客户和供应商发布帖子?让配置文件控制器处理所有帖子。摆脱供应商和客户喜欢的网址。

    根据客户或供应商的不同,如有必要,请呈现不同的视图。

    编辑2:

    手工完成:

    <%= form_for @post, as: :post, url: profile_path(@customer, @post) do |f| %>
      ...
    <% end %>