开发者

pagination and memcached in rails

What's the best way to cache a paginated result set with rails and memcached?

For example, posts controller:

def index
  @posts = Rails.cache.fetch('all_posts') do
    Post.paginate(:conditions => ['xx = ?', yy], :include => [:author], :page => params[:page],开发者_C百科 :order => 'created_at DESC')
  end
end

This obviously doesn't work when the params[:page] changes. I can change the key to "all_posts_#{params[:page]}_#{params[:order]_#{last_record.created_at.to_i}", but then there could be several possible orders (recent, popular, most voted etc) and there will be a combination of pages and orders ... lots of keys this way.

Problem #2 - It seems that when I implement this solution, the caches get written correctly and the page loads fine during the first call to a paginated action. When I click back on the same page i.e. page1, with recent order, it seems the browser does not even make a call to the server. I don't see any controller action being called in the production log.

I am using passenger, REE, memcached, and rails 2.3.5. Firebug shows no requests being made....

Is there a simples/more graceful way of handling this?


When it comes to caching there is no easy solution. You might cache every variant of the result, and thats ok if you implement auto-expiration of entries. You can't just use all_posts, because this way you will have to expire dozens of keys if posts will get changed.

Every AR model instance has the .cache_key based on updated_at method, which is prefered way, so use this instead of last record. Also don't base your key on last record, because if some post in the middle will get deleted your key wont change. You can use logic like this instead.

class ActiveRecord::Base         
  def self.newest
    order("updated_at DESC").first
  end    
  def self.cache_key
    newest.nil? ? "0:0" : "#{newest.cache_key}:#{count}"
  end
end

Now you can use Post.cache_key, which will get changed if any post will get changed/deleted or created.

In general I would just cache Post.all and then paginate on this object. You really need to do some profiling to find bottle necks in your application.

Besides, if you want to cache every variant, then do fragment/page caching instead.

If up to you how and where to cache. No one-way here.

As for the second part of the question, there is way to few hints for me to figure an answer. Check if the browser is making a call at all LiveHTTPHeaders, tcpdump, etc.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