Is there an alternative to update_attributes that does not save the record?
So I could do something like:
@car = Car.new(:make => 'GMC')
#other processing
@car.update_attributes(:model => 'Sierra', :year => "2012", :looks => "Super Sexy, wanna make love to it")
#other processing
@car.save
BTW, I know I can @car.model = 'Sierra'
, but I want to update them all on one line.
For mass assignment of values to an ActiveRecord model without saving, use either the
assign_attributes
orattributes=
methods. These methods are available in Rails 3 and newer. However, there are minor differences and version-related gotchas to be aware of.Both methods follow this usage:
Note that neither method will perform validations or execute callbacks; callbacks and validation will happen when
save
is called.Rails 3
attributes=
differs slightly fromassign_attributes
in Rails 3.attributes=
will check that the argument passed to it is a Hash, and returns immediately if it is not;assign_attributes
has no such Hash check. See the ActiveRecord Attribute Assignment API documentation forattributes=
.The following invalid code will silently fail by simply returning without setting the attributes:
attributes=
will silently behave as though the assignments were made successfully, when really, they were not.This invalid code will raise an exception when
assign_attributes
tries to stringify the hash keys of the enclosing array:assign_attributes
will raise aNoMethodError
exception forstringify_keys
, indicating that the first argument is not a Hash. The exception itself is not very informative about the actual cause, but the fact that an exception does occur is very important.The only difference between these cases is the method used for mass assignment:
attributes=
silently succeeds, andassign_attributes
raises an exception to inform that an error has occurred.These examples may seem contrived, and they are to a degree, but this type of error can easily occur when converting data from an API, or even just using a series of data transformation and forgetting to
Hash[]
the results of the final.map
. Maintain some code 50 lines above and 3 functions removed from your attribute assignment, and you've got a recipe for failure.The lesson with Rails 3 is this: always use
assign_attributes
instead ofattributes=
.Rails 4
In Rails 4,
attributes=
is simply an alias toassign_attributes
. See the ActiveRecord Attribute Assignment API documentation forattributes=
.With Rails 4, either method may be used interchangeably. Failure to pass a Hash as the first argument will result in a very helpful exception:
ArgumentError: When assigning attributes, you must pass a hash as an argument.
Validations
If you're pre-flighting assignments in preparation to a
save
, you might be interested in validating before save, as well. You can use thevalid?
andinvalid?
methods for this. Both return boolean values.valid?
returns true if the unsaved model passes all validations or false if it does not.invalid?
is simply the inverse ofvalid?
valid?
can be used like this:This will give you the ability to handle any validations issues in advance of calling
save
.I believe what you are looking for is
assign_attributes
.It's basically the same as update_attributes but it doesn't save the record:
You can use
assign_attributes
orattributes=
(they're the same)Update methods cheat sheet (for Rails 4):
update_attributes
=assign_attributes
+save
attributes=
= alias ofassign_attributes
update
= alias ofupdate_attributes
Source:
https://github.com/rails/rails/blob/master/activerecord/lib/active_record/persistence.rb
https://github.com/rails/rails/blob/master/activerecord/lib/active_record/attribute_assignment.rb
Another cheat sheet:
http://www.davidverhasselt.com/set-attributes-in-activerecord/#cheat-sheet
You can use the 'attributes' method:
Source: http://api.rubyonrails.org/classes/ActiveRecord/Base.html
attributes=(new_attributes, guard_protected_attributes = true) Allows you to set all the attributes at once by passing in a hash with keys matching the attribute names (which again matches the column names).
If guard_protected_attributes is true (the default), then sensitive attributes can be protected from this form of mass-assignment by using the attr_protected macro. Or you can alternatively specify which attributes can be accessed with the attr_accessible macro. Then all the attributes not included in that won’t be allowed to be mass-assigned.