29

我几乎尝试了一切,但似乎无法使用模型中的 expire_fragment ?我知道你不应该这样做,而且它不是 MVC,但肯定有很多方法可以做到这一点。

我在 lib/cache_helper.rb 中创建了一个模块,其中包含我所有的过期助手,其中每个只是一堆 expire_fragment 调用。我在 /app/sweepers 下设置了所有缓存清除程序,并在我的应用程序控制器中有一个“包含 CacheHelper”,因此当通过控制器调用时,应用程序中的过期缓存工作正常。

然后事情是我有一些外部守护进程,尤其是一些重复的 cron 任务,它们调用调用某个方法的 rake 任务。此方法进行一些处理并将条目输入到模型中,之后我需要使缓存过期。

最好的方法是什么,因为我无法在模型中指定缓存清扫器。直截了当的观察者似乎是最好的解决方案,但它抱怨 expire_fragment 未定义等,我什至尝试将 ActionController 缓存类包含到观察者中,但没有奏效。我很想知道如何为此创建解决方案。谢谢。

4

8 回答 8

43

免责声明:我的铁轨有点生锈,但这个或类似的东西应该可以工作

ActionController::Base.new.expire_fragment(key, options = nil) 
于 2009-02-19T21:14:04.440 回答
13

Orion 提供的解决方案完美运行。作为增强和方便起见,我将以下代码放入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')

于 2010-01-05T14:45:03.467 回答
8

这很容易做到。您可以实现 Orion 的建议,但您也可以实现下面说明的更广泛的技术,这使您可以从任何模型访问当前控制器,以及您决定打破 MVC 分离的任何目的(例如,弄乱片段缓存、访问current_user、生成路径/URL 等)

为了从任何模型访问当前请求的控制器(如果有的话),请将以下内容添加到新插件中environment.rb,或者最好添加到新插件中(例如vendor/plugins/controller_from_model/init.rb,包含以下代码的创建):

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,但为了获得某些功能而不必这样做(虽然丑陋且难以维护。)

玩得开心!

于 2009-03-03T23:36:30.700 回答
6

在我的一个脚本中,我使用了以下 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。

于 2008-12-26T02:55:39.247 回答
2

我有点像 Rails 菜鸟,所以这可能不正确,甚至没有帮助,但尝试从模型中调用控制器操作似乎是错误的。

是否不可能在控制器中编写一个执行您想要的操作,然后从您的 rake 任务中调用控制器操作?

于 2009-02-27T08:59:46.333 回答
2

为什么不让您的外部 rake 任务调用控制器上的 expiry 方法。然后你仍然是 MVC 兼容的,你没有建立对一些范围黑客等的依赖。

就此而言,您为什么不将所有守护程序/外部功能放在控制器上并让 rake / cron 调用它。这将更容易维护。

——马库斯

于 2009-03-02T05:08:30.357 回答
2

将当前控制器作为参数传递给模型方法调用不是更容易和更干净吗?如下:

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

您可以从模型中访问控制器的所有公共方法和属性。只要不修改控制器的状态,应该没问题。

于 2009-06-01T18:22:20.460 回答
1

这可能不适用于您正在做的事情,但您可以在模型上定义自定义回调:

class SomeModel < ActiveRecord::Base
    define_callback :after_exploded

    def explode
        ... do something that invalidates your cache ...
        callback :after_exploded
    end
end

然后,您可以像往常一样使用扫地机:

class SomeModelSweeper < ActionController::Caching::Sweeper
  observe SomeModel 

    def after_exploded(model)
      ... expire your cache
    end
end

让我知道这是否有用!

于 2009-03-03T12:53:18.890 回答