Rails 3 allows the developer to change ActiveRecord attributes in various ways. Each one does it slightly differently with sometimes unique side-effects. It’s important you understand which method to use, so here’s a cheat sheet. Scroll further down for an explanation of each.
This article was written for Rails 3. Check out the updated Rails 4 version.
Cheat Sheet
Method | Uses Default Accessor | Mass Assignment Protection | Saved to Database | Validations |
---|---|---|---|---|
attribute= | Yes | No | No | n/a |
write_attribute | No | No | No | n/a |
update_attribute | Yes | No | Yes | No |
attributes= | Yes | Yes1 | No | n/a |
update_attributes | Yes | Yes | Yes | Yes |
In Depth
For the following examples we’ll set the name
attribute on the user
object.
user.name = "Rob"
This regular assignment is the most common and easiest to use. It is the default write accessor generated by Rails. The name
attribute will be marked as dirty and the change will not be sent to the database yet.
You can undo the change by calling reload!
or save the change to the database by calling save
.
user.write_attribute(:name, "Rob")
This is the method that is called by the default accessor above. A synonym for this function is user[:name] = "Rob"
. It also has a read_attribute
counterpart.
Just like above, this method does not yet change the attribute in the database. Use this method anywhere you need to bypass the default write accessor above, for example when you want to write a custom attribute= writer.
user.update_attribute(:name, "Rob")
This method will change the attribute in the model and pass it straight to the database, without running any validations.
Two gotchas:
- Any other changed attributes are also saved to the database.
- Validations are skipped so you could end up with invalid data.
Because of that last quirk it’s a good practice to use update_attributes
instead.
user.attributes = {name: "Rob"}
This method will set all the attributes you pass it, except those who are protected from mass assignment if you’re using attr_protected
or attr_accessible
. The changes are not saved to the database.
You can override the mass assignment protection by passing false:
user.send(:attributes=, name: "Rob", false)
user.update_attributes(name: "Rob")
This method changes the attributes of the model, checks the validations, and updates the record in the database if it validates. Since it uses the above attributes=
method, attributes protected from mass assignment are not changed.
Note that just like update_attribute
this method also saves other changed attributes to the database.
More
If you want to understand more about these methods I suggest you check out their source code. Each time it’s only a couple of lines and it will really broaden your understanding of how Rails works!
-
Mass Assignment Protection for
attributes=
is overridable. ↩