Reputation:
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?
Upvotes: 4
Views: 2889
Reputation: 319
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.
Upvotes: 0
Reputation: 12202
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.
Upvotes: 0
Reputation: 25659
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.
Upvotes: 2