Search code examples
ruby-on-railscachingruby-on-rails-4fragment-cachingrussian-doll-caching

Russian doll caching and permission-based links in view fragment


I've got a view that utilizes Russian Doll caching, where the whole collection of items is cached, and each item in the collection is cached individually within that cache.

However, each item in the collection should show edit/delete links based on the current user's permissions granted through CanCan. So, User A would only see the edit/delete links next to her own posts, but not next to User B's posts.

Well, whenever a post is created by User A, it's cached with the appropriate edit/delete links since she should have them visible based on her permissions. But when User B views the collection, he's served User A's cached post, along with the edit/delete links that he shouldn't see. Granted, CanCan prevents these edit/delete actions from occurring, but the links are still present.

Is there anyway around creating individual caches based on current_user.id and prevent having gobs of versions of (almost) identical cached content?


Solution

  • Is there anyway around creating individual caches based on current_user.id and prevent having gobs of versions of (almost) identical cached content?

    Instead of including the user's ID in the cache key, you could include the users' permissions. This would still have duplicate copies of the content, but scales as per your permission model, not the number of users. So instead of the typical:

    <% cache("posts/all-#{Post.maximum(:updated_at).try(:to_i)}") do %>
    ...
    <% end %>
    

    you can create a cache key like (assuming current_user returns the authenticated user) and you care about only editing vs. reading:

    <% cache("posts/all-#{Post.maximum(:updated_at).try(:to_i)}-#{current_user.can?(:edit, Post) ? :edit : :read}") do %>
    ...
    <% end %>
    

    Note that the cache key generation should probably be extracted to a separate class/helper method.