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.idFROMgridsWHERE (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 AMOops, 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 AMUntil 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? endUnfortunately 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 PMI 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 [827e5de60f27c6b559640eda7b79857050a72d9e])
Change ...
- 
         6127 
          after_initialize may lead to missing attribute when used with uniqueness validation
        (from [b155fdadf334cff32a7e648c86c3c97f2f51257f])
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. 3165 
          ActiveRecord::MissingAttributeError after update to rails v 2.3.4
        This has finally been resolved in Rails 3.0.7 by 
#6127.
 alindeman
      alindeman
 Carl Youngblood
      Carl Youngblood
 Corey Ward
      Corey Ward