usos tutorial sintaxis rails instalar funciona español ejemplo descargar como caracteristicas ruby-on-rails ruby caching memcached

ruby on rails - tutorial - Cómo llamar a expire_fragment desde Rails Observer/Model?



ruby on rails usos (8)

He intentado prácticamente todo, pero parece imposible usar expire_fragment de los modelos. Sé que se supone que no debes hacerlo y no es MVC, pero seguramente habrá mucho para hacerlo.

Creé un módulo en lib / cache_helper.rb con todos mis ayudantes caducados, dentro de cada uno hay solo un montón de llamadas expira_fragment. Tengo todas mis barredoras de caché configuradas en / app / sweepers y tengo un "include CacheHelper" en mi controlador de aplicación, por lo que el caché que expira en la aplicación cuando se llama a través de los controladores funciona bien.

Entonces las cosas son que tengo algunos daemons externos y especialmente algunas tareas cron recurrentes que llaman una tarea de rake que llama a cierto método. Este método realiza algunas entradas de procesamiento y entradas en el modelo, después de las cuales necesito caducar el caché.

¿Cuál es la mejor manera de hacerlo ya que no puedo especificar la limpieza de caché dentro del modelo? Los observadores directos parecen ser la mejor solución, pero luego se queja de que expire_fragment no está definido, etc., incluso intenté incluir las clases de caché de ActionController en el observador, pero eso no funcionó. Me encantaría algunas ideas de cómo crear una solución para esto. Gracias.


¿No será más fácil y limpio simplemente pasar el controlador actual como argumento de la llamada al método modelo? Como siguiendo:

def delete_cascade(controller) self.categories.each do |c| c.delete_cascade(controller) controller.expire_fragment(%r{article_manager/list/#{c.id}.*}) end PtSection.delete(self.id) controller.expire_fragment(%r{category_manager/list/#{self.id}.*}) end

Puede acceder a todos los métodos y propiedades públicos del controlador desde el modelo. Siempre que no modifique el estado del controlador, debería estar bien.


¿Por qué no hacer que sus tareas externas de rake llamen al método de vencimiento en el controlador? Entonces sigues siendo compatible con MVC, no dependes de algún truco de scoping, etc.

Para el caso, ¿por qué no pone toda la funcionalidad daemon / externa en un controlador y tiene rake / cron solo llame eso. Sería mucho más fácil de mantener.

- MarkusQ


Descargo de responsabilidad: Mis rieles están un poco oxidados, pero esto o algo así debería funcionar

ActionController::Base.new.expire_fragment(key, options = nil)


En uno de mis scripts utilizo el siguiente hack:

require ''action_controller/test_process'' sweepers = [ApartmentSweeper] ActiveRecord::Base.observers = sweepers ActiveRecord::Base.instantiate_observers controller = ActionController::Base.new controller.request = ActionController::TestRequest.new controller.instance_eval do @url = ActionController::UrlRewriter.new(request, {}) end sweepers.each do |sweeper| sweeper.instance.controller = controller end

Luego, una vez que se invocan las devoluciones de llamada de ActiveRecord, los sweepers pueden invocar expire_fragment.


Es posible que esto no funcione para lo que está haciendo, pero es posible que pueda definir una devolución de llamada personalizada en su modelo:

class SomeModel < ActiveRecord::Base define_callback :after_exploded def explode ... do something that invalidates your cache ... callback :after_exploded end end

Luego puede usar una barredora como lo haría normalmente:

class SomeModelSweeper < ActionController::Caching::Sweeper observe SomeModel def after_exploded(model) ... expire your cache end end

¡Avíseme si esto es útil!


Esto es bastante fácil de hacer. Puede implementar la sugerencia de Orion, pero también puede implementar la técnica más amplia ilustrada a continuación, que le da acceso al controlador actual desde cualquier modelo y para cualquier propósito que haya decidido romper la separación MVC (por ejemplo, jugar con la memoria caché de fragmentos, acceder al current_user , generando rutas / URLs, etc.)

Para obtener acceso al controlador de la solicitud actual (si corresponde) de cualquier modelo , agregue lo siguiente a environment.rb o, muy preferiblemente, a un nuevo complemento (por ejemplo, create vendor/plugins/controller_from_model/init.rb contenga el siguiente código) )

module ActiveRecord class Base protected def self.thread_safe_current_controller #:nodoc: Thread.current[:current_controller] end def self.thread_safe_current_controller=(controller) #:nodoc: Thread.current[:current_controller] = controller end # pick up the correct current_controller version # from @@allow_concurrency if @@allow_concurrency alias_method :current_controller, :thread_safe_current_controller alias_method :current_controller=, :thread_safe_current_controller= else cattr_accessor :current_controller end end end

Luego, en app/controllers/application.rb ,

class ApplicationController < ActionController::Base before_filter { |controller| # all models in this thread/process refer to this controller # while processing this request ActiveRecord::Base.current_controller = controller } ...

Entonces, desde cualquier modelo ,

if controller = ActiveRecord::Base.current_controller # called from within a user request else # no controller is available, didn''t get here from a request - maybe irb? fi

De todos modos, en su caso particular, es posible que desee insertar código en sus diversos descendientes ActiveRecord::Base cuando se carguen las clases de controlador relevantes, de modo que el código actual controlado por el controlador todavía resida en la app/controllers/*.rb , pero no es obligatorio hacerlo para obtener algo funcional (aunque feo y difícil de mantener).

¡Que te diviertas!


La solución provista por Orion funciona perfectamente. Como una mejora y por conveniencia, he puesto el siguiente código en config/initializers/active_record_expire_fragment.rb

class ActiveRecord::Base def expire_fragment(*args) ActionController::Base.new.expire_fragment(*args) end end

Ahora puede usar expire_fragment en todas las instancias de ActiveRecord :: Base, por ejemplo User.first.expire_fragment(''user-stats'')


Soy un poco novato en los rieles, por lo que puede no ser correcto, o incluso útil, pero parece incorrecto tratar de llamar a las acciones del controlador desde dentro del modelo.

¿No es posible escribir una acción dentro del controlador que hace lo que desea y luego invocar la acción del controlador desde dentro de su tarea de rake?