Как создать вложенные объекты с помощью accepts_nested_attributes_for
Я обновил до Rails 2.3.3 (от 2.1.x), и я пытаюсь выяснить метод accepts_nested_attributes_for
. Я могу использовать этот метод для обновления существующих вложенных объектов, но я не могу использовать его для создания новых вложенных объектов. Учитывая надуманный пример:
class Product < ActiveRecord::Base
has_many :notes
accepts_nested_attributes_for :notes
end
class Note < ActiveRecord::Base
belongs_to :product
validates_presence_of :product_id, :body
end
Если я попытаюсь создать новый Product
с вложенным Note
следующим образом:
params = {:name => 'Test', :notes_attributes => {'0' => {'body' => 'Body'}}}
p = Product.new(params)
p.save!
Не удалось выполнить проверку с сообщением:
ActiveRecord::RecordInvalid: Validation failed: Notes product can't be blank
Я понимаю, почему это происходит - из-за validates_presence_of :product_id
в классе Note
, и поскольку во время сохранения новой записи объект Product
не имеет id
. Однако я не хочу удалять эту проверку; Я думаю, было бы неправильно удалить его.
Я мог бы также решить проблему, создав сначала Product
, а затем добавив Note
, но это победит простоту accepts_nested_attributes_for
.
Существует ли стандартный способ Rails для создания вложенных объектов в новых записях?
Ответы
Ответ 1
Это общая проблема с круговой зависимостью. Существует существующий билет LightHouse, который стоит проверить.
Я ожидаю, что это значительно улучшится в Rails 3, но пока вам придется сделать обходной путь. Одним из решений является настройка виртуального атрибута, который вы устанавливаете при вложенности, чтобы сделать проверку правильной.
class Note < ActiveRecord::Base
belongs_to :product
validates_presence_of :product_id, :unless => :nested
attr_accessor :nested
end
И тогда вы должны установить этот атрибут как скрытое поле в своей форме.
<%= note_form.hidden_field :nested %>
Этого должно быть достаточно, чтобы атрибут nested
устанавливался при создании заметки через вложенную форму. Непроверенные.
Ответ 2
проверьте этот документ, если используете Rails3.
http://api.rubyonrails.org/classes/ActiveRecord/NestedAttributes/ClassMethods.html#label-Validating+the+presence+of+a+parent+model
Ответ 3
Решение Ryan на самом деле действительно круто.
Я пошел и сделал мой контроллер толще, чтобы это гнездо не должно было появляться в представлении. В основном потому, что мой взгляд иногда бывает json, поэтому я хочу быть в состоянии как можно меньше уйти.
class Product < ActiveRecord::Base
has_many :notes
accepts_nested_attributes_for :note
end
class Note < ActiveRecord::Base
belongs_to :product
validates_presence_of :product_id unless :nested
attr_accessor :nested
end
class ProductController < ApplicationController
def create
if params[:product][:note_attributes]
params[:product][:note_attributes].each { |attribute|
attribute.merge!({:nested => true})
}
end
# all the regular create stuff here
end
end
Ответ 4
Лучшим решением пока является использование плагина parental_control: http://github.com/h-lame/parental_control