Как сопоставить ресурс нескольким помощникам в рельсах?
У меня есть модель 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 ответ
Некоторые варианты:
использовать символ
form_for([:profile, @post]) do |f|
псевдоним других методов. Смотрите это для добавления маршрутов: Как определить собственные помощники маршрутизации в рельсах 3?
alias_method :customers_path, :profiles_path
перебирать символы в маршрутах
в 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 %>