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... кто знает...