Rails Accepts_nested_attributes_for 子级在验证时没有设置父级

发布于 2024-08-20 22:04:59 字数 1010 浏览 8 评论 0 原文

验证时,我试图在子模型中访问我的父模型。我在 has_one 上发现了一些关于反向属性的信息,但我的 Rails 2.3.5 无法识别它,因此它一定从未进入发行版。我不确定这是否正是我所需要的。

我想根据父属性有条件地验证子属性。我的父模型已经创建。如果当我在父级上 update_attributes 时尚未创建子级,则它无权访问父级。我想知道如何才能访问这位家长。它应该很容易,像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

I'm trying to access my parent model in my child model when validating. I found something about an inverse property on the has_one, but my Rails 2.3.5 doesn't recognize it, so it must have never made it into the release. I'm not sure if it's exactly what I need though.

I want to validate the child conditionally based on parent attributes. My Parent model has already been created. If the child hasn't been created when I update_attributes on the parent, then it doesn't have access to the parent. I'm wondering how I can access this parent. It should be easy, something like parent.build_child sets the parent_id of the child model, why is it not doing it when building the child for accepts_nested_attributes_for?

For Example:

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

My form is standard:

<% form_for @parent do |f| %>
  <% f.fields_for :child do |c| %>
    <%= c.name %>
  <% end %>
<% end %>

With an update method

def update
  @parent = Parent.find(params[:id])
  @parent.update_attributes(params[:parent])   # => this is where my child validations take place
end

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

自控 2024-08-27 22:04:59

我在使用 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

I had basically the same problem with Rails 3.2. As suggested in the question, adding the inverse_of option to the parent's association fixed it for me.

Applied to your example:

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
贪恋 2024-08-27 22:04:59

我遇到了类似的问题: 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

I had a similar problem: Ruby on Rails - nested attributes: How do I access the parent model from child model

This is how I solved it eventually; by setting parent on callback

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
尝蛊 2024-08-27 22:04:59

您不能这样做,因为内存中的子进程不知道其分配给的父进程。只有保存后才知道。例如。

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

如果您确实认为有必要。

PS 现在不这样做的原因是因为它不太容易。需要明确告知在每种特定情况下如何访问父/子。使用身份映射的综合方法可以解决这个问题,但对于较新的版本,有 :inverse_of 解决方法。 此讨论等一些讨论发生在新闻组中。

You cannot do this because in-memory child doesn't know the parent its assigned to. It only knows after save. For example.

child = parent.build_child
parent.child # => child
child.parent # => nil

# BUT
child.parent = parent
child.parent # => parent
parent.child # => child

So you can kind of force this behavior by doing reverse association manually. For example

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

If you really find it necessary.

P.S. The reason it's not doing it now is because it's not too easy. It needs to be explicitly told how to access parent/child in each particular case. A comprehensive approach with identity map would've solved it, but for newer version there's :inverse_of workaround. Some discussions like this one took place on newsgroups.

戏剧牡丹亭 2024-08-27 22:04:59

检查这些网站,也许他们会帮助你...

Rails 嵌套属性关联验证失败< /a>

accepts_nested_attributes_for 子关联验证失败

http://ryandaigle.com/articles/ 2009/2/1/what-s-new-in-edge-rails-nested-attributes

看来,rails 会在子验证成功后分配parent_id。
(因为父母在保存后有一个ID)

也许值得尝试这个:

child.parent.some_condition

而不是 self.parent.some_condition ...谁知道...

check these sites, maybe they'll help you...

Rails Nested Attributes Association Validation Failing

accepts_nested_attributes_for child association validation failing

http://ryandaigle.com/articles/2009/2/1/what-s-new-in-edge-rails-nested-attributes

it seems, rails will assign parent_id after child validation succeeds.
(as parent has an id after it's saved)

maybe worth trying this:

child.parent.some_condition

instead of self.parent.some_condition ... who knows...

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文