views:

879

answers:

3

Since has_one doesn't provide a before_add callback to allow validation, how do I prevent rails from destroying the old association even when the new one does'nt pass validation?

susan :has_one :shirt shirt :belongs_to :susan

susan.shirt = a_nice_shirt

this destroys whatever association was present beforehand, even if the new shirt is never realy associated because it didn't pass validation, leaving a shirtless susan behind (well, acutally leaving a shirt behind that doesn't belong to anyone..).

susan.build_shirt

does the same thing

Is there a good reason for the missing before_add callback that I overlooked?

+2  A: 

I'm not sure why that callback isn't there, but you can always just add an Observer to the model, and verify the new association in a before_save. I'll assume "susan" is a User Model instance, and the shirt has to be red to pass validation.

class UserObserver< ActiveRecord::Observer
  def before_save(user)
    return false if user.shirt.color != "red"
  end
end

If you return false in the observer, the object won't save. Of course, your current instance of "susan" will still have the invalid association. I'm not positive, but if you change the before_save_ in the observer to something like this:

class UserObserver< ActiveRecord::Observer
  def before_save(user)
    if user.shirt.color != "red"
      user.reload
      false
  end
end

Might refresh the instance of your User. I've never tried this though.

Mike Trpcic
A: 

In Rails validation is usually done when you try to save the object to the database (using save or save!), not when it's modified. If for any reason you would like to restore the old value when the validation fails you can either reload the object or use the new dirty attributes feature.

Adam Byrtek
A: 

Look at this ticket:

http://dev.rubyonrails.org/ticket/10518

It appears that the functionality described there is still present if you have :dependent => :destroy on your association.

Personally, I think this is a bug in rails.