Why doesn't this cache statement write the key that I expect?

I have this partial _profile.html.erb :

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

But 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 don't see anything about roles .

What happens if I log in as a user with the admin role, and then as a user with a different role, I see cached profiles that appear as if I were an administrator, and not as this other user with the correct view.

What could be the reason for this and how to fix it?

Change 1

If I change the cache statement as follows:

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

And update, 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 to _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 you logged in as a non-admin user, just like the admin user.

Edit 3

Here is the cache block that invokes 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 %> 
+5
source share
2 answers

Your parent cache does not allow child caches to do their job properly. You can either delete the parent cache, or simply move it to the beginning, and then each child can be divided

Replace <% cache @profiles do %> with:

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

and then internal _profile.html.erb

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

According to the rails documentation, you can simply name all the dependencies as the cache name. Refer to ActionView :: Helpers :: CacheHelper # cache

Since you have a nested cache (or call Russian Caching for a cap ), you will need to point all the dependencies in your nested cache to the outest cache block. Something like that:

 <% cache [@profiles, current_user, current_user.roles] do <%> # ... <% end %> 

Considering the ActionView :: Helpers :: CacheHelper # fragment_name_with_digest method, it simply uses everything you pass to create the cache name. Thus, you just need to make sure that everything that can change is included in ANY cache block.

If you are using Rails 3

which seems to be wrong, but just something to keep in mind, be sure to add the version to the cache name and sketch the version whenever there is a change in the template. You will need to corrupt the version for the entire external unit. Or select the cache cache digest that already comes with Rails 4.

Edit

We denote here all the variables. You have a parent view that displays a @profiles collection. And the view will change depending on whether the current user is an administrator. Not sure why params[:rating] will matter in this case. And I'm not sure what @selected_profile . But I guess it should be turned on.

Here is what I will do.

 # In User model, add a method to tell if it 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 pass the cached option. And "If your collection cache depends on several sources (try to avoid this so that everything is simple), you can name all these dependencies as part of the block that returns the array" according to here and here .

 <%= render partial: "profile", collection: profiles, cached: -> profile { [ profile, current_user, current_user.admin?, @selected_profile ] } %> 

And you do not need to have another partial cache block.

+2
source

Source: https://habr.com/ru/post/1261440/


All Articles