When do I use save!, create! and update_attributes! in Rails?

62,917

Solution 1

Generally you want to use the non-bang versions in your controllers. This allows logic like this:

def update
  @model = Model.find params[:id]
  if @model.update_attributes params[:model] #returns true of false
     # handle success
  else
     # handle failure
  end
end

I find myself using the bang versions a lot in tests when I want to make sure I know if something doesn't validate, and isn't saved. I've definitely wasted time debugging tests that were failing because of changed model validations, which would be obvious if I used the bang versions.

e.g.

it "should do something" do
   m = Model.create! :foo => 'bar' # will raise an error on validation failure             
   m.should do_something
end

In terms of not having invalid data in the database, you should be handling this with ActiveRecord validations (e.g. validates_presence_of :user_id), or defining your own validate method in the model. (http://api.rubyonrails.org/classes/ActiveRecord/Validations/ClassMethods.html) This should prevent saves from occurring if your data isn't valid. If you're really paranoid you can add some constraints to your database. Check the ActiveRecord::Migration docs for how to set up unique indexes and other database constraints in your migrations.

Also in my experience you want to avoid using any custom save or create method whenever possible. If you re-implement functionality included in ActiveRecord you end up paying a price down the road. http://matthewpaulmoore.com/post/5190436725/ruby-on-rails-code-quality-checklist has more to say on this.

Solution 2

The main difference is how failed saves are handled. When updating an ActiveRecord class the ! version will raise an exception if the record is invalid.

I recommend reading the docs here - http://api.rubyonrails.org/classes/ActiveRecord/Base.html

Using transactions might also be something worth looking into - http://api.rubyonrails.org/classes/ActiveRecord/Transactions/ClassMethods.html

Solution 3

What ! (bang) means for update_attributes and save is:

"Raise an exception upon failure" rather than "Return false upon failure"

https://api.rubyonrails.org/classes/ActiveRecord/Persistence.html#method-i-update-21 https://api.rubyonrails.org/classes/ActiveRecord/Persistence.html#method-i-save

What ! (bang) means for create is:

"Raise an exception upon failure" rather than "Return the resulting object upon failure" https://api.rubyonrails.org/classes/ActiveRecord/Persistence/ClassMethods.html#method-i-create-21

Share:
62,917
CalebHC
Author by

CalebHC

I'm a programmer from Earth...

Updated on July 05, 2022

Comments

  • CalebHC
    CalebHC almost 2 years

    I'm trying to figure out when to use the bang! versions for saving and updating records? I've read and heard that you don't need them if you're just saving one record or updating a single attribute, if you're confident nothing should go wrong, or to always use them outside of a controller. I guess I'm paranoid about having multiple things getting saved then something fails then there is incomplete data in the DB. The current Rails project I'm working on is over 50% complete and currently doesn't contain any bangs. I have some custom methods I'm calling in models that update or create multiple records and worry if they should be in some sort of transaction.

    Sorry if this seems scattered but I'm just trying to figure how to use the saving capabilities in ActiveRecord correctly and make my life easier and little more stress free in the end. Thanks for your time.

  • ifightcrime
    ifightcrime about 11 years
    Great for pointing the key difference between the two, unlike the selected answer.
  • ki4jnq
    ki4jnq over 9 years
    Thanks for pointing to the use of transactions, they often seem overlooked.
  • NM Pennypacker
    NM Pennypacker over 7 years
    +1. Might also be worth noting that the non-bang methods will silently fail in transactions, so always use save!, update_attributes!, etc. when your code is wrapped in a transaction.
  • Magne
    Magne over 6 years
    @NickM So that the transaction is automatically rolled back, I presume? Whilst the silent failure will make it go through?
  • NM Pennypacker
    NM Pennypacker over 6 years
    @Magne Yep, if the exception isn't raised the transaction will still complete
  • SMAG
    SMAG over 2 years
    update! is wrapped in a transaction at it's source