This project is archived and is in readonly mode.
after_initialize may lead to missing attribute when used with uniqueness validation
Reported by Kai Schlamp | December 7th, 2010 @ 10:18 PM
Under some special circumstances an after_initialize callback may lead to a missing attribute exception when combined with a uniqueness validation.
A not so uncommon scenario:
class MyModel < ActiveRecord::Base after_initialize :init_token validates :token, :uniqueness => true def init_token if self.token.blank? self.token = rand(999999) # just for demo end end end
MyModel has only a token column (String) in the database.
Now when doing the following:
m1 = MyModel.create m2 = MyModel.new m2.token = m1.token m2.valid? # calls init_token again and throws the below exception.
missing attribute: token
is because of the last
find_by_sql
that does a
SELECTwhere token is not selected.grids
.id
FROMgrids
WHERE (grids
.token
= BINARY 'mkp8ae2qbq') LIMIT 1
I am not sure if it is that good at all that a
valid?
call ends up in a instantiation of a new record
and calling the initialize callbacks.
Could it not just check the row without a new instantiation?
ActiveModel::MissingAttributeError: missing attribute: token from /home/zeus/projects/myproject/app/models/my_model.rb:9:in `init_token' from /home/zeus/.rvm/gems/ruby-1.8.7-p302@rails/gems/activesupport-3.0.3/lib/active_support/callbacks.rb:415:in `_run_initialize_callbacks' from /home/zeus/.rvm/gems/ruby-1.8.7-p302@rails/gems/activerecord-3.0.3/lib/active_record/base.rb:1453:in `init_with' from /home/zeus/.rvm/gems/ruby-1.8.7-p302@rails/gems/activerecord-3.0.3/lib/active_record/base.rb:909:in `instantiate' from /home/zeus/.rvm/gems/ruby-1.8.7-p302@rails/gems/activerecord-3.0.3/lib/active_record/base.rb:467:in `find_by_sql' from /home/zeus/.rvm/gems/ruby-1.8.7-p302@rails/gems/activerecord-3.0.3/lib/active_record/base.rb:467:in `collect!' from /home/zeus/.rvm/gems/ruby-1.8.7-p302@rails/gems/activerecord-3.0.3/lib/active_record/base.rb:467:in `find_by_sql' from /home/zeus/.rvm/gems/ruby-1.8.7-p302@rails/gems/activerecord-3.0.3/lib/active_record/relation.rb:64:in `to_a' from /home/zeus/.rvm/gems/ruby-1.8.7-p302@rails/gems/activerecord-3.0.3/lib/active_record/relation/finder_methods.rb:333:in `find_first' from /home/zeus/.rvm/gems/ruby-1.8.7-p302@rails/gems/activerecord-3.0.3/lib/active_record/relation/finder_methods.rb:122:in `first' from /home/zeus/.rvm/gems/ruby-1.8.7-p302@rails/gems/activerecord-3.0.3/lib/active_record/relation/finder_methods.rb:180:in `exists?' from /home/zeus/.rvm/gems/ruby-1.8.7-p302@rails/gems/activerecord-3.0.3/lib/active_record/validations/uniqueness.rb:39:in `validate_each' from /home/zeus/.rvm/gems/ruby-1.8.7-p302@rails/gems/activemodel-3.0.3/lib/active_model/validator.rb:154:in `validate' from /home/zeus/.rvm/gems/ruby-1.8.7-p302@rails/gems/activemodel-3.0.3/lib/active_model/validator.rb:151:in `each' from /home/zeus/.rvm/gems/ruby-1.8.7-p302@rails/gems/activemodel-3.0.3/lib/active_model/validator.rb:151:in `validate' from /home/zeus/.rvm/gems/ruby-1.8.7-p302@rails/gems/activesupport-3.0.3/lib/active_support/callbacks.rb:314:in `send' from /home/zeus/.rvm/gems/ruby-1.8.7-p302@rails/gems/activesupport-3.0.3/lib/active_support/callbacks.rb:314:in `_callback_before_1265' from /home/zeus/.rvm/gems/ruby-1.8.7-p302@rails/gems/activesupport-3.0.3/lib/active_support/callbacks.rb:414:in `_run_validate_callbacks' from /home/zeus/.rvm/gems/ruby-1.8.7-p302@rails/gems/activemodel-3.0.3/lib/active_model/validations.rb:212:in `run_validations!' from /home/zeus/.rvm/gems/ruby-1.8.7-p302@rails/gems/activemodel-3.0.3/lib/active_model/validations/callbacks.rb:67:in `run_validations!' from /home/zeus/.rvm/gems/ruby-1.8.7-p302@rails/gems/activesupport-3.0.3/lib/active_support/callbacks.rb:413:in `_run_validation_callbacks' from /home/zeus/.rvm/gems/ruby-1.8.7-p302@rails/gems/activemodel-3.0.3/lib/active_model/validations/callbacks.rb:67:in `run_validations!' from /home/zeus/.rvm/gems/ruby-1.8.7-p302@rails/gems/activemodel-3.0.3/lib/active_model/validations.rb:179:in `valid?' from /home/zeus/.rvm/gems/ruby-1.8.7-p302@rails/gems/activerecord-3.0.3/lib/active_record/validations.rb:55:in `valid?' from (irb):103
Comments and changes to this ticket
-
Carl Youngblood March 2nd, 2011 @ 01:39 AM
Oops, I meant 2.3.8. In my case, activerecord/lib/active_record/base.rb is attempting to call after_initialize on line 1687 for a record that only has an id. The after_initialize method it is calling attempts to set some attributes that aren't present in the record and throws a missing attribute error.
-
John Berry March 25th, 2011 @ 04:07 PM
+1 on this one. Also seeing it in Rails 3.0.5 with a situation very similar to the original poster (validating a column in an after_initialize callback.)
-
Corey Ward March 26th, 2011 @ 04:05 AM
Until this is fixed properly, I'm using the following pattern to work around the issue:
after_initialize :set_defaults def set_defaults self.foo ||= 'bar' unless attributes["foo"].nil? end
Unfortunately this isn't the only case where this error arises when setting defaults. If you use this, try to keep note that you did so that an obscure bug you encounter in a month doesn't waste hours of your time. ;)
-
Repository March 29th, 2011 @ 01:12 PM
- State changed from new to resolved
(from [827e5de60f27c6b559640eda7b79857050a72d9e]) Change exists? so that it doesn't instantiate records [#6127 state:resolved] https://github.com/rails/rails/commit/827e5de60f27c6b559640eda7b798...
-
Repository March 29th, 2011 @ 01:12 PM
(from [b155fdadf334cff32a7e648c86c3c97f2f51257f]) Change exists? so that it doesn't instantiate records [#6127 state:resolved] https://github.com/rails/rails/commit/b155fdadf334cff32a7e648c86c3c...
-
John Berry April 4th, 2011 @ 10:29 PM
I can confirm that that patch fixes our problem with validates_uniqueness_of. Thanks.
Create your profile
Help contribute to this project by taking a few moments to create your personal profile. Create your profile »
<h2 style="font-size: 14px">Tickets have moved to Github</h2>
The new ticket tracker is available at <a href="https://github.com/rails/rails/issues">https://github.com/rails/rails/issues</a>
People watching this ticket
Referenced by
- 6127 after_initialize may lead to missing attribute when used with uniqueness validation (from [827e5de60f27c6b559640eda7b79857050a72d9e]) Change ...
- 6127 after_initialize may lead to missing attribute when used with uniqueness validation (from [b155fdadf334cff32a7e648c86c3c97f2f51257f]) Change ...
- 3165 ActiveRecord::MissingAttributeError after update to rails v 2.3.4 This has finally been resolved in Rails 3.0.7 by #6127.