after_initialize вызывает переполнение стека - PullRequest
1 голос
/ 21 августа 2009

Попытка быть СУХОЙ, я пытаюсь присвоить переменной экземпляра модели после инициализации объекта.

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 ]

5 голосов
/ 21 августа 2009

После инициализации вызывается всякий раз, когда создается экземпляр объекта (new'ed).Ваш вызов find в self.last_clockout создает объект, а затем рекурсивно вызывает after_initialize.Следовательно, бесконечная рекурсия и переполнение стека.

Before_save или after_create более уместны.

См. http://api.rubyonrails.org/classes/ActiveRecord/Callbacks.html

1 голос
/ 22 августа 2009

Я нашел default_value_for - очень хороший способ сделать это.

0 голосов
/ 08 июля 2015

Другим подходом было бы проверить, является ли инициализированный объект новым или нет, например ::100100

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