Problema con ar_mailer + observer en Rails 2.2.2


#1

Bueno, ahí va un Poltergeist. La situación es la siguiente:
Rails 2.2.2 (actualizado de 2.1.2)
ar_mailer 1.3.1
Todos los emails de la aplicación salen a través de ar_mailer.

Tengo varios observers, y el error se reproduce en todos los observers
que
envian un email. Pongo uno de ejemplo:

Tengo un modelo GroupUser donde almaceno los usuarios que se van
apuntando a
los grupos. Hay un observer que envia un email al propietario de un
grupo
cuando un nuevo miembro se apunta.

class GroupUserObserver < ActiveRecord::Observer
def after_create(group_user)
GroupUserMailer.deliver_new_user_notification(group_user.group.owner,
group_user.user, group_user.group )
end
end

No pongo más código porque esto no tiene ningún misterio y funciona
bien. El
caso es que si arranco el servidor y me añado a un grupo, peta con el
siguiente error (os adjunto el raise completo abajo)

NoMethodError in GroupsController#add_to_group

You have a nil object when you didn’t expect it!
You might have expected an instance of Array.
The error occurred while evaluating nil.include?

Si vuelvo a probarlo hrecargando la página, evidentemente me sigue dando
el
mismo error, pero, y aquí viene el Poltergeist, si paro el servidor, lo
vuelvo a arrancar y recargo la página me añade el usuario al grupo i
envia
el email.

Si lo vuelvo a probar vuelve a fallar, solo funciona cuando, después de
fallar una vez, paro y arranco de nuevo el servidor.

Este es el error completo.

/Library/Ruby/Gems/1.8/gems/activerecord-2.2.2/lib/active_record/attribute_methods.rb:142:in
`create_time_zone_conversion_attribute?’

/Library/Ruby/Gems/1.8/gems/activerecord-2.2.2/lib/active_record/attribute_methods.rb:75:in
`define_attribute_methods’

/Library/Ruby/Gems/1.8/gems/activerecord-2.2.2/lib/active_record/attribute_methods.rb:71:in
`each’

/Library/Ruby/Gems/1.8/gems/activerecord-2.2.2/lib/active_record/attribute_methods.rb:71:in
`define_attribute_methods’

/Library/Ruby/Gems/1.8/gems/activerecord-2.2.2/lib/active_record/attribute_methods.rb:350:in
`respond_to?’

/Library/Ruby/Gems/1.8/gems/activerecord-2.2.2/lib/active_record/base.rb:2587:in
`attributes=’

/Library/Ruby/Gems/1.8/gems/activerecord-2.2.2/lib/active_record/base.rb:2583:in
`each’

/Library/Ruby/Gems/1.8/gems/activerecord-2.2.2/lib/active_record/base.rb:2583:in
`attributes=’

/Library/Ruby/Gems/1.8/gems/activerecord-2.2.2/lib/active_record/base.rb:2283:in
`initialize’

/Library/Ruby/Gems/1.8/gems/activerecord-2.2.2/lib/active_record/base.rb:691:in
`new’

/Library/Ruby/Gems/1.8/gems/activerecord-2.2.2/lib/active_record/base.rb:691:in
`create’

/Library/Ruby/Gems/1.8/gems/ar_mailer-1.3.1/lib/action_mailer/ar_mailer.rb:92:in
`perform_delivery_activerecord’

/Library/Ruby/Gems/1.8/gems/ar_mailer-1.3.1/lib/action_mailer/ar_mailer.rb:91:in
`each’

/Library/Ruby/Gems/1.8/gems/ar_mailer-1.3.1/lib/action_mailer/ar_mailer.rb:91:in
`perform_delivery_activerecord’

/Library/Ruby/Gems/1.8/gems/actionmailer-2.2.2/lib/action_mailer/base.rb:526:in
`send

/Library/Ruby/Gems/1.8/gems/actionmailer-2.2.2/lib/action_mailer/base.rb:526:in
`deliver!’

