A ver si me pueden dar una manito con esto. Estoy intentando utilizar el
plugin Interlock [1] para cachear objetos en MemCache combinado con un
modelo de datos basado en Single-Table Inheritance (STI).
El modelo es bastante simple:
Post < ActiveRecord
MicroblogPost < Post
ImagePost < Post
Interlock provee “Caching finders”, que hace uso del method
overloading de Ruby sobre los “find” de ActiveRecord. Por lo tanto si le
pasamos un entero o un set, Interlock automáticamente los almacenará en
MemCache para futuros accesos.
El problema es cuando intento utilizar un modelo que hereda de otro.
Por ejemplo:
–
Post.find(1000,2000,3000)
ArgumentError: undefined class/module MicroblogPost
from
/var/lib/gems/1.8/gems/memcache-client-1.5.0/lib/memcache.rb:262:in load' from /var/lib/gems/1.8/gems/memcache-client-1.5.0/lib/memcache.rb:262:in get_multi’
from
/var/lib/gems/1.8/gems/memcache-client-1.5.0/lib/memcache.rb:261:in
`each’
–
Sin embargo si hago un “MicroblogPost.find(1000)” funciona
correctamente, e incluso a partir de ese momento funcionaría tambien
“Post.find(1000)”
Con el Post.find(2000) volvería a fallar porque puede ser un ImagePost y
vuelta a empezar.
He leído [2] que probablemente tenga que hacer un “require_dependency
‘post’” para volver a cargar el modelo en cada request, pero el tema es
que tampoco funciona en mi caso.
Lo único que he encontrado útil ha sido un post [3] que implementa un
before_filter para precargar los modelos que heredan de Post (en mi
caso) antes de cada request, pero como bien dice el mismo autor, no deja
de ser un hack.
ArgumentError: undefined class/module MicroblogPost
from
Eso pasa porque Marshal.load intenta deserializar un objeto de una clase
que no está cargada en memoria. Según como tengas montada tu aplicación
bastarÃa con arrancar en modo production, de esa forma una vez se carga
una clase en memoria ya se queda ahÃ, y cuando se intenta deserializar
la encuentras.
Lo único que he encontrado útil ha sido un post [3] que implementa un
before_filter para precargar los modelos que heredan de Post (en mi
yo utilizo algo muy parecido a eso, lo que pasa es que en lugar de un
before_filter lo ejecuto directamente antes de llamar al get de la gema
memcache_client, y solamente le llamo una vez si estoy en modo
production o en cada ejecución en modo development.
Tengo este trozo de código
def self.preload_models #we need to reference the classes here so if coming from cache
Marshal.load will find them
ActiveRecord::Base.connection.tables.each do |model|
begin
“#{model.classify}”.constantize
rescue Exception
nil
end
end
end
self.preload_models #we need to reference all the models, just in case