Updating attributes in Rails
When I save data in Rails, I continually misuse the different methods available, so that my code is sprinkled with
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
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!() behave just like
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
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.
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)
I can have:
Which is also the same as:
So to summarize:
Use validations where I can;
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
update_attributes and always inside a block.