tutorial sintaxis rails mundo hola español ejemplos curso comandos caracteristicas ruby-on-rails ruby ruby-on-rails-3 caching memcached

ruby on rails - sintaxis - Error de Rails.cache en Rails 3.1-TypeError: no se puede descargar el hash con el proceso predeterminado



ruby on rails tutorial español pdf (4)

Me encuentro con un problema con los métodos Rails.cache en 3.1.0.rc4 (ruby 1.9.2p180 (2011-02-18 revisión 30909) [x86_64-darwin10]). El código funciona bien dentro de la misma aplicación en 2.3.12 (ruby 1.8.7 (2011-02-18 patchlevel 334) [i686-linux], MBARI 0x8770, Ruby Enterprise Edition 2011.03), pero comenzó a devolver un error después de la actualización. Todavía no he podido averiguar por qué.

El error parece ocurrir cuando intentamos almacenar en caché objetos que tienen más de un ámbito en ellos.

Además, todos los ámbitos que utilizan lambdas fallan independientemente de la cantidad de ámbitos.

He golpeado fallas de estos patrones:

Rails.cache.fetch("keyname", :expires_in => 1.minute) do Model.scope_with_lambda end Rails.cache.fetch("keyname", :expires_in => 1.minute) do Model.scope.scope end

Este es el error que recibo:

TypeError: can''t dump hash with default proc from /project/shared/bundled_gems/ruby/1.9.1/gems/activesupport-3.1.0.rc4/lib/active_support/cache.rb:627:in `dump'' from /project/shared/bundled_gems/ruby/1.9.1/gems/activesupport-3.1.0.rc4/lib/active_support/cache.rb:627:in `should_compress?'' from /project/shared/bundled_gems/ruby/1.9.1/gems/activesupport-3.1.0.rc4/lib/active_support/cache.rb:559:in `initialize'' from /project/shared/bundled_gems/ruby/1.9.1/gems/activesupport-3.1.0.rc4/lib/active_support/cache.rb:363:in `new'' from /project/shared/bundled_gems/ruby/1.9.1/gems/activesupport-3.1.0.rc4/lib/active_support/cache.rb:363:in `block in write'' from /project/shared/bundled_gems/ruby/1.9.1/gems/activesupport-3.1.0.rc4/lib/active_support/cache.rb:520:in `instrument'' from /project/shared/bundled_gems/ruby/1.9.1/gems/activesupport-3.1.0.rc4/lib/active_support/cache.rb:362:in `write'' from /project/shared/bundled_gems/ruby/1.9.1/gems/activesupport-3.1.0.rc4/lib/active_support/cache.rb:299:in `fetch'' from (irb):62 from /project/shared/bundled_gems/ruby/1.9.1/gems/railties-3.1.0.rc4/lib/rails/commands/console.rb:45:in `start'' from /project/shared/bundled_gems/ruby/1.9.1/gems/railties-3.1.0.rc4/lib/rails/commands/console.rb:8:in `start'' from /project/shared/bundled_gems/ruby/1.9.1/gems/railties-3.1.0.rc4/lib/rails/commands.rb:40:in `<top (required)>'' from script/rails:6:in `require'' from script/rails:6:in `<main>''

He intentado utilizar la opción: raw => true como alternativa, pero eso no funciona porque los bloques Rails.cache.fetch están intentando almacenar objetos en caché.

¿Alguna sugerencia? ¡Gracias por adelantado!


Esto podría ser un poco detallado, pero tuve que pasar un tiempo con el código fuente de Rails para aprender cómo funciona el funcionamiento de la memoria caché. Escribir cosas ayuda a comprenderlo y creo que compartir algunas notas sobre cómo funcionan las cosas no puede doler. Salta al final si tienes prisa.

Por qué sucede

Este es el método ofensivo dentro de ActiveSupport:

def should_compress?(value, options) if options[:compress] && value unless value.is_a?(Numeric) compress_threshold = options[:compress_threshold] || DEFAULT_COMPRESS_LIMIT serialized_value = value.is_a?(String) ? value : Marshal.dump(value) return true if serialized_value.size >= compress_threshold end end false end

Tenga en cuenta la asignación a serialized_value . Si cache.rb dentro de cache.rb , verás que usa Marshal para serializar objetos a cadenas de bytes antes de que entren en la caché y luego a Marshal nuevamente para deserializar objetos. El problema de la compresión no es importante aquí, lo importante es el uso de Marshal.

El problema Marshal :

Algunos objetos no se pueden volcar: si los objetos a ser objeto de dumping incluyen enlaces, procedimientos o objetos de método, instancias de clase IO u objetos singleton, se generará un TypeError.

Algunas cosas tienen estado (como descriptores de archivos del sistema operativo o bloques) que Marshal no puede serializar. El error que estás notando es esto:

no puede volcar el hash con el proceso predeterminado

Entonces, alguien en su modelo tiene una variable de instancia que es un Hash y ese Hash usa un bloque para suministrar valores predeterminados. El método column_methods_hash usa dicho Hash e incluso @dynamic_methods_hash el hash dentro de @dynamic_methods_hash ; column_methods_hash se llamará (indirectamente) por métodos públicos como respond_to? y method_missing .

Uno de respond_to? o la method_missing a method_missing probablemente se method_missing tarde o temprano en todas las instancias del modelo de AR e invocar cualquiera de los dos métodos hace que el objeto no pueda ser serializado. Entonces, las instancias del modelo AR son esencialmente no serializables en Rails 3.

Curiosamente, el respond_to? y method_missing implementaciones de method_missing en 2.3.8 también están respaldadas por un Hash que usa un bloque para valores predeterminados. El caché 2.3.8 es "[...] está destinado para cachear cadenas". entonces tenías suerte con un backend que podía manejar objetos enteros o usaba Marshal antes de que tus objetos tuvieran hash-with-procs en ellos; o tal vez estaba usando el backend de caché MemoryStore y eso es poco más que un gran hash.

El uso de múltiples scope-with-lambdas puede terminar almacenando Procs en sus objetos AR; Esperaría que las lambdas se almacenaran con la clase (o clase singleton) en lugar de los objetos, pero no me molesté con un análisis como el problema con respond_to? y method_missing hace que el tema del scope irrelevante.

Qué puedes hacer al respecto

Creo que has estado almacenando las cosas incorrectas en tu caché y teniendo suerte. Puede comenzar a usar correctamente la caché de Rails (es decir, almacenar datos simples generados en lugar de modelos completos) o puede implementar los marshal_dump / marshal_load o _dump / _load como se indica en Marshal . Alternativamente, puede usar uno de los servidores de almacenamiento de MemoryStore y limitarse a un caché distinto por proceso de servidor.

Resumen ejecutivo

No puede depender de almacenar objetos del modelo ActiveRecord en la memoria caché de Rails a menos que esté preparado para manejar el marshalling usted mismo o si desea limitarse a los backends de memoria caché de MemoryStore.


Gracias a mu-es-demasiado-corto para su excelente análisis. Conseguí que mi modelo se serializara ahora con esto:

def marshal_dump {}.merge(attributes) end def marshal_load stuff send :initialize, stuff, :without_protection => true end

También tengo algunos "atributos virtuales" establecidos por una consulta directa de unión SQL usando AS por ejemplo, SELECT DISTINCT posts.*, name from authors AS author_name FROM posts INNER JOIN authors ON author.post_id = posts.id WHERE posts.id = 123 . Para que funcionen, necesito declarar un attr_accessor para cada uno, luego attr_accessor / cargarlos también, así:

VIRTUAL_ATTRIBUTES = [:author_name] attr_accessor *VIRTUAL_ATTRIBUTES def marshal_dump virtual_attributes = Hash[VIRTUAL_ATTRIBUTES.map {|col| [col, self.send(col)] }] {}.with_indifferent_access.merge(attributes).merge(virtual_attributes) end def marshal_load stuff stuff = stuff.with_indifferent_access send :initialize, stuff, :without_protection => true VIRTUAL_ATTRIBUTES.each do |attribute| self.send("#{attribute}=", stuff[attribute]) end end

Usando Rails 3.2.18


Me di cuenta de que usar where o algún ámbito creaba objetos ActiveRecord::Relation . Luego noté que funcionaba un Model.find simple. Sospeché que no le gustaba el objeto ActiveRecord::Relation así que forcé la conversión a una Array simple y eso funcionó para mí.

Rails.cache.fetch([self.id, ''relA'']) do relA.where( attr1: ''some_value'' ).order( ''attr2 DESC'' ).includes( :rel_1, :rel_2 ).decorate.to_a end


simplemente elimine el proceso predeterminado una vez que haya terminado de modificarlo. algo como:

your_hash.default = nil # clear the default_proc