Strange behaviour in Unit Test


#1

Hi,

I’m having a weird problem in one of my unit tests.

this code generates an assertion error on the second line

assert !@valid_category.update_attributes(:name => nil)
assert_equal old_name, @valid_category.name

However, when I write the following, the error is no more…

assert !@valid_category.update_attributes(:name => nil)
@valid_category.reload
assert_equal old_name, @valid_category.name

This sure can’t be normal? I tried to write out the name of the
@valid_category between the 2 lines, and its empty.

Another question:
Is it correct that the update_attribute method bypasses validation?
According to the API this is the fact, but why would that be, updates
should also be valid??

Thanks!

Joram


#2

That is normal behavior. #update_attributes actually does update the
attributes, but returns on whether the save to the database was
successful
or not. One reason it’s done this way is to allow for field re-filling
on
forms when there are errors in the form.

Jason


#3

Sorry, hit the send button too quickly. As to your second question,
update_attributes does not bypass validations. Nothing in AR bypasses
the
validations unless you specifically tell it to do so.

Jason


#4

Thanks for the information, Jason, it does make sense to me now.

About the validation, I found this in the API:

"update_attribute(name, value)

Updates a single attribute and saves the record. This is especially
useful for boolean flags on existing records. Note: This method is
overwritten by the Validation module that’ll make sure that updates
made with this method doesn’t get subjected to validation checks.
Hence, attributes can be updated even if the full object isn’t valid.
"

I’m getting an MySql exception when I use this method, stating that I
want to insert a null value into a column where null is not allowed.


#5

I’m getting an MySql exception when I use this method, stating that I
want to insert a null value into a column where null is not allowed.

Yes, update_attribute does bypass validation. You are getting an
error because of a null restriction on the column in MySQL. If it
wasn’t for that the nil name would have persisted. Only use update
attribute if you don’t want validations to run.

Aaron


#6

assert !@valid_category.update_attributes(:name => nil)
assert_equal old_name, @valid_category.name

When an update fails validation the changes that you made are still in
memory, they just don’t persist to the database. Think about when you
fill out a form, click submit, and an validation error occurs. All
the values you entered are returned and populate the form so you don’t
have to enter them again.

@valid_category.valid? => tells you if the current version is valid
puts @valid_category.errors.inspect => to see the validation errors

You can even do something like this to check that the error you
expected occurred:
assert_equal( 1, @valid_category.errors.length )
assert_equal( ‘name must have a value’,
@valid_category.errors.on(:name))

assert !@valid_category.update_attributes(:name => nil)
@valid_category.reload
assert_equal old_name, @valid_category.name

This works because reload does exactly that, it reloads
@valid_category with the version from the database. Your
update_attributes failed validation so the database version was left
unchanged.

Aaron


#7

Thank you Aaron and Jason for your quick reply!

It’s all clear to me now :slight_smile: