api-pagination icon indicating copy to clipboard operation
api-pagination copied to clipboard

Caching and Pagination ?

Open danramteke opened this issue 7 years ago • 8 comments

Hi, I'm having a little trouble getting Rails caching to play nicely with this gem. Here's some psuedo code that matches my code fairly well:

# Shows HTTP paging headers, but loads everything into memory
def user_posts
  cache_key = {
    user_id: current_user.id, 
    latest_post: current_user.posts.maximum(:updated_at)
  }

  posts = Rails.cache.fetch(cache_key) do
     current_user.posts.order('created_at DESC')
  end
  render json: paginate(posts), each_serializer: PostSerializer
end

If I do this, I will get the api_pagination HTTP headers. However, I'm loading all of the current_user's posts into memory, which seems like a bad thing.

If I paginate inside the caching block (like below), then I don't get any api_pagination HTTP headers.

# Doesn't show HTTP paging headers, but doesn't load everything into memory
def user_posts
  cache_key = {
    user_id: current_user.id, 
    latest_post: current_user.posts.maximum(:updated_at), 
    page: params[:page]
  }

  posts = Rails.cache.fetch(cache_key) do
     paginate(current_user.posts.order('created_at DESC'))
  end
  render json: posts, each_serializer: PostSerializer
end

Can someone point me in the right direction? I'm having a hard time googling for API Pagination and Rails caching. Perhaps I'm missing something fairly obvious. I'm using kaminari, if that helps.

Thanks so much!

danramteke avatar Jul 26 '16 16:07 danramteke

@danramteke Is your app open source, by any chance? If not, would you be able to reproduce this in a fresh rails app using kaminari and api-pagination and send me the app's code?

davidcelis avatar Jul 26 '16 18:07 davidcelis

Just had the same problem. paginate overrides Rails' render method.

This override is skipped if the application serves the cached results, so in order to get the correct (full) headers in case the request hits the cache, we have better to paginate what the cache returns instead of paginating inside the cache block.

Something like the following should work:

...
posts = Rails.cache.fetch(cache_key) do
  current_user.posts.order('created_at DESC')
end
paginate json: posts, each_serializer: PostSerializer
...

davideghz avatar Oct 25 '17 13:10 davideghz

@davideghz as the author stated, this way you're going to put all posts into cache, and u might have milions of them, so that's not a good solution.

jacek213 avatar Oct 05 '18 13:10 jacek213

Hi!! Did anyone find a solution for this? I am having the same issue...

alemata avatar Feb 11 '19 17:02 alemata

Hey all, sorry that there's still an issue with this. I'm still happy to look into this, but I haven't experienced the issue, so having access to the source code of one of these apps that I can run locally would help. Or even just a dummy Rails app that's set up to reproduce the problem.

davidcelis avatar Feb 11 '19 18:02 davidcelis

Hello @davidcelis! Thanks for the reply... I have created a toy project to test this (https://github.com/alemata/pagination_and_cache)

I know this is not the ideal code to test but it's an idea of the issue

Ideeally we should be able to paginate... store that page result in cache and send the responde with pagination headers...

Sorry if I am being not so clear... please ping me with any question

alemata avatar Feb 12 '19 15:02 alemata

@davidcelis were you able to review this?! was the project helpfull?

alemata avatar Feb 17 '19 23:02 alemata

Ok I think I make it work...

# call paginate outside cache to add headers
paginated = paginate Property.all
paginated_collection = Rails.cache.fetch(Property.cache_key(properties)) do
  # Store just the collection in cache (`paginate method returns the collection`)
  paginated.to_a
end

paginated_collection

I am not sure if there is a nice way to improve this inside the gem...

alemata avatar Feb 18 '19 16:02 alemata