Могу ли я иметь один и тот же 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
Другие вопросы по тегам