Rails accepts_nested_attributes_for не имеет родительского набора при проверке
Я пытаюсь получить доступ к моей родительской модели в моей дочерней модели при проверке. Я нашел что-то об инверсном свойстве на has_one, но мой Rails 2.3.5 не узнает его, поэтому он, должно быть, никогда не попал в релиз. Я не уверен, что это именно то, что мне нужно.
Я хочу проверить дочерние элементы на основе родительских атрибутов. Моя родительская модель уже создана. Если ребенок не был создан, когда я обновляю атрибуты родителя, он не имеет доступа к родительскому элементу. Мне интересно, как я могу получить доступ к этому родителю. Это должно быть легко, что-то вроде parent.build_child устанавливает parent_id дочерней модели, почему это не делается при создании дочернего элемента для accepts_nested_attributes_for?
Пример:
class Parent < AR
has_one :child
accepts_nested_attributes_for :child
end
class Child < AR
belongs_to :parent
validates_presence_of :name, :if => :some_method
def some_method
return self.parent.some_condition # => undefined method `some_condition' for nil:NilClass
end
end
Моя форма стандартная:
<% form_for @parent do |f| %>
<% f.fields_for :child do |c| %>
<%= c.name %>
<% end %>
<% end %>
С помощью метода обновления
def update
@parent = Parent.find(params[:id])
@parent.update_attributes(params[:parent]) # => this is where my child validations take place
end
Ответы
Ответ 1
У меня была в основном та же проблема с Rails 3.2. Как предложено в вопросе, добавление опции inverse_of
к родительской ассоциации исправило это для меня.
Применительно к вашему примеру:
class Parent < AR
has_one :child, inverse_of: :parent
accepts_nested_attributes_for :child
end
class Child < AR
belongs_to :parent, inverse_of: :child
validates_presence_of :name, :if => :some_method
def some_method
return self.parent.some_condition # => undefined method 'some_condition' for nil:NilClass
end
end
Ответ 2
У меня была аналогичная проблема: Ruby on Rails - вложенные атрибуты: как мне получить доступ к родительской модели из дочерней модели
Вот как я решил это в конце концов; путем установки родителя при обратном вызове
class Parent < AR
has_one :child, :before_add => :set_nest
accepts_nested_attributes_for :child
private
def set_nest(child)
child.parent ||= self
end
end
Ответ 3
Вы не можете сделать это, потому что ребенок в памяти не знает родителя, которому он назначен. Он знает только после сохранения. Например.
child = parent.build_child
parent.child # => child
child.parent # => nil
# BUT
child.parent = parent
child.parent # => parent
parent.child # => child
Таким образом, вы можете проявить силовое поведение, сделав обратную связь вручную. Например
def child_with_inverse_assignment=(child)
child.parent = self
self.child_without_inverse_assignment = child
end
def build_child_with_inverse_assignment(*args)
build_child_without_inverse_assignment(*args)
child.parent = self
child
end
def create_child_with_inverse_assignment(*args)
create_child_without_inverse_assignment(*args)
child.parent = self
child
end
alias_method_chain :"child=", :inverse_assignment
alias_method_chain :build_child, :inverse_assignment
alias_method_chain :create_child, :inverse_assignment
Если вы действительно считаете это необходимым.
P.S. Причина, по которой он не делает этого сейчас, состоит в том, что это не слишком легко. Необходимо четко указать, как обращаться к родительскому/дочернему объектам в каждом конкретном случае. Комплексный подход с идентификационной картой разрешил бы его, но для более новой версии там :inverse_of
обходной путь. Некоторые обсуждения, такие как этот, имели место в новостных группах.
Ответ 4
проверить эти сайты, может быть, они помогут вам...
Сбой проверки вложенных ассоциаций вложенных атрибутов
accepts_nested_attributes_ для отказа проверки дочерней ассоциации
http://ryandaigle.com/articles/2009/2/1/what-s-new-in-edge-rails-nested-attributes
Кажется, рельсы назначат parent_id после успешной проверки.
(поскольку родитель имеет идентификатор после его сохранения)
Возможно, стоит попробовать:
child.parent.some_condition
вместо self.parent.some_condition... кто знает...