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 %>
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 %>
According to rails' documentation, you can simply name all the dependencies as the cache name. Refer to ActionView::Helpers::CacheHelper#cache
Since you are nesting cache (or called Russian Doll Caching), you will need to name all the dependencies in your nested cache at the outest cache block. Something like this:
<% cache [@profiles, current_user, current_user.roles] do <%>
# ...
<% end %>
Looking at the ActionView::Helpers::CacheHelper#fragment_name_with_digest method, it simply uses whatever you pass in to build the cache name. So you just need to make sure anything that could change is included in ANY affected cache block.
which doesn't seem to be the case, but just something to keep in mind, remember to add a version to the cache name, and bump the version whenever there is a change to the template. You will need to bump the version for all the outer block. Or opt to use cache digest gem, which already comes with Rails 4.
Let's identify all the variables here. You have the parent view which renders a collection of @profiles
. And the view will change according to if the current user is an admin. Not sure why params[:rating]
would matter in this case. And I am not sure what @selected_profile
is for either. But I assume it should be included.
Here's what I would do.
# In User model, add a method to tell if it's an admin
# because "user.roles.first" seems fragile to me. what if the "roles" collection is sorted differently?
def admin?
roles.where(name: 'admin').present?
end
# In the view
<% cache [@profiles, current_user, current_user.admin?, @selected_profile] do %>
# ...
When rendering collections, you can actually pass in a cached
option. And "If your collection cache depends on multiple sources (try to avoid this to keep things simple), you can name all these dependencies as part of a block that returns an array" according to here and here.
<%= render partial: "profile", collection: profiles, cached: -> profile { [ profile, current_user, current_user.admin?, @selected_profile ] } %>
And you shouldn't need to have another cache block in the partial.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With