1

到目前为止,缓存是我的视图代码中逻辑最密集的部分,所以我想从装饰器内部进行片段缓存,但是我做不到。

当我从我的装饰器中这样做时:

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

我明白了:

当你没想到时,你有一个 nil 对象!您可能期望有一个 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

4 回答 4

2

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

def cached_name
  Rails.cache.fetch(source) do
    source.name # etc.
  end
end
于 2013-08-08T14:16:03.447 回答
1

如果您使用的是 Draper,我相信您不需要显式传递视图上下文。您可能希望在实例化时将模型或集合传递给您的 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
于 2012-09-22T15:05:06.680 回答
0

Rails 的cache方法尝试根据调用它的视图来推断缓存键。由于您实际上并不是从视图中调用它(而是从装饰器类的实例内部),所以我希望它在尝试构建缓存键时会爆炸。

您可以尝试通过显式传递缓存键h.cache "your cache key" do。通过完整的堆栈跟踪,您可以找出它在哪里引发异常,然后也可以解决这个问题。但是,如果没有完整的堆栈跟踪,就很难为您提供帮助。

编辑:查看Rails 的缓存代码,我认为这可能是一个更深层次的问题;它试图获取 的长度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 内部进行一些挖掘才能使其正常工作。

于 2012-09-22T15:27:21.187 回答
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
于 2012-09-22T15:52:04.203 回答