Skip to content →

ActiveRecord Coerces Values Set with #id= into Fixnum

I found a bug in my code today that stems from my not remembering that ActiveRecord::Base will try to coerce values set on its attributes into whatever type is defined in the DB. Specifically I got burned by #id= coercing a String into a Fixnum. Check this out:

Not only is the type of object changed by setting the attribute but the leading zero is lost. Luckily my specs caught this.

I know, I know it’s a bad idea to set #id yourself. You should let ActiveRecord do that for you. In my case I was trying to cleverly avoid manipulating incoming attributes before assignment. The API I’m working with returns JSON records that have their own id field (probably a common case). I was mass assigning these attributes to a new ActiveRecord object and letting a callback, before validation, move the API id from #id into #api_id.

I thought it was safe because A) the only time #id would appear in #changes would be after an API mass assignment and B) I just assumed that because these are brand new Ruby objects that they would behave as such and not care about the type of object that is set on an attribute (at least while it is still a #new_record?) . Obviously I was wrong and this was a bad idea. I double checked the ActiveRecord docs and there is no mention of type coercion. While doing so I came across #id_before_type_cast and discovered its useful behavior:

Good to know, but still better to just avoid using #id=.

Got questions or feedback? I want it. Drop your thoughts in the comments below or hit me @ccstump. You can also follow me on Twitter to be aware of future articles.

Thanks for reading!

 

Published in dev

Comments

Leave a Reply

Your email address will not be published. Required fields are marked *