Как сопоставить ресурс нескольким помощникам в рельсах?

У меня есть модель Profile, которая наследуется моделью Customer и Vendor. Профиль has_many: сообщения.

Когда я делаю

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

Вместо callind profile_posts_path form_for будет фактически вызывать customer_posts_path или vendor_posts_path.

Поскольку я хочу иметь URL-адреса, такие как "/ 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

Но это все еще ужасно. Мне бы очень хотелось, чтобы в качестве параметра был массив, чтобы я мог сделать:

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

Можно ли добиться чего-то подобного? Все будет отображаться на тот же контроллер. И никакого повторения в действии. Любой способ создания именованных маршрутов без необходимости вызова ресурсов или сопоставления или чего-либо еще...

заранее спасибо

редактировать: отношение между сообщениями и профилями может стать полиморфным в ближайшем будущем. Таким образом, последнее решение, предложенное AJcodex, сломается.

Я нахожу это разочарование, я, вероятно, запросить эту функцию для следующих рельсов

1 ответ

Решение

Некоторые варианты:

  1. использовать символ form_for([:profile, @post]) do |f|

  2. псевдоним других методов. Смотрите это для добавления маршрутов: Как определить собственные помощники маршрутизации в рельсах 3?

    alias_method :customers_path, :profiles_path
    
  3. перебирать символы в маршрутах

в route.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 для пользователя.

редактировать:

Есть ли причина, по которой вам нужны маршруты для клиентов и поставщиков для сообщений? Все сообщения обрабатываются контроллером профилей. Избавьтесь от причудливых URL поставщиков и клиентов.

В зависимости от того, клиент это или продавец, представьте другое представление при необходимости.

редактировать 2:

сделать это вручную:

<%= form_for @post, as: :post, url: profile_path(@customer, @post) do |f| %>
  ...
<% end %>
Другие вопросы по тегам