Strange behaviour in Unit Test

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

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

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

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.

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

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

Thank you Aaron and Jason for your quick reply!

It's all clear to me now :slight_smile: