Могу ли я иметь один и тот же URL, но разные динамические сегменты?
Можно ли использовать один и тот же URL, но с разными динамическими сегментами?
Моя проблема: я хочу иметь возможность добавить объект A
к объектам B
а также C
, Итак, я хочу иметь 2 маршрута Rails, A/new/:b_id
А ТАКЖЕ A/new/:c_id
, Который я пробовал.
В моих маршрутах.rb:
controller :A do
get 'A/new/:b_id', to: 'A#new', as: :new_b_a
get 'A/new/:c_id', to: 'A#new', as: :new_c_a
end
Проблема в том, что значение, передаваемое на новую страницу, всегда params[:b_id]
! (Я могу распечатать значение из URL, используя params[:b_id]
.)
Так что, может быть, я не могу иметь 2 одинаковых маршрута с разными динамическими сегментами..? Если так, как бы я это сделал?
2 ответа
Лучший способ сделать это - использовать вложенные ресурсы.
Вы всегда получаете :b_id
потому что Rails совпадает с маршрутами в том порядке, в котором они появляются в вашем файле. Так как B
ID - это целое число, неотличимое от C
ID, нет способа узнать, хотите ли вы одно или другое.
Но, так как у вас есть B
с иC
Если они уже есть, и, возможно, их также нужно создать, показать и т. д., вы можете разграничить их пути RESTful, что и делает Rails от вас.
# config/routes.rb
resources :bs do
resources :as
end
resources :cs do
resources :as
end
Это создаст вам пути, которые вы создаете вручную, но немного обернулись:
/bs/:b_id/as/new
/cs/:c_id/as/new
Как вы можете видеть, пути теперь начинаются с типа объекта, который вы хотите добавить A
тоже Rails может отличить их друг от друга. Вспомогательные методы, сгенерированные для этого, выглядят так же, как те, которые вы в настоящее время определяете вручную:
new_b_a_path(b)
new_c_a_path(c)
Оба пути направят вас к AsController
и тогда вам нужно будет найти правильный B
или же C
на основе присутствующего параметра:
# AsController#new
@parent = B.find(params[:b_id]) if params[:b_id]
@parent = C.find(params[:c_id]) if params[:c_id]
@a = parent.build_a # Assuming has_one or has_many from B and C to A
Rails потратил много времени на разработку особого способа решения подобных задач. Вы всегда можете погрузиться и сделать это по-другому, но в лучшем случае вы будете тратить впустую усилия, а в худшем вы будете бороться с рамками. Структура менее компромиссная и обычно побеждает.
Система маршрутизации работает, пытаясь сопоставить текущий путь с каждым из зарегистрированных маршрутов сверху вниз. Динамический :b_id
часть означает "все, что идет сюда по пути, будет передано как параметр с именем :b_id
к контроллеру ". Так что сделав запрос "A/new/anything"
всегда будет соответствовать первому маршруту, и поскольку вы переименовали параметр в :new_b_a
вот как это называется в params
хэш.
Если вы действительно хотите использовать тот же маршрут, вам нужно будет передать дополнительный аргумент, указывающий класс, с которым вы хотите создать отношения, хотя я бы не рекомендовал делать это. Это может быть что-то вроде get 'A/new/:klass/:id'
Таким образом, в контроллере вы можете сопоставить параметр с желаемыми классами:
def new
case params[:klass]
when 'B' then # do stuff
when 'C' then # do stuff
else raise "Invalid class: #{params[:klass]}"
end
end