Any difference between save and save!?

26 views
Skip to first unread message

Andrew Newman

unread,
May 20, 2013, 3:27:01 AM5/20/13
to rails-...@googlegroups.com
Hi,

I've been recently been trying to track down a bug that I think is caused by the following code:

Job.transaction do
  job = Job.new
  if job.save
    render status: :ok
  else
    render status: :conflict
  end
end

Is there any important difference (semantically) between that code and the following:

begin
  Job.transaction do
    job = Job.new
    job.save!
    render status: :ok
  end
rescue
  render status: :conflict
end

It seems to me that both approaches won't save to the database unless the validations run successfully.  The only difference I can see in the database log is that the former does a RELEASE SAVEPOINT and the later a ROLLBACK TO SAVEPOINT (when the validations fail).

I'm getting invalid models in the database (Job.find(123).valid? -> false) and I'm pretty sure this is the only code path that creates those models.

Paul Annesley

unread,
May 20, 2013, 3:53:20 AM5/20/13
to rails-...@googlegroups.com
I can't see how either would persist an invalid record.

What database system and table storage engine are you using?
i.e. it's not MySQL + MyISAM, right? Right?

That shouldn't matter, anyway; AR won't attempt to INSERT if the record is invalid.

Your validations don't have `:on => :update` or similar clauses, do they?

The save! bang-method doesn't add much complexity over plain save:

lib/active_record/attribute_methods/dirty.rb
40: def save!(*)
41- super.tap do
42- @previously_changed = changes
43- @changed_attributes.clear
44- end
45- end

lib/active_record/persistence.rb
121: def save!(*)
122- create_or_update || raise(RecordNotSaved)
123- end

lib/active_record/transactions.rb
274: def save!(*) #:nodoc:
275- with_transaction_returning_status { super }
276- end

lib/active_record/validations.rb
56: def save!(options={})
57- perform_validations(options) ? super : raise(RecordInvalid.new(self))
58- end

— Paul

Jon Rowe

unread,
May 20, 2013, 4:07:41 AM5/20/13
to rails-...@googlegroups.com
Probably not related (and you may have simplified your code sample) but that naked rescue clause will rescue all errors and display the conflict page in cases where save might have succeeded but something else has failed…

Do you have callbacks or that could be doing something on save that is being interrupted by the error of a save! ?

Jon Rowe
-----------------------------

--
You received this message because you are subscribed to the Google Groups "Ruby or Rails Oceania" group.
To unsubscribe from this group and stop receiving emails from it, send an email to rails-oceani...@googlegroups.com.
To post to this group, send email to rails-...@googlegroups.com.

Andrew Newman

unread,
May 20, 2013, 5:31:39 AM5/20/13
to rails-...@googlegroups.com
Thanks. I think this is just a case of a missing database constraint (relying on validators only).

Daniel Tsui

unread,
May 21, 2013, 3:04:39 AM5/21/13
to rails-...@googlegroups.com
I believe save! raises an exception and save without bang doesn't, which may be relevant if you want your transaction to rollback?
Reply all
Reply to author
Forward
0 new messages