Reputation: 2124
For example, if I run test.update_attributes prop1: 'test', prop2: 'test2'
when prop1
and prop2
have validations that prevent those values, test.prop1
will still be 'test'
and test.prop2
will still be 'test2'
. Why is this happening and how can I fix it?
Upvotes: 0
Views: 870
Reputation: 5398
This is working as designed. For example the update
controller method usually looks like this:
def update
@test = Test.find(params[:id])
if @test.update(test_attributes)
# redirect to index with success messsage
else
render :edit
end
private
def test_attributes
# params.require here
end
end
The render :edit
will then re-display the form with an error message and the incorrect values filled in for the user to correct. So you actually do want the incorrect values to be available in the model instance.
Upvotes: 0
Reputation: 574
Try wrapping it in an if-statement:
if test.update(test_params)
# your code here
else
# your code here
end
Upvotes: 0
Reputation: 2124
According to the Rails docs for update_attributes
, it's an alias of update
. Its source is as follows:
# File activerecord/lib/active_record/persistence.rb, line 247
def update(attributes)
# The following transaction covers any possible database side-effects of the
# attributes assignment. For example, setting the IDs of a child collection.
with_transaction_returning_status do
assign_attributes(attributes)
save
end
end
So, it's wrapped in a DB transaction which is why the rollback happens. However, let's check out assign_attributes
. According to its source:
# File activerecord/lib/active_record/attribute_assignment.rb, line 23
def assign_attributes(new_attributes)
...
_assign_attribute(k, v)
...
end
That is defined as:
# File activerecord/lib/active_record/attribute_assignment.rb, line 53
def _assign_attribute(k, v)
public_send("#{k}=", v)
rescue NoMethodError
if respond_to?("#{k}=")
raise
else
raise UnknownAttributeError.new(self, k)
end
end
So, when you call test.update_attributes prop1: 'test', prop2: 'test'
, it basically boils down to:
test.prop1 = 'test'
test.prop2 = 'test'
test.save
If save
fails the validations, our in-memory copy of test
still has the modified prop1
and prop2
values. Hence, we need to use test.reload
and the issue is resolved (i.e. our DB and in-memory versions are both unchanged).
tl;dr Use test.reload
after the failed update_attributes
call.
Upvotes: 1