/Library/Ruby/Gems/1.8/gems/actionmailer-2.2.2/lib/action_mailer/base.rb:392:in
`method_missing’

app/models/group_user_observer.rb:4:in `after_create’

/Library/Ruby/Gems/1.8/gems/activerecord-2.2.2/lib/active_record/observer.rb:171:in
`send’

/Library/Ruby/Gems/1.8/gems/activerecord-2.2.2/lib/active_record/observer.rb:171:in
`update’

/Library/Ruby/Gems/1.8/gems/activerecord-2.2.2/lib/active_record/callbacks.rb:328:in
`notify’

/Library/Ruby/Gems/1.8/gems/activerecord-2.2.2/lib/active_record/callbacks.rb:321:in
`callback’

/Library/Ruby/Gems/1.8/gems/activerecord-2.2.2/lib/active_record/callbacks.rb:238:in
`create_without_timestamps’

/Library/Ruby/Gems/1.8/gems/activerecord-2.2.2/lib/active_record/timestamp.rb:29:in
`create’

/Library/Ruby/Gems/1.8/gems/activerecord-2.2.2/lib/active_record/base.rb:2699:in
`create_or_update_without_callbacks’

/Library/Ruby/Gems/1.8/gems/activerecord-2.2.2/lib/active_record/callbacks.rb:222:in
`create_or_update’

/Library/Ruby/Gems/1.8/gems/activerecord-2.2.2/lib/active_record/base.rb:2383:in
`save_without_validation’

/Library/Ruby/Gems/1.8/gems/activerecord-2.2.2/lib/active_record/validations.rb:1009:in
`save_without_dirty’

/Library/Ruby/Gems/1.8/gems/activerecord-2.2.2/lib/active_record/dirty.rb:79:in
`save_without_transactions’

/Library/Ruby/Gems/1.8/gems/activerecord-2.2.2/lib/active_record/transactions.rb:179:in
`send’

/Library/Ruby/Gems/1.8/gems/activerecord-2.2.2/lib/active_record/transactions.rb:179:in
`with_transaction_returning_status’

/Library/Ruby/Gems/1.8/gems/activerecord-2.2.2/lib/active_record/connection_adapters/abstract/database_statements.rb:66:in
`transaction’

/Library/Ruby/Gems/1.8/gems/activerecord-2.2.2/lib/active_record/transactions.rb:129:in
`transaction’

/Library/Ruby/Gems/1.8/gems/activerecord-2.2.2/lib/active_record/transactions.rb:138:in
`transaction’

/Library/Ruby/Gems/1.8/gems/activerecord-2.2.2/lib/active_record/transactions.rb:178:in
`with_transaction_returning_status’

/Library/Ruby/Gems/1.8/gems/activerecord-2.2.2/lib/active_record/transactions.rb:146:in
`save_without_trace_ActiveRecord___self_class_name__save’

/Library/Ruby/Gems/1.8/gems/activerecord-2.2.2/lib/active_record/transactions.rb:158:in
`rollback_active_record_state!’

/Library/Ruby/Gems/1.8/gems/activerecord-2.2.2/lib/active_record/transactions.rb:146:in
`save_without_trace_ActiveRecord___self_class_name__save’

/Library/Ruby/Gems/1.8/gems/activerecord-2.2.2/lib/active_record/associations/association_collection.rb:237:in
`create’

/Library/Ruby/Gems/1.8/gems/activerecord-2.2.2/lib/active_record/associations/association_collection.rb:405:in
`create_record’

/Library/Ruby/Gems/1.8/gems/activerecord-2.2.2/lib/active_record/associations/association_collection.rb:423:in
`add_record_to_target_with_callbacks’

/Library/Ruby/Gems/1.8/gems/activerecord-2.2.2/lib/active_record/associations/association_collection.rb:405:in
`create_record’

/Library/Ruby/Gems/1.8/gems/activerecord-2.2.2/lib/active_record/associations/association_collection.rb:235:in
`create’

app/controllers/groups_controller.rb:118:in `add_to_group’

