When to use `save` vs `save!` in model?

Ruby on-Rails-3

Ruby on-Rails-3 Problem Overview


According to save bang your head, active record will drive you mad, we should avoid using save! and rescue idiom for exceptional situations. Given that, say a model needs to @post.mark_rejected.

If the code in mark_rejected fails due to one of the below problems, should an exception be thrown? :

  • if there is a validation problem
  • if a non-nullable-field was being assigned a null
  • if there was a connection loss to database

If we do not throw an exception, then:

  • controller action would have to check for return value of mark_rejected and do it's thing
  • we are not expecting an exception from that method call, so we do not write a rescue clause in the controller action, thus the exception bubbles up to (..wherever..) and will probably show up as some (500 HTTP?) error

Example code:

def mark_rejected
  ...
  save!
end

or

def mark_rejected
  ...
  save
end

Ruby on-Rails-3 Solutions


Solution 1 - Ruby on-Rails-3

save! will raise an error if not successful.

save will return boolean value like true or false.

Solution 2 - Ruby on-Rails-3

There's more overhead in an exception, so there is a performance issue, especially when it can be expected that it will likely be thrown often, as is the case with save.

It is fewer lines of code to check if the return value is false than rescue an exception, so I don't see how it's a problem having to check for the return value if you already have to rescue the exception. How often would an exception thrown by save! ever have to bubble-up the call stack in practice? Rarely, if ever, in my experience.

If there is an exception thrown when calling save as opposed to save! you should want it to show a 500 error page because that's what happened: an unrecoverable, unknown, unexpected internal server error.

Solution 3 - Ruby on-Rails-3

Suggestion: use save when it's on the last line; save! otherwise.

The idea: if the method is returning the save's result you should not throw exception and let the caller to handle save problems, but if the save is buried inside model method logic you would want to abort the process with an exception in case of failure.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionZabbaView Question on Stackoverflow
Solution 1 - Ruby on-Rails-3SelvamaniView Answer on Stackoverflow
Solution 2 - Ruby on-Rails-3Andrew MarshallView Answer on Stackoverflow
Solution 3 - Ruby on-Rails-3gamlielaView Answer on Stackoverflow