2010-02-09 131 views
9

Rails的accept_nested_attributes_for孩子没有父集验证时我试图访问我的父模型。我在has_one上找到了一些有关逆向属性的内容,但是我的Rails 2.3.5无法识别它,所以它一定从未将它放入发布版。我不确定它是否正是我需要的。验证时验证

我想根据父属性有条件地验证孩子。我的父母模型已经创建。如果在父级上update_attributes时没有创建子级,那么它无权访问父级。我想知道如何访问这个父母。它应该很容易,就像parent.build_child设置子模型的parent_id,为什么在构建accept_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 

回答

7

你不能做到这一点因为内存中的孩子不知道分配给它的父代。它只在保存后才知道。例如。

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解决方法。一些讨论如this one发生在新闻组上。

8

我有一个类似的问题:Ruby on Rails - nested attributes: How do I access the parent model from child model

这是我如何解决它最终;通过设置父母回调

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 
+0

我有同样的错误作为操作,但是当我尝试这种方法时,我得到了“未知的键(s):before_add”? – Kvass 2011-08-19 16:02:19

8

我有基本上与Rails 3.2相同的问题。正如问题中所建议的那样,向家长协会添加inverse_of选项为我解决了这个问题。