after_initialize导致堆栈溢出

时间:2009-08-21 05:13:08

标签: ruby-on-rails stack-overflow

尝试DRY,我试图在对象初始化后分配给模型的实例变量。

class WorkNote < ActiveRecord::Base

  def after_initialize
    self[:clockin]= WorkNote.last_clockout
  end

  def self.last_clockout
    WorkNote.find(:first, :order => "clockout DESC").clockout
  end
end

但是,after_initialize中的方法调用会导致SystemStackError

ActiveRecord::StatementInvalid: SystemStackError: stack level too deep: SELECT * FROM "work_notes"  ORDER BY clockout DESC LIMIT 1
    from /Library/Ruby/Gems/1.8/gems/activerecord-2.3.2/lib/active_record/connection_adapters/abstract_adapter.rb:212:in `log'
    from /Library/Ruby/Gems/1.8/gems/activerecord-2.3.2/lib/active_record/connection_adapters/sqlite_adapter.rb:157:in `execute'
    from /Library/Ruby/Gems/1.8/gems/activerecord-2.3.2/lib/active_record/connection_adapters/sqlite_adapter.rb:402:in `catch_schema_changes'
    from /Library/Ruby/Gems/1.8/gems/activerecord-2.3.2/lib/active_record/connection_adapters/sqlite_adapter.rb:157:in `execute'
    from /Library/Ruby/Gems/1.8/gems/activerecord-2.3.2/lib/active_record/connection_adapters/sqlite_adapter.rb:305:in `select'
    from /Library/Ruby/Gems/1.8/gems/activerecord-2.3.2/lib/active_record/connection_adapters/abstract/database_statements.rb:7:in `select_all_without_query_cache'
    from /Library/Ruby/Gems/1.8/gems/activerecord-2.3.2/lib/active_record/connection_adapters/abstract/query_cache.rb:62:in `select_all'
    from /Library/Ruby/Gems/1.8/gems/activerecord-2.3.2/lib/active_record/base.rb:661:in `find_by_sql'
    from /Library/Ruby/Gems/1.8/gems/activerecord-2.3.2/lib/active_record/base.rb:1553:in `find_every'
    from /Library/Ruby/Gems/1.8/gems/activerecord-2.3.2/lib/active_record/base.rb:1510:in `find_initial'
    from /Library/Ruby/Gems/1.8/gems/activerecord-2.3.2/lib/active_record/base.rb:613:in `find'
    from /Users/noob/jobs/app/models/work_note.rb:10:in `last_clockout'
    from /Users/noob/jobs/app/models/work_note.rb:6:in `after_initialize'
    from /Library/Ruby/Gems/1.8/gems/activerecord-2.3.2/lib/active_record/callbacks.rb:347:in `send'
    from /Library/Ruby/Gems/1.8/gems/activerecord-2.3.2/lib/active_record/callbacks.rb:347:in `callback'
    from /Library/Ruby/Gems/1.8/gems/activerecord-2.3.2/lib/active_record/base.rb:1662:in `send'
... 5116 levels...

如果我发表评论after_initialize,则last_clockout方法没有问题。当我使用before_save而不是after_initialize之类的回调时,这种情况也不会发生。为什么after_initialize会导致这种情况?

谢谢!

3 个答案:

答案 0 :(得分:5)

每当对象被实例化(new'ed)时调用initialize。你在self.last_clockout中的find调用是创建一个对象,然后以递归方式调用after_initialize。因此无限递归和堆栈溢出。

Before_saveafter_create更合适。

请参阅http://api.rubyonrails.org/classes/ActiveRecord/Callbacks.html

答案 1 :(得分:1)

我发现default_value_for是一种非常好的方法。

答案 2 :(得分:0)

另一种方法是检查初始化对象是否是新的,例如:

def after_initialize
  return unless self.new_record?
  self.clockin = WorkNote.last_clockout
end