This project is archived and is in readonly mode.

#6127 ✓resolved
Kai Schlamp

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

SELECT grids.id FROM grids WHERE (grids.token = BINARY 'mkp8ae2qbq') LIMIT 1
where token is not selected.

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

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>

Referenced by

Pages