Question
Rails update_attributes Without Saving: How to Assign Multiple Attributes First
Question
In Rails, is there an alternative to update_attributes that updates multiple fields without immediately saving the record?
For example, I want to do something like this:
@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
I know I can assign each field individually, such as:
@car.model = 'Sierra'
But I want to update several attributes in a single line and save the record later.
Short Answer
By the end of this page, you will understand how to set multiple Active Record attributes in Rails without saving immediately. You will learn when to use assign_attributes, how it differs from update/update_attributes, and how this pattern is used in real Rails applications before a final save or save!.
Concept
In Rails, some Active Record methods change attributes and save right away, while others only change the object in memory.
This distinction matters because there are many situations where you want to:
- prepare an object gradually
- run extra logic before saving
- validate later
- combine changes from multiple sources
- avoid writing to the database too early
The method update_attributes was commonly used in older Rails versions to update fields and save immediately. In modern Rails, update is the preferred name, but the behavior is the same: it assigns attributes and then attempts to save the record.
If you want to assign several attributes at once without saving yet, use:
assign_attributes
This updates the model instance in memory only. The database is not touched until you call save or save!.
Example:
car = Car.new(make: 'GMC')
car.assign_attributes(model: 'Sierra', year: '2012')
# not saved yet
car.save
Why this matters in real programming:
- You may need to build an object in stages.
- You may want to inspect or modify data before saving.
- You may want a single save operation after multiple changes.
- You may want validations to run only once at the end.
So the key idea is:
assign_attributes= set many attributes now, save laterupdate/update_attributes= set many attributes and save immediately
Mental Model
Think of an Active Record object like a paper form on your desk.
assign_attributesmeans fill in several fields on the form, but do not submit it yet.savemeans submit the form to the database.updatemeans fill in the fields and submit immediately.
So if you are still reviewing the form, adding more information, or checking for mistakes, assign_attributes is the right tool.
Syntax and Examples
The core syntax is:
record.assign_attributes(attribute_name: value, another_attribute: value)
Then save later:
record.save
Example 1: Basic usage
car = Car.new(make: 'GMC')
car.assign_attributes(model: 'Sierra', year: '2012', color: 'Black')
puts car.model
# => "Sierra"
puts car.persisted?
# => false
car.save
Explanation:
Car.new(make: 'GMC')creates a new object in memory.assign_attributes(...)sets multiple fields at once.- The record is still not saved after assignment.
savewrites it to the database.
Example 2: Existing record
car = Car.find(1)
car.assign_attributes(model: 'Sierra', year: '2012')
# database still unchanged here
car.save
This also works for an existing record. Rails marks the changed fields as dirty, but does not persist them until save.
Example 3: Compare with update
car = Car.find(1)
car.update(model: 'Sierra', year: '2012')
This assigns the values and immediately attempts to save.
Older alias
In older Rails code, you may see:
car.attributes = { model: 'Sierra', year: '2012' }
This also assigns attributes without saving. In many codebases, assign_attributes is clearer and more explicit.
Step by Step Execution
Consider this example:
car = Car.new(make: 'GMC')
car.assign_attributes(model: 'Sierra', year: '2012')
car.year = '2013'
car.save
Step by step:
-
car = Car.new(make: 'GMC')- A new
Carobject is created in memory. makeis set to"GMC".- Nothing is saved to the database yet.
- A new
-
car.assign_attributes(model: 'Sierra', year: '2012')modelbecomes"Sierra".yearbecomes"2012".- The database is still untouched.
-
car.year = '2013'- The in-memory value of
yearchanges from"2012"to"2013". - Still not saved yet.
- The in-memory value of
-
car.save- Rails runs validations.
- If valid, Rails inserts or updates the database row.
- The saved value for
yearwill be"2013".
The important lesson is that all assignments made before save are just preparing the object. Only save persists them.
Real World Use Cases
Here are common cases where assigning attributes without saving is useful:
Multi-step form flow
A user fills out part of a form first, then additional details later.
@car.assign_attributes(step_one_params)
@car.assign_attributes(step_two_params)
@car.save
Data normalization before save
You receive user input, then clean it up before persisting it.
@car.assign_attributes(car_params)
@car.model = @car.model.strip.titleize
@car.save
Applying defaults or business rules
@car.assign_attributes(car_params)
@car.year ||= Time.current.year
@car.save
Combining values from different sources
For example, some values come from the form and others from an external API.
@car.assign_attributes(car_params)
@car.assign_attributes(vin_data)
@car.save
Validate before final persistence
@car.assign_attributes(car_params)
if @car.valid?
# do more work
@car.save
end
Real Codebase Usage
In real Rails projects, developers often use this pattern when they want clearer control over when saving happens.
Pattern: build, enrich, save
car = Car.new
car.assign_attributes(car_params)
car.user = current_user
car.slug = car.model.parameterize
car.save
This is common when some attributes come from the request and others come from application logic.
Pattern: guard clauses before saving
car.assign_attributes(car_params)
return false unless car.valid?
return false unless policy(car).update?
car.save
The object is prepared first, then saved only if all checks pass.
Pattern: service objects
class UpdateCarProfile
def initialize(car, attrs)
@car = car
@attrs = attrs
end
def call
@car.assign_attributes(@attrs)
@car.last_reviewed_at = Time.current
@car.save
end
end
This keeps business logic organized and avoids accidental early database writes.
Pattern: error handling with save!
car.assign_attributes(car_params)
car.save!
Use save! when you want Rails to raise an exception if saving fails.
Pattern: transactional workflows
Car.transaction do
car.assign_attributes(car_params)
car.save!
AuditLog.create!(action: 'car_updated', record: car)
end
This is useful when saving the model is only one part of a larger operation.
Common Mistakes
Mistake 1: Using update when you do not want to save yet
Broken example:
car.update(model: 'Sierra', year: '2012')
# This already attempted to save
Why it is a problem:
- The database may be updated earlier than intended.
- Validations run immediately.
- Callbacks may run immediately.
Use this instead:
car.assign_attributes(model: 'Sierra', year: '2012')
Mistake 2: Forgetting to call save
car.assign_attributes(model: 'Sierra')
# no save
If the object is never saved, the database will not change.
Mistake 3: Assuming in-memory changes are already persisted
car.assign_attributes(model: 'Sierra')
puts car.model
# => "Sierra"
Seeing the new value in Ruby does not mean it is stored in the database yet.
Mistake 4: Confusing save and save!
car.save
savereturnstrueorfalsesave!raises an exception on failure
If you need failure to be loud and explicit, use save!.
Mistake 5: Using deprecated style without knowing your Rails version
Older tutorials may use update_attributes. In newer Rails versions, update is preferred.
Mistake 6: Passing untrusted params directly
In controllers, use strong parameters.
@car.assign_attributes(params[:car])
Avoid doing this directly. Prefer:
@car.assign_attributes(car_params)
Comparisons
| Method | Assigns attributes? | Saves immediately? | Raises on failure? | Typical use |
|---|---|---|---|---|
assign_attributes | Yes | No | No | Prepare changes before saving |
attributes= | Yes | No | No | Older or alternative assignment syntax |
update | Yes | Yes | No | Change and save in one step |
update! | Yes | Yes | Yes | Change and save, fail loudly |
save | No | Yes | No | Persist current in-memory changes |
save! | No | Yes | Yes | Persist current changes, fail loudly |
assign_attributes vs individual setters
car.model = 'Sierra'
car.year = '2012'
vs
car.assign_attributes(model: 'Sierra', year: '2012')
Both are valid. assign_attributes is cleaner when updating many fields together.
assign_attributes vs update
- Use
assign_attributeswhen you want to save later. - Use
updatewhen you want a single operation that assigns and persists immediately.
Cheat Sheet
# Assign many attributes without saving
car.assign_attributes(model: 'Sierra', year: '2012')
# Save later
car.save
# Save later and raise on failure
car.save!
# Assign and save immediately
car.update(model: 'Sierra', year: '2012')
# Assign and save immediately, raising on failure
car.update!(model: 'Sierra', year: '2012')
# Older alternative assignment syntax
car.attributes = { model: 'Sierra', year: '2012' }
Quick rules:
assign_attributeschanges the Ruby object only.savewrites pending changes to the database.updateassigns and saves in one step.update_attributesis older naming;updateis preferred in modern Rails.- Use strong parameters in controllers.
- Use
save!orupdate!when you want exceptions on failure.
Useful check:
car.changed?
This tells you whether the model has unsaved changes.
FAQ
What is the Rails method to update attributes without saving?
Use assign_attributes. It sets multiple fields on the model instance without persisting them until you call save.
Does update_attributes save the record in Rails?
Yes. update_attributes assigns the values and immediately attempts to save the record. In newer Rails versions, update is the preferred method name.
What is the difference between assign_attributes and update in Rails?
assign_attributes only changes the object in memory. update changes the object and saves it to the database right away.
Can I use attributes= instead of assign_attributes?
Yes. attributes= also assigns multiple attributes without saving. However, assign_attributes is often clearer to read.
Will validations run when I call assign_attributes?
No, not by themselves. Validations normally run when you call save, save!, update, or valid?.
How do I know whether the record has unsaved changes?
Use Rails dirty tracking methods such as:
car.changed?
This returns whether any attributes were modified but not yet saved.
Should I use save or save! after assign_attributes?
Use save if you want a true/false result. Use save! if you want an exception raised when the record is invalid or saving fails.
Mini Project
Description
Build a small Rails-style example that prepares a Car object in stages before saving it. This demonstrates how to assign multiple attributes on one line, apply extra logic, and then persist the final version only once.
Goal
Create and modify a Car record using assign_attributes, then save it after additional processing.
Requirements
- Create a new
Carobject with an initial attribute. - Assign multiple additional attributes in one line without saving immediately.
- Modify at least one attribute again before saving.
- Check whether the object has unsaved changes.
- Save the object at the end.
Keep learning
Related questions
Add a Default Value to an Existing Column in a Rails Migration
Learn how to add or change a default value on an existing database column using Rails Active Record migrations safely.
Calling a Class Method from an Instance in Ruby
Learn how to call a class method from an instance in Ruby using self.class, with examples, pitfalls, and practical usage patterns.
Calling an Overridden Monkey-Patched Method in Ruby
Learn how to call the original method when monkey patching in Ruby, including alias_method patterns, examples, pitfalls, and practical usage.