2
votes

Is there a way to do validations across models within the nested structure of a nested model form? In the nested hierarchy I’m working with, a child model references an attribute in the parent to perform a validation. Since the validations are done from the bottom up, (the child model is validated first), the child does not have a reference to the parent and the validation fails. For example:

# encoding: utf-8
class Child < ActiveRecord::Base
  attr_accessible :child_attribute
  belongs_to :parent
  validate :to_some_parent_value

  def to_some_parent_value
    if child_attribute > parent.parent_attribute # raises NoMethodError here on ‘parent’
      errors[:child_attribute] << "Validation error."
    end
  end
end

class Parent < ActiveRecord::Base
  attr_accessible :parent_attribute
  has_one :child
  accepts_nested_attributes_for :child
end

In console:

> p=Parent.new( { "parent_attribute" => "1", "child_attributes" => { "child_attribute" => "2" }} )
> p.valid?
=> NoMethodError: undefined method `parent_attribute' for nil:NilClass

Is there a way to have this kind of validation where the child references a value in the parent and still use the Rails nested model forms feature?

1

1 Answers

1
votes

edit: hum, I read your post a bit too fast, I thought that with where the child references a value in the parent, you meant the foreign key parent_id... My answer might still help, not sure.

I think you're looking for the inverse_of option. Try that:

class Parent < ActiveRecord::Base
    has_one :child, inverse_of :parent
end

class Child < ActiveRecord::Base
    belongs_to :parent, inverse_of :child
end

From the doc:

Validating the presence of a parent model

If you want to validate that a child record is associated with a parent record, you can use validates_presence_of and inverse_of as this example illustrates:

class Member < ActiveRecord::Base
    has_many :posts, :inverse_of => :member
    accepts_nested_attributes_for :posts
end

class Post < ActiveRecord::Base
    belongs_to :member, :inverse_of => :posts
    validates_presence_of :member
end