Search code examples
ruby-on-railscachingruby-on-rails-5russian-doll-caching

Why does this cache statement not write the key I expect?


I have this in my _profile.html.erb partial:

<% cache [current_user.roles.first, profile, @selected_profile, params[:rating]] do %>

Yet this is what I see in my server log:

Read fragment views/profiles/26-20161212033839290582/profiles/52-20161213010040474070/profiles/14-20161213015458288839/profiles/34-20161212035644491093/profiles/33-20161212035644237925/profiles/38-20161207092843851446/profiles/35-20161212040016291016/profiles/36-20161212040016565707/profiles/4-20161213021028862933/profiles/39-20161207092843925084/profiles/46-20161207092844067579/profiles/47-20161207223703646028/profiles/37-20161212040016656625/660bdc6ad0b20e4c5329112cf79946f7 (0.1ms)

I am seeing nothing about roles there.

What's happening is that if I log in as a user with an admin role, and then login as a user with another role, I am seeing the cached profiles that are displayed as if I am an admin and not as that other user with the correct view.

What could be causing this and how do I fix it?

Edit 1

If I change the cache statement to be this:

<% cache [current_user, profile, @selected_profile, params[:rating]] do %>

And refresh, this is what the logs look like:

Write fragment views/users/2-20161218005548388099/profiles/37-20161212040016656625///bb163edd4a8c7af2db71a04243338e7b (0.1ms)
  Rendered collection of profiles/_profile.html.erb [1 times] (25.4ms)
Write fragment views/profiles/26-20161212033839290582/profiles/52-20161213010040474070/profiles/14-20161213015458288839/profiles/34-20161212035644491093/profiles/33-20161212035644237925/profiles/38-20161207092843851446/profiles/35-20161212040016291016/profiles/36-20161212040016565707/profiles/4-20161213021028862933/profiles/39-20161207092843925084/profiles/46-20161207092844067579/profiles/47-20161207223703646028/profiles/37-20161212040016656625/83ddeaa031bf68e602ce66af2d268317 (0.1ms)

Edit 2

When I binding.pry into the _profile.html.erb, I get the following:

[3] pry(#<#<Class:0x007f968480ec98>>)> current_user.roles.first
=> #<Role:0x007f969e4422a8 id: 1, name: "admin", resource_id: nil, resource_type: nil, created_at: Mon, 12 Sep 2016 00:38:47 UTC +00:00, updated_at: Mon, 12 Sep 2016 00:38:47 UTC +00:00>

I even tried the following:

<% cache [current_user.roles.first.name, profile, @selected_profile, params[:rating]] do %>

And it still gives me the same cached results when logged in as a non-admin user as it does an admin user.

Edit 3

Here is the cache block that calls the collection that invokes _profile.html.erb:

  <% cache @profiles do %>
    <div class="wrapper wrapper-content">
    <% @profiles.to_a.in_groups_of(3, false).each do |profiles| %>
        <div class="row">
            <%= render partial: "profile", collection: profiles %>
        </div>
    <% end %>
    </div>
  <% end %>

Solution

  • Your parent cache is preventing the children caches from doing their job correctly. You can either remove the parent cache, or just move it to the top and then each child can be separate

    Replace <% cache @profiles do %> with:

    <% cache [current_user.roles.first.try(:name), @profiles, @selected_profile, params[:rating]] do %>
    

    and then the inner _profile.html.erb

    <% cache [current_user.roles.first.try(:name), profile, @selected_profile, params[:rating]] do %>