Если у вас когда либо возникала чудная ситуация, когда вы прописали ассоциации для моделей (has_one и belongs_to), accepted_nested_attributes, но хелпер fields_for не показывает форму то это пост поожет вам раз и навсегда избавится от этого «глюка». Заранее предупреждаю, что пост сугубо для rails разработчиков, и ни для кого никому, кроме как rails разработчикам интересен не будет!
Предусловия
Итак, допустим у нас есть следующие модели:
class Company < ActiveRecord::Base
belongs_to :location
has_one :user
accepts_nested_attributes_for :user
accepts_nested_attrbiutes_for :location
end
class User < ActiveRecord::Base
belongs_to :company
end
class Location < ActiveRecord::Base
has_one :company
end
Нам нужна форма компании с вложенными ресурсами user и location. На первый взгляд может показаться что кода:
form_for :company do |f|
f.text_field :name
f.fields_for :user, f.object.user_or_build do |fu|
fu.text_field :name
end
f.fields_for :location, f.object.location_or_build do |fl|
fl.text_field :address
end
end
будет достаточно, чтобы показать желаемую форму. Однако это не так. Запустив приложение и открыв браузер вы увидете, что вместо ожидаемых 3-х полей на странице всего одно — это поле name для company (предполагается, что у нас есть проинициализированный объект как то так:
@company = Company.new
).
Что же в этом коде не так?
Проблема кроется в том, что мы не проинициализировали ассоциированные объекты user и location для @company:
@company.build_location # то же что и @company.location = Location.new
@company.build_user # то же что и @company.user = User.new
Если эти условия выполнить до выполнения хелперов fields_for, то форма будет выглядеть как мы и ожидали. Однако писать каждый раз такой код в контроллерах как-то несерьезно, ведь контроллеры должны быть чистыми!
Решение
Избежать данную проблему можно с помощью этого гема, который носит немного неуклюжие название — get_or_build.
Добавляем в Gemfile строку:
gem 'get_ot_build'
Устанавливаем gems: bundle install, перезапускаем приложение и рефакторим код с хелперами fields_for следующим образом:
form_for :company do |f|
f.fields_for :user, :build_association => true do |fu|
fu.text_field :name
end
f.fields_for :user, :build_association => true do |fl|
fl.text_field :address
end
end
После этого код инициализации объектов ассоциаций user и location можно удалить из контроллеров, шаблонов и хелперов (еще где-то, где он есть ;) и уже не нужен).
Буду очень признателен за критику и коментарии, также приветствуются добровольцы для развития гема. Спасибо за внимание!
Автор: ka8725