How to call expire_fragment from Rails Observer/Model?

前端 未结 8 799
长发绾君心
长发绾君心 2020-12-23 10:15

I\'ve pretty much tried everything, but it seems impossible to use expire_fragment from models? I know you\'re not supposed to and it\'s non-MVC, but surely there much be

相关标签:
8条回答
  • 2020-12-23 10:40

    This might not work for what you're doing, but you may be able to define a custom call back on your model:

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

    You can then use a sweeper like you would normally:

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

    Let me know if this is useful!

    0 讨论(0)
  • 2020-12-23 10:41

    Will it not be easier and clean just to pass the current controller as an argument to the model method call? Like following:

    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
    

    You can access all public methods and properties of the controller from within model. As long as you do not modify the state of the controller, it should be fine.

    0 讨论(0)
  • 2020-12-23 10:44

    The solution provided by Orion works perfectly. As an enhancement and for convenience, I've put the following code into config/initializers/active_record_expire_fragment.rb

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

    Now, you can use expire_fragment on all instances of ActiveRecord::Base, e.g. User.first.expire_fragment('user-stats')

    0 讨论(0)
  • 2020-12-23 10:50

    Disclaimer: My rails is a bit rusty, but this or something like it should work

    ActionController::Base.new.expire_fragment(key, options = nil) 
    
    0 讨论(0)
  • 2020-12-23 10:50

    I'm a bit of a rails noob, so this may not be correct, or even helpful, but it seems wrong to be trying to call controller actions from within the model.

    Is it not possible to write an action within the controller that does what you want and then invoke the controller action from within your rake task?

    0 讨论(0)
  • 2020-12-23 10:51

    In one of my scripts I use the following 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
    

    Then, once the ActiveRecord callbacks are called, sweepers are able to call expire_fragment.

    0 讨论(0)
提交回复
热议问题