无法从装饰器(布局)缓存

时间:2012-09-15 13:02:09

标签: ruby-on-rails caching haml draper

缓存是我的视图代码中最具逻辑密集度的部分,因此我想从装饰器内部进行片段缓存,但是,我无法做到。

当我从装饰师那里做到这一点时:

def cached_name
  h.cache do
   "a name here"
  end
end

我明白了:

  

当你没想到它时,你有一个零对象!你可能有   期待一个Array的实例。评估时发生错误   nil.length

我从控制器

中实例化我的装饰器
@presenter = SomePresenter::new

我正在使用HAML作为我的观点

如何从装饰器内成功缓存,所以我的视图可以做这样的事情

= @decorator.cached_logic_heavy_stuff

更新:我创建了一个git repo来显示我的问题:https://github.com/houen/presenter_caching

更新:这可能有效 - 请参阅回购

  include Haml::Helpers
  def another_way_to_try
    self.init_haml_helpers
    buffer = haml_buffer.buffer

    h.with_output_buffer(buffer) do
      h.cache do
        h.concat "i should still not be empty"
      end
    end
  end

4 个答案:

答案 0 :(得分:2)

我建议直接使用Rails.cache可能会解决您的问题;我们在使用Rails 4的装饰器中做同样的事情。

def cached_name
  Rails.cache.fetch(source) do
    source.name # etc.
  end
end

答案 1 :(得分:1)

如果你正在使用Draper,我相信你不需要显式传递视图上下文。实例化时,您可能希望将模型或集合传递给存在的存储器。例子:

class UserDecorator < Draper::Base
  decorates :user

  # additional methods
end

# in the controller
@presenter = UserDecorator.new(@user)       # for an instance
@presenter = UserDecorator.decorate(@users) # for a collection

我怀疑你得到的nil对象错误是来自你的代码中没有列出的另一个方法调用。

对于装饰器中的片段缓存,你需要使用concat辅助方法让它在装饰器内工作:

# your decorator class
def cached_name
  h.cache("some_cache_key") do
    h.concat "a name here"
  end
end

答案 2 :(得分:0)

Rails'cache方法尝试根据从中调用的视图来推断缓存键。因为你实际上并没有从视图中调用它(而是从装饰器类的实例中调用它),所以我希望在尝试构建缓存键时它会被轰炸。

您可以尝试通过h.cache "your cache key" do显式传递缓存密钥。使用完整的堆栈跟踪,您可以找出它抛出异常的位置,然后解决这个问题。但是,如果没有完整的堆栈跟踪,就很难帮助你。

编辑:关注Rails' caching code,我认为这可能是一个更深层次的问题;它试图得到output_buffer的长度,这在你的观点的上下文之外是不可用的(也就是说,在Draper中)。您可以尝试添加:

def output_buffer
  h.output_buffer
end

但是如果不对它进行测试,我认为如果没有更多工作,它可能无法完全按计划运行。这只是一个粗略的猜测 - 如果这实际上是问题我会感到惊讶,但希望它能让你走上正确的道路。

来源中的注释:

# VIEW TODO: Make #capture usable outside of ERB
# This dance is needed because Builder can't use capture

表示这不是一个完全解决的问题,所以你可能需要在Rails内部进行一些挖掘,以使这个工作。

答案 3 :(得分:0)

这有效:

  include Haml::Helpers
  def another_way_to_try
    self.init_haml_helpers
    buffer = haml_buffer.buffer
    h.with_output_buffer(buffer) do
      h.cache "some_key10", :expires_in => 10.seconds do
        h.concat "i should still not be empty 2"
      end
    end
  end