2015-06-04 76 views
5

我想使用Redis在我的Rails應用程序中執行一些低級緩存。 在控制器我通常我們這次拿到的所有書:集合低級緩存

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 

爲了簡單起見,我暫時忽略了過期的策略,但顯然他們需要在那裏。

+0

我不會在模型 – apneadiving

+0

只是檢查添加緩存:你看了(HTTP [關於緩存指南]://guides.rubyonrails .ORG/caching_with_rails.html)? – zwippie

+0

當然,但我正在尋找特定的模型緩存集合 – John

回答

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' 
}] 

然後您就可以「解密」這個東西放入數組後。喜歡的東西

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,因爲它是一個普通的數組(您可以致電sort,但這個想法是緩存已經排序數據)。

那麼......值得嗎?其實,並不是真的。如果你需要緩存這塊 - 可能最好的辦法是緩存一個渲染頁面,而不是查詢結果。

如果您使用cached_titlecached_author - 這是個好問題。首先,這取決於什麼cached_title可能。如果它是一個字符串 - 沒有什麼可以緩存的。您通過DB請求獲得Book,或者您從緩存中獲得Book - 以任何方式顯示title,因爲它是簡單類型。但讓我們看看author。最有可能的是它與另一個型號Author的關係,這是緩存適合完美的地方。您可以在本書中重新定義author方法(或者定義新的方法,並避免Rails在未來的複雜查詢中可能產生討厭的效果),並查看是否有緩存。如果是,則返回緩存。如果沒有 - 查詢數據庫,將結果保存到緩存並返回。

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 

還是不太方便,但更 「安全」:

def cached_author 
    Rails.cache.fetch("#{author_id}/info", expires_in: 12.hours) do 
    author 
    end 
end 
+0

感謝您的全面解釋,這對我來說非常有用! – John