This project is archived and is in readonly mode.

#1943 ✓wontfix
Tamer Salama

Nested attributes validations circular dependency

Reported by Tamer Salama | February 11th, 2009 @ 04:41 PM | in 2.x

When using accepts_nested_attributes_for , a child object with a validates_presence_of :parent_id will not pass the validations upon saving the parent object.

(the child validation is done before the parent id is propagated to the child).



class Person < ActiveRecord::Base
  has_many :children
  accepts_nested_attributes_for :children
end

class Child < ActiveRecord::Base
  belongs_to :person

  #Validating that a child has a parent
  validates_presence_of :person_id
end

p = Person.new(:name => "Smith", :children_attributes => {"new_1" => {:name => "John"}})
p.valid? #=> false
p.save  #false
p.children.first.errors.on(:person_id) #=> "can't be blank" 

Comments and changes to this ticket

  • Eloy Duran

    Eloy Duran February 17th, 2009 @ 08:35 AM

    • Assigned user set to “Eloy Duran”
  • Eloy Duran

    Eloy Duran February 22nd, 2009 @ 04:24 PM

    • State changed from “new” to “wontfix”

    I wonder how we could actually handle this. It would mean you'd have to save the parent before the children in order to be able to validate the children. So simply calling parent.valid? would save it and then run the validations on the children. That all seems very complicated to me.

    Also, this should already be tested in the framework and not something the developer should need to worry about. However, if you feel there are tests for scenarios missing let me know.

    If you still feel a strong need to validate that after creation the foreign key is set, I would suggest adding an after_save callback which verifies this and if not rolls back the transaction.

  • Stephen Touset

    Stephen Touset March 9th, 2009 @ 04:01 PM

    This could be resolved by validates_presence_of :parent, rather than validates_presence_of :parent_id. Unfortunately, Rails doesn't set the parent on building the association. Could that be changed?

    Either that, or making validates_associated not be completely useless, and do what is implied by its name.

  • Eloy Duran

    Eloy Duran March 9th, 2009 @ 06:32 PM

    This could be resolved by validates_presence_of :parent, rather than validates_presence_of :parent_id. Unfortunately, Rails doesn't set the parent on building the association. Could that be changed?

    Hmm, having #build directly assign the parent sounds like a good idea in general. Maybe open a separate ticket for it or ask on the ML if there are any known issues with this?

    Either that, or making validates_associated not be completely useless, and do what is implied by its name.

    Why is validates_associated completely useless?

  • Michael Kintzer

    Michael Kintzer March 12th, 2009 @ 05:00 AM

    Is there any update regarding the previous suggestion? (Having #build_child directly assign the parent to satisfy a 'validates_presence_of :parent without the need for the parent to already be saved?)

    I looked around on the mailing lists and did not see a ticket on this. It seems like a promising approach, and it would allow for a resolution to this issue.

    Based on the blog feedback, it seems more than a handful of people do use validates_presence_of :parent_id in their belongs_to relationship models (I recall it being recommended in Dan Chak's excellent Enterprise Rails book) and it seems a shame to ask them to remove or recode that with an after_save callback just so this new feature can work.

  • Eloy Duran

    Eloy Duran March 12th, 2009 @ 08:39 AM

    Is there any update regarding the previous suggestion? (Having #build_child directly assign the parent to satisfy a 'validates_presence_of :parent without the need for the parent to already be saved?) I looked around on the mailing lists and did not see a ticket on this. It seems like a promising approach, and it would allow for a resolution to this issue.

    Nope, not that I know of. As I already suggested, open up a new ticket which requests this, or better yet, attach a patch.

    Based on the blog feedback, it seems more than a handful of people do use validates_presence_of :parent_id in their belongs_to relationship models (I recall it being recommended in Dan Chak's excellent Enterprise Rails book) and it seems a shame to ask them to remove or recode that with an after_save callback just so this new feature can work.

    This has nothing to do with any new feature, it just doesn't work this way.

  • Chris Bartlett

    Chris Bartlett April 22nd, 2009 @ 11:14 PM

    • Tag set to code

    There might also be uniqueness conditions that you want to enforce, but these fail as per the discussion above. For example, if you were trying to save a course and enrolments and had a uniqueness condition on enrolments to prevent a student from enrolling in a course more than once: validates_uniqueness_of :student_id, :scope => :course_id This validation does not work when creating a new course (say, the user has accidentally added the same student twice on the course form they are submitting). This is an old issue - see: http://dev.rubyonrails.org/ticke...

    Basically, it means that accepts_nested_attributes_for is not as nice and tidy as one would perhaps expect. Validations need to be handled by the DBMS.

  • Dmitry Polushkin

    Dmitry Polushkin April 23rd, 2009 @ 07:25 AM

    What to do? Just use DBMS index :unique => true? Or it's possible to write a patch?

  • Evgeniy Dolzhenko

    Evgeniy Dolzhenko May 13th, 2009 @ 04:50 PM

    So it's not in any way related to nested attributes, right?

    I was bitten by the same problem ( described here http://railsforum.com/viewtopic.php?pid=96990 ), and still don't get how to build, in the terms of the above example, the Person object with Child object in children association in memory, and then save them with one call.

    I.e. get the transaction safety and easier error reporting for building complex objects.

  • Melvin Ram

    Melvin Ram May 20th, 2009 @ 06:43 AM

    So what is the convention to solving this problem? Is there a workaround for the validates_presence_of :parent?

  • sarah (at ultrasaurus)
  • TMaYaD

    TMaYaD May 2nd, 2010 @ 05:54 PM

    I think we still need to fix it.
    In case of a nested resource with its own form, we might want to validate that the child does indeed belong to a parent even if its form is not nested in the parent.
    At the very least we need to be able to provide a way to tell weather we are in the model from a nested form or individual form, so that we can validate accordingly.
    the workaround I currently use in my apps is to assign an attribute ':nest' ( = self, ie, the parent )to each child before validation on parent and check for it in child

  • TMaYaD

    TMaYaD May 2nd, 2010 @ 06:07 PM

    • Tag changed from code to nested attributes, code, nested_attributes_for
  • Sean Corbett

    Sean Corbett July 3rd, 2010 @ 08:24 PM

    • Assigned user cleared.
    • Importance changed from “” to “”

    I like Ari Epstine's workaround for this on the related ticket: https://rails.lighthouseapp.com/projects/8994-ruby-on-rails/tickets...

    class Person < ActiveRecord::Base
    
      has_many :children
      accepts_nested_attributes_for :children
      before_validation_on_create :initialize_children
    
      def initialize_children
        children.each { |c| c.parent = self }
      end
    
    end
    
    class Child < ActiveRecord::Base
    
      belongs_to :person
    
    end
    
  • TMaYaD

    TMaYaD February 19th, 2011 @ 08:39 PM

    A variant to Ari Epstine's work around is using before_add callback
    class Person < ActiveRecord::Base
    has_many :children, :before_add => :set_nest accepts_nested_attributes_for :children private
    def set_nest(child)

    child.person ||= self
    

    end end

    class Child < ActiveRecord::Base
    belongs_to :person

    #Validating that a child has a parent validates_presence_of :person_id, :unless => Proc.new { |c| c.parent && c.parent.new_record? } end

Create your profile

Help contribute to this project by taking a few moments to create your personal profile. Create your profile »

<h2 style="font-size: 14px">Tickets have moved to Github</h2>

The new ticket tracker is available at <a href="https://github.com/rails/rails/issues">https://github.com/rails/rails/issues</a>

Referenced by

Pages