Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Rails: How to use before_save to change a field value based on another field?

I'm trying to set a boolean field to false based on the value of another boolean field. I tried the following with an ActiveRecord model:

  before_save :reconcile_xvent

  def reconcile_xvent
    self.xvent_hood = false if !self.xvent_plenum?
  end

But this doesn't work. Now, many of my unit tests fail with:

ActiveRecord::RecordNotSaved: ActiveRecord::RecordNotSaved

How can I set xvent_hood to be false if xvent_plenum is false?

Update

Here's what works (some of which comes from the comments/answers below):

before_validation :reconcile_xvent

def reconcile_xvent
  if self.xvent_hood?
    self.xvent_hood = false unless xvent_plenum?
  end
end

I couldn't figure out to make it work without the "if self.xvent_hood?" part....

like image 770
croceldon Avatar asked Aug 02 '12 17:08

croceldon


2 Answers

before_save is only called after validation has passed. What you need to do is move reconcile_xvent up to before_validation rather than before_save

If you keep that method in before_save what will happen is that it thinks that xvent_hood is null, if you have a validation that checks for nullity of xvent_hood it will fail before the before_save gets called. Which probably explains why you got RecordNotSaved error.

Another thing to keep in mind is that if you have a boolean property, you also can't use validate_presence_of. See http://alexanderwong.me/post/16084280769/rails-validate-presence-of-boolean-and-arrays-mongoid

like image 75
Ken Li Avatar answered Oct 24 '22 16:10

Ken Li


I just hit this issue also, the problem with the first block of code is that you're assigning the xvent_hood value to false which is then returned by your before_save method.

as per

Canceling callbacks

If a before_* callback returns false, all the later callbacks and the associated action are cancelled. If an after_* callback returns false, all the later callbacks are cancelled. Callbacks are generally run in the order they are defined, with the exception of callbacks defined as methods on the model, which are called last.

from http://api.rubyonrails.org/classes/ActiveRecord/Callbacks.html

like image 37
lyallward Avatar answered Oct 24 '22 17:10

lyallward