收集的低级缓存

时间:2015-06-04 15:41:21

标签: ruby-on-rails caching redis

我想在我的Rails应用程序中使用Redis进行一些低级缓存。 在控制器中,我通常会用这个来获取所有书籍:

class BooksController < ApplicationController
  def index
    @books = Book.order(:title)
  end
end

视图迭代了这个:

<ul>
  - @books.each do |book|
    <li>= "#{book.title} - #{book.author}"</li>
</ul>

现在我想要完全相同的结果,然后缓存。我有Redis设置并运行。所以我应该在控制器中使用cached_books方法,如下所示:

@books = Book.cached_books.order(:title)

保持视图不变,或者在视图中使用book.cached_titlebook.cached_author并保持控制器原样?

cached_books模型中Book方法的外观如何?

class Book < ActiveRecord::Base
  ...

  def cached_books
    Rails.cache.fetch([self, "books"]) { books.to_a }
  end
end

为简单起见,我现在忽略了过期策略,但显然他们需要在那里。

1 个答案:

答案 0 :(得分:5)

  

所以我应该在控制器中使用cached_books方法,如下所示:

是的,你可以。虽然有一些问题你必须要注意。 BookActiveRecord。当你致电Book.something(例如Book.all,或者只是Book.order(:title)时,它会返回ActiveRecord::Relation,它基本上是Book数组的包装器(此包装器)防止发起不必要的查询,提高性能。

您无法在Redis中保存查询的整个结果。比如说,您可以使用模型属性保存哈希数组的JSON字符串,例如

[{
  id: 1,
  title: 'How to make a sandwich",
  author: 'Mr. cooker'
}, {
  id: 2,
  title: 'London's Bridge',
  author: 'Fergie'
}]

然后你可以解密&#39;这个东西进入数组之后。像

这样的东西
def cached_books(key)
  # I suggest you to native wrapper
  if result = $redis.hget 'books_cache', key
    result.map do { |x| Book.new(x) }
  end
end

而且,在将属性放入缓存之前,您必须先将属性序列化。

好的,现在你有了可以在视图中使用相同数据迭代的集合,尽管你不能在缓存集合上调用order,因为它是一个普通数组(你可以调用{{ 1}},但想法是缓存已经排序的数据。

嗯......值得吗?实际上,不是真的。如果你需要缓存这篇文章 - 最好的方法是缓存一个渲染的页面,而不是一个查询结果。

你应该使用sortcached_title - 这是个好问题。首先,它取决于cached_author可能是什么。如果它是一个字符串 - 你可以缓存任何东西。您可以通过数据库请求获得cached_title,或者从缓存中获得Book - Book将以任何方式显示在其中,因为它是一种简单类型。但是让我们更接近title。最有可能的是它与另一个模型author的关系,这就是缓存非常适合的地方。您可以在本书中重新定义Author方法(或者定义新的并避免Rails在将来的复杂查询中可能会产生令人讨厌的影响)并查看是否存在缓存。如果是,请返回缓存。如果不是 - 查询数据库,将结果保存到缓存并返回。

author

或不太方便,但更安全&#34;:

def author
  Rails.cache.fetch("#{author_id}/info", expires_in: 12.hours) do
    # block executed if cache is not founded
    # it's better to alias original method and call it here
    #instead of directly Author.find call though
    Author.find(author_id) 
  end
end