Rails Devise Построить вложенную модель в контроллере
Я использую Devise
и я пытаюсь построить вложенные модели в моем RegistrationsController
,
Хотя это не работает. Я могу создавать вложенные модели с помощью
resource.build_nested_model
в представлении, но не в самом контроллере.
Это новое действие моей регистрации контроллеров
def new
super
resource.build_user_info
resource.user_info.languageskills.build
if params[:is_driver].to_i == 1
resource.build_driver
end
Rails.logger.debug(resource.build_user_info.inspect)
end
Это вывод, который он генерирует:
Started GET "/en/sign_up?is_driver=1" for 127.0.0.1 at 2014-02-13 13:20:01 +0100
Processing by RegistrationsController#new as JS
Parameters: {"is_driver"=>"1", "locale"=>"en"}
Rendered registrations/_new_user_fields.html.erb (12.1ms)
Rendered registrations/new.html.erb within layouts/application (27.8ms)
Rendered layouts/_header.html.erb (2.8ms)
Rendered layouts/_messages.html.erb (0.2ms)
Rendered layouts/_footer.html.erb (0.6ms)
(0.2ms) begin transaction
(0.1ms) commit transaction
#<UserInfo id: nil, user_id: nil, first_name: nil, last_name: nil, year_of_birth: nil, city: nil, created_at: nil, updated_at: nil, gender_id: nil, interests: nil, about: nil, country_alpha2: nil>
Completed 200 OK in 117ms (Views: 96.5ms | ActiveRecord: 0.4ms)
Почему это невозможно? Я предполагаю, что devise не сохраняет мои изменения в ресурсе, когда я строю связанные модели. Единственный выход, который я вижу, - это определение моей собственной переменной, содержащей полную копию обновленного ресурса. Это не очень хорошая практика.
Чтобы ты делал?
1 ответ
Я думаю, что проблема в том, что по умолчанию RegistrationsController.new
просто:
def new
build_resource({})
respond_with self.resource
end
(Это зависит от вашей версии устройства, но кажется, что это или эквивалент для довольно долгого пути назад.)
Это означает, что представление отображается respond_with
), прежде чем добавить свои вложенные модели в переопределенные new
потому что вы делаете это после звонка super
, Я думаю, у вас есть два варианта:
- Не звони
super
, Просто поставьте первую строку по умолчаниюnew
в начале вашегоnew
и последняя строка по умолчаниюnew
в конце твоего. - Override
build_resource
вместоnew
, В начале вашего переопределеноbuild_resource
, вызовsuper
а затем добавьте код, который был в вашемnew
послеsuper
в вашемbuild_resource
, Единственное, что вам нужно сделать, это проверить,build_resource
был вызван сnil
или пустой хеш, в этом случае вы создаете свой пустой user_info и т. д., или если он был вызван с непустым хешем, тогда не добавляйте свой пустой user_info и т. д., потому чтоbuild_resource
Должно быть, был вызван изcreate
Таким образом, хеш будет содержать все, что ваш пользователь ввел в форму для user_info, так что вы не хотите перезаписывать пустую версию! (Вы могли бы проверить текущий URL или что-то в этом роде вместо проверки хеш-параметра, но лично мне это нравится немного меньше.)
Я использовал вариант 2 в прошлом. Мне нравится это, потому что это все еще вызывает super
, поэтому мы все еще используем реализацию разработки build_resource
в то время как вариант 1 полностью игнорирует реализацию разработки new
- и что, если они внесут некоторые важные изменения в свои new
в будущем, которое вы упускаете? (Например, раньше был resource
переменная локальная для new
, но сейчас self
как вы можете видеть в приведенном выше коде.) Вариант 2 немного сложнее, потому что вам нужно проверить, нужно ли добавлять пустую user_info и т. д. Так что это на ваш вкус!