/Library/Ruby/Gems/1.8/gems/actionpack-2.2.2/lib/action_controller/mime_responds.rb:106:in
`call’

/Library/Ruby/Gems/1.8/gems/actionpack-2.2.2/lib/action_controller/mime_responds.rb:106:in
`respond_to’

app/controllers/groups_controller.rb:116:in `add_to_group’

/Library/Ruby/Gems/1.8/gems/actionpack-2.2.2/lib/action_controller/base.rb:1253:in
`send’

/Library/Ruby/Gems/1.8/gems/actionpack-2.2.2/lib/action_controller/base.rb:1253:in
`perform_action_without_filters’

/Library/Ruby/Gems/1.8/gems/actionpack-2.2.2/lib/action_controller/filters.rb:617:in
`call_filters’

/Library/Ruby/Gems/1.8/gems/actionpack-2.2.2/lib/action_controller/filters.rb:610:in
`perform_action_without_benchmark’

/Library/Ruby/Gems/1.8/gems/actionpack-2.2.2/lib/action_controller/benchmarking.rb:68:in
`perform_action_without_rescue’

/Library/Ruby/Gems/1.8/gems/actionpack-2.2.2/lib/action_controller/benchmarking.rb:68:in
`perform_action_without_rescue’

/Library/Ruby/Gems/1.8/gems/actionpack-2.2.2/lib/action_controller/rescue.rb:136:in
`perform_action_without_caching’

/Library/Ruby/Gems/1.8/gems/actionpack-2.2.2/lib/action_controller/caching/sql_cache.rb:13:in
`perform_action_without_newrelic_trace’

/Library/Ruby/Gems/1.8/gems/activerecord-2.2.2/lib/active_record/connection_adapters/abstract/query_cache.rb:34:in
`cache’

/Library/Ruby/Gems/1.8/gems/activerecord-2.2.2/lib/active_record/query_cache.rb:8:in
`cache’

/Library/Ruby/Gems/1.8/gems/actionpack-2.2.2/lib/action_controller/caching/sql_cache.rb:12:in
`perform_action_without_newrelic_trace’

/Library/Ruby/Gems/1.8/gems/actionpack-2.2.2/lib/action_controller/base.rb:524:in
`send’

/Library/Ruby/Gems/1.8/gems/actionpack-2.2.2/lib/action_controller/base.rb:524:in
`process_without_filters’

/Library/Ruby/Gems/1.8/gems/actionpack-2.2.2/lib/action_controller/filters.rb:606:in
`process_without_session_management_support’

/Library/Ruby/Gems/1.8/gems/actionpack-2.2.2/lib/action_controller/session_management.rb:134:in
`process’

/Library/Ruby/Gems/1.8/gems/actionpack-2.2.2/lib/action_controller/base.rb:392:in
`process’

/Library/Ruby/Gems/1.8/gems/mongrel-1.1.5/lib/mongrel/rails.rb:76:in
`process’

/Library/Ruby/Gems/1.8/gems/mongrel-1.1.5/lib/mongrel/rails.rb:74:in
`synchronize’

/Library/Ruby/Gems/1.8/gems/mongrel-1.1.5/lib/mongrel/rails.rb:74:in
`process’

/Library/Ruby/Gems/1.8/gems/mongrel-1.1.5/lib/mongrel.rb:159:in
`process_client’

/Library/Ruby/Gems/1.8/gems/mongrel-1.1.5/lib/mongrel.rb:158:in `each’

/Library/Ruby/Gems/1.8/gems/mongrel-1.1.5/lib/mongrel.rb:158:in
`process_client’

/Library/Ruby/Gems/1.8/gems/mongrel-1.1.5/lib/mongrel.rb:285:in `run’

/Library/Ruby/Gems/1.8/gems/mongrel-1.1.5/lib/mongrel.rb:285:in
`initialize’

/Library/Ruby/Gems/1.8/gems/mongrel-1.1.5/lib/mongrel.rb:285:in `new’

/Library/Ruby/Gems/1.8/gems/mongrel-1.1.5/lib/mongrel.rb:285:in `run’

/Library/Ruby/Gems/1.8/gems/mongrel-1.1.5/lib/mongrel.rb:268:in
`initialize’

