简体   繁体   中英

Rails ActiveRecord callback messup

This is driving nuts. I have a dead simple callback functions to initialize and validate a class children as such:

class A < ActiveRecord::Base
   has_many :bs
   after_initialize :add_t_instance
   validate :has_only_one_t

  protected

  def add_t_instance
      bs << B.new(:a => self, :type => "T") unless bs.map(&:type).count("T") > 0
  end

  def has_only_one_t
     unless bs.map(&:type).count("T") < 2
       errors.add(:bs, 'has too many Ts")
     end
  end

end

and now, here comes the magic at runtime:

a = A.new
>>[#<A>]
a.bs
>> [#<T>]
a.save
>> true
a.id
>> 15

so far it's all going great, but:

s = A.find(15)
s.bs
>>[#<T>,#<T>]
s.bs.count
>> 2
s.valid?
>> false
s.errors.full_messages
>> "Too many Ts"

What the heck am I missing here?!?! What in the world could be adding the second #T?

Confusingly (to me at least) after_initialize is called whenever an active record object is instantiated, not only after creating a new instance, but also after loading an existing one from the database. So you create the second B when you run A.find(15) .

You could solve the problem by checking whether you are dealing with a new record in your callback, eg

def add_t_instance
  if new_record?
    bs << B.new(:a => self, :type => "T") unless bs.map(&:type).count("T") > 0
  end
end

or you could place a condition on the before_initialize declaration itself, or perhaps try using a before_create callback.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM