ActiveRecord::MissingAttributeError: missing attribute — a bug or a feature?
Sooner or later, the need arises to assign default values to model attributes. In rails this is usually done in model’s after_initialize() with a new_record? guard.
Something like:
class User def after_initialize if new_record? self.country = "US" end end end
This initializes the object with proper default so the UI form gets properly populated and the database gets proper default if user hasn’t overridden it.
Sometimes, you realize that you have (pre-existing?) objects in database that also need the same default if the current value is nil. In such case, you may modify your initializer like this:
class User def after_initialize self.country ||= "US" end end
This works for both scenarios: User.new and User.find.
However, it introduces a behavior that may not be apparant immediately.
$ script/console ree> User.find(u.id) User Load (0.9ms) SELECT * FROM `users` WHERE (`users`.`id` = 1) ree> User.exists?(:id => u.id) RateSearch Load (0.6ms) SELECT `users`.id FROM `users` WHERE (`users`.`id` = 1) LIMIT 1 ActiveRecord::MissingAttributeError: missing attribute: country /[prj]/app/models/User.rb:3:in `after_initialize'
A closer look reveals that ActiveRecord tries to be smart and only fetch ‘id’ column when performing Model.exists? call.
Many people have tripped this and logged it as a bug. The report has been silently ignored, and I believe, for good/performance reasons.
So, what do we get around it? Here’s one way.
class User def after_initialize self.country ||= "US" rescue ActiveRecord::MissingAttributeError # this should only happen on Model.exists?() call. It can be safely ignored. end end
As they say, it is not a bug, it is a feature.
No related posts.
Related posts brought to you by Yet Another Related Posts Plugin.






Thanks for the help. In the latest rails release the exception has been moved to the ActiveModel class though.
ActiveModel::MissingAttributeError
Ryan
11 Apr 11 at 11:46 pm
I think you mean ActiveModel::MissingAttributeError – ActiveRecord::MissingAttributeError isn’t defined.
Jason
12 Feb 12 at 8:14 pm
Bug or feature, it still doesn’t follow the priniciple of least surprise. What a gotcha, at least the first time you experience it!
Nathan
8 Nov 12 at 11:28 am
This should be done with an if statement check on the presence of attributes["country"] since catching the exception in this case will be relatively slow if you are generating thousands of objects. See: http://www.simonecarletti.com/blog/2010/01/how-slow-are-ruby-exceptions/
Nathan woodhull
14 Nov 12 at 12:35 pm