开发者

rails 3 : Do i need to give return true in a before_save callback for an object.save to work?

开发者 https://www.devze.com 2023-02-05 17:46 出处:网络
Class User before_save :set_searchable def set_searchable self.searchable = true if self.status == :active
Class User  
  before_save :set_searchable

  def set_searchable  
    self.searchable = true if self.status == :active  
  end  
end  

>> u = User.last  
>> u.save  
false  

u.save always return false. If i remove the before_save it works also if i give a开发者_JAVA百科 return true in before_save it works

so do i need to give return statements in before_save ? will ActiveRecord saves an object if the before_save returns false ?

Where can i see a full documentation regarding callbacks and its workflow .

Thanks in advance


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

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.

So, yes.


No, you don't need to return true from Rails callbacks. You can return nothing at all, or true, or 3.141592, and it will still be saved. The only thing that matters is if you return false, and this only applies prior to Rails 5. Returning false would cancel saving prior to Rails 5. Returning true never had any effect.

For Rails 5+, the new way to block the update is to throw an exception: throw(:abort). . This is more intuitive and less error-prone. The return value has no effect on whether it will save, unless you configure legacy behaviour.

It's valid - and imo good DRY practice - to just get on with your business and not return anything at all; just be sure to avoid accidentally returning false implicitly if using earlier Rails. For example:

# This is fine, record will be saved
def before_save
  self.foo = 'bar' # Implicitly returns 'bar'
end

# This is an accidental veto, record will not be saved
def before_save
  Rails.logger.info 'user requested save'
  self.fresh = false # Oops! Implicitly returns false
end

# One way to rectify the above example (another would be to re-order if it's possible)
def before_save
  Rails.logger.info 'user requested save'
  self.fresh = false
  return # Implicitly returns nil. Could also do `return true`
end

The gotcha here is that you might forget some "procedural" type functions will return a boolean as a kind of status code or simply because the implementation happens to end with a boolean as a side effect. You might think you're mutating a string or something, but end up accidentally vetoing the callback. So while I think it's usually too noisy to explicitly return from callbacks, you do need to take care with implicit returns. One reason people advocated returning true was to guard against this gotcha.


The documentation say

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.

BUT

you might want to check this out ( I have tested this myself and the issue is 100% authentic)

Plus also there is bug related to before_save you might want to know check the comment over here

rails 3 : Do i need to give return true in a before_save callback for an object.save to work?

As said in the comment it is observed sometimes.

Whatever you do just be aware of that there are some issues with rails callback. This would save your time when you ran into one of those


Another cleaner way to set boolean columns without return is to use tap

  def set_searchable
    self.tap{|u| u.searchable = status.eql?(:active) }
  end
0

精彩评论

暂无评论...
验证码 换一张
取 消