我几乎尝试过所有东西,但似乎不可能从模型中使用expire_fragment?我知道你不应该而且它不是非MVC,但肯定有很多方法可以做到.
我在lib/cache_helper.rb中创建了一个带有所有过期助手的模块,每个模块都只是一堆expire_fragment调用.我在/ app/sweepers下设置了所有缓存清理器,并在我的应用程序控制器中有一个"include CacheHelper",因此当通过控制器调用时,应用程序中的缓存可以正常工作.
然后事情是我有一些外部守护进程,特别是一些重复的cron任务,它们调用一个调用某种方法的rake任务.此方法执行一些处理并将条目输入到模型中,之后我需要使缓存过期.
这是最好的方法,因为我无法在模型中指定缓存清理程序.直观的观察者似乎是最好的解决方案,但后来它抱怨expire_fragment未定义等等,我甚至尝试将ActionController缓存类包含在观察者中,但这不起作用.我喜欢有关如何为此创建解决方案的一些想法.谢谢.
免责声明:我的导轨有点生锈,但这或类似的东西应该有用
ActionController::Base.new.expire_fragment(key, options = nil)
猎户座提供的解决方案完美无缺.为了方便起见,我将以下代码放入其中config/initializers/active_record_expire_fragment.rb
class ActiveRecord::Base def expire_fragment(*args) ActionController::Base.new.expire_fragment(*args) end end
现在,您可以在ActiveRecord :: Base的所有实例上使用expire_fragment,例如 User.first.expire_fragment('user-stats')
这很容易做到.您可以实现Orion的建议,但您也可以实现下面所示的更广泛的技术,这使您可以从任何模型访问当前控制器,无论您决定打破MVC分离的目的(例如,搞乱片段缓存,访问current_user
,生成)路径/ URL等)
为了从任何模型访问当前请求的控制器(如果有的话),将以下内容添加到environment.rb
或更好地添加到新插件(例如,vendor/plugins/controller_from_model/init.rb
包含以下代码的create ):
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
然后,在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 } ...
然后,从任何模型,
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
无论如何,在您的特定情况下,您可能希望ActiveRecord::Base
在相关控制器类加载时将代码注入各种后代,以便实际的控制器感知代码仍然驻留在其中app/controllers/*.rb
,但为了获得某些功能而不是必须这样做(虽然丑陋且难以维护.)
玩得开心!
在我的一个脚本中,我使用以下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
然后,一旦调用了ActiveRecord回调,清扫器就可以调用expire_fragment.