如何缓存对象的JSON表示?

ben*_*ben 8 json caching ruby-on-rails

JSON我的Car模型的表示中,我包括一个昂贵的方法的输出:

#car.rb
def as_json(options={})
  super(options.merge(methods: [:some_expensive_method]))
end
Run Code Online (Sandbox Code Playgroud)

我有一个标准的索引操作:

#cars_controller.rb
respond_to :json
def index
  respond_with(Car.all)
end
Run Code Online (Sandbox Code Playgroud)

我也在JSON其他地方使用汽车的表示,如下所示:

#user_feed.rb
def feed_contents
  Horse.all + Car.all
end

#user_feeds_controller.rb
respond_to :json
def index
  respond_with(UserFeed.feed_contents)
end
Run Code Online (Sandbox Code Playgroud)

因为a的JSON表示car在多个地方使用,所以我希望将其car.cache_key作为自动过期的缓存键自行缓存.

这就是我目前正在做的事情:

#car.rb
def as_json(options={})
  Rails.cache.fetch("#{cache_key}/as_json") do
    super(options.merge(methods: [:some_expensive_method]))
  end
end
Run Code Online (Sandbox Code Playgroud)

将缓存代码放入其中as_json是不正确的,因为缓存不是可as_json重复性的一部分.这样做的正确方法是什么?我正在使用Rails 3.2.15.

Vid*_*dya 2

首先我要说我对这个问题的努力表示赞赏。你会发现很难找到比我更热衷于以正确方式设计软件的人了——包括用小方法在一个抽象级别上做好一件事。

不过,我不得不说,在这一点上,我其实是反对这个问题的前提的。我认为你的as_json样子最好。

最重要的是使客户端与实现脱钩。客户端需要知道的唯一一件事Car#as_json是返回值是Car. 并且as_json做了那件事并且做得很好。缓存和/或获取是应该保留在方法内部的实现细节,并且它是该任务不可或缺的细节。

否则就好像说任何带有if语句的方法都是“不正确的”,因为它做了两件事。当然这不是真的。在这两种情况下(usingif和 using Rails.cache.fetch),方法实现都是一些原子操作,其结果基于条件。

这是一件事可以以两种方式之一进行,这与两件事不同。

同时,我不得不不同意@severin 的回应。它当然可以工作,但是您现在已经将您的视图与实现细节结合起来。任何人,当然也不应该是您的观点,都不应该了解缓存的方法,甚至不应该知道涉及缓存。在我看来,你现在已经用这种方法泄露了抽象。也许这并不重要,但既然我们正在谈论做事的“正确方式”......

所以我说保持现状。但我相信这是一个很好的问题。