【问题标题】:Rails accepts_nested_attributes_for child doesn't have parent set when validatingRails accept_nested_attributes_for child 在验证时没有设置父级
【发布时间】:2011-01-14 16:00:18
【问题描述】:

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

我想根据父属性有条件地验证孩子。我的父模型已经创建。如果在我对父级进行 update_attributes 时尚未创建子级,则它无权访问父级。我想知道如何访问该父级。 应该很简单,类似 parent.build_child 设置子模型的 parent_id,为什么在为接受嵌套属性构建子模型时不这样做?

例如:

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

【问题讨论】:

    标签: ruby-on-rails activerecord relationships


    【解决方案1】:

    查看这些网站,也许它们会对您有所帮助...

    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

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

    也许值得一试:

    child.parent.some_condition
    

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

    【讨论】:

      【解决方案2】:

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

      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
      

      如果你真的觉得有必要。

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

      【讨论】:

        【解决方案3】:

        我也有类似的问题: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
        

        【讨论】:

        • 我遇到了与操作相同的错误,但是当我尝试这种方法时,我得到了“Unknown key(s): before_add”?
        【解决方案4】:

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

        【讨论】:

          猜你喜欢
          • 2011-07-20
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2023-03-05
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多