Updating attributes in Rails
When I save data in Rails, I continually misuse the different methods available, so that my code is sprinkled with save
, save!
, save(false)
, update_attribute
, update_attributes
and so on. I also often introduce bugs by assigning a new value to an attribute and then forgetting to update it.
So, here is a quick summary.
save
is the one to use if I want my model to validate. And, by the way, it is well worth using validations, like validates_presence_of
, to check that an assignment hasn’t been forgotten somewhere. save
is used most commonly in the create
method of a controller where errors are likely to be handled by the view
code.
save!
works like save
except that it raises an ActiveRecord::RecordInvalid
exception suitable for use in a rescue
clause. In other words, the only context in which to use save!
is this one:
begin
thing.save!
rescue RecordInvalid => error
# do something
end
It is likely to be used outside the controller (i.e. in the model) where I should want to do something sensible if any validations fail.
save(false)
, on the other hand, provides no validations at all and should only be used if I am absolutely sure about the data I am saving or perhaps if I am saving several records together and want to speed things up a bit (and am feeling reckless).
update_attributes()
and update_attributes!()
behave just like save
and save!
respectively, but accept a hash of attributes as an argument so allow assignments to multiple attributes and saving all in a single line. update_attributes
is most commonly used when updating a model from within a controller.
update_attribute()
, as the name implies, just updates a single attribute and bypasses validations; a sensible choice if a single attribute—such as a boolean flag on an existing record—is being updated.
Note that behind the scenes update_attribute
uses save(false)
, so that it is not a great idea to use it if I am likely to have other attributes awaiting update.
Incidentally, if I am updating a boolean and know that I just want its state to change, then it might be worth using toggle(name)
instead of update_attribute(name, value)
, which might save a line or two of code.
Also, update(id, attributes)
combines the reading of a row and the updating of its attributes onto a single line, so that instead of:
thing = Thing.find(id)
thing.update_attributes(attributes)
I can have:
Thing.update(id, attributes)
Which is also the same as:
Thing.find(id).update_attributes(attributes)
So to summarize:
Use validations where I can;
Only use save(false)
for performance reasons, not to be lazy;
Beware of using update_attribute
in any context where more than one attribute is being updated;
Outside controllers, use the bang! versions of save
and update_attributes
and always inside a block.