/Library/Ruby/Gems/1.8/gems/mongrel-1.1.5/lib/mongrel.rb:268:in `new’

/Library/Ruby/Gems/1.8/gems/mongrel-1.1.5/lib/mongrel.rb:268:in `run’

/Library/Ruby/Gems/1.8/gems/mongrel-1.1.5/lib/mongrel/configurator.rb:282:in
`run’

/Library/Ruby/Gems/1.8/gems/mongrel-1.1.5/lib/mongrel/configurator.rb:281:in
`each’

/Library/Ruby/Gems/1.8/gems/mongrel-1.1.5/lib/mongrel/configurator.rb:281:in
`run’

/Library/Ruby/Gems/1.8/gems/mongrel-1.1.5/bin/mongrel_rails:128:in `run’

/Library/Ruby/Gems/1.8/gems/mongrel-1.1.5/lib/mongrel/command.rb:212:in
`run’

/Library/Ruby/Gems/1.8/gems/mongrel-1.1.5/bin/mongrel_rails:281

/Library/Ruby/Gems/1.8/gems/activesupport-2.2.2/lib/active_support/dependencies.rb:142:in
`load_without_new_constant_marking’

/Library/Ruby/Gems/1.8/gems/activesupport-2.2.2/lib/active_support/dependencies.rb:142:in
`load’

/Library/Ruby/Gems/1.8/gems/activesupport-2.2.2/lib/active_support/dependencies.rb:521:in
`new_constants_in’

/Library/Ruby/Gems/1.8/gems/activesupport-2.2.2/lib/active_support/dependencies.rb:142:in
`load’

/Library/Ruby/Gems/1.8/gems/rails-2.2.2/lib/commands/servers/mongrel.rb:64

/Library/Ruby/Gems/1.8/gems/activesupport-2.2.2/lib/active_support/dependencies.rb:153:in
`require’

/Library/Ruby/Gems/1.8/gems/activesupport-2.2.2/lib/active_support/dependencies.rb:521:in
`new_constants_in’

/Library/Ruby/Gems/1.8/gems/activesupport-2.2.2/lib/active_support/dependencies.rb:153:in
`require’

/Library/Ruby/Gems/1.8/gems/rails-2.2.2/lib/commands/server.rb:49


#2

No es tan poliester como te piensas:

en desarrollo la opción cache_classes suele estar a false, lo que
significa que con cada request se vuelven a cargar modelos, observers
y notifiers.

El hecho de que te ocurra la segunda vez y no la primera apunta a que
hay algún error en el observer, ya que los observers se cargan después
de los modelos, y hasta que los modelos no son revisitados de nuevo
(en la segunda request si cache_classes está a false) no canta ese
error.

Pero vamos, a lo mejor no está en el observer, pero sí que tiene pinta
de estar en algo que se ejcuta desde el observer.


#3

Parece una condición de carrera o algo parecido, pero ni idea, sin
embargo…

La línea que falla es la siguiente:

time_zone_aware_attributes &&
!skip_time_zone_conversion_for_attributes.include?(name.to_sym) &&
[:datetime, :timestamp].include?(column.type)

En la línea hay dos “include?” pero solo el primero puede fallar siendo
nil.

Si buscas “skip_time_zone_conversion_for_attributes” en ese mismo
archivo lo encuentras en el “self.included”

def self.included(base)

base.class_inheritable_accessor
:skip_time_zone_conversion_for_attributes, :instance_writer => false
base.skip_time_zone_conversion_for_attributes = []
end

No encuentro más referencias en todo ActiveRecord y AttributeMethods
solo se incluye desde “lib/active_record.rb”, por lo que no hay razón
para que ese trozo de código no sea ejecutado.

Por lo tanto si tú no tienes ninguna línea que modifique
“skip_time_zone_conversion_for_attributes” y que lo ponga a “nil”, yo
probaría a poner la línea “skip_time_zone_conversion_for_attributes =
[]” en tú modelo Email. A ver si funciona.

Suerte.