1

J'ai une application rails 4 utilisant pundit gem pour l'autorisation. Si je fais la mise en cache de fragments de poupées russes comme le code ci-dessous, l'instruction conditionnelle utilisée pour l'autorisation sera également mise en cache, ce qui n'est pas bon puisque les boutons edit/delete ne devraient être disponibles que pour le post.user.des rails omettant certaines parties de la mise en cache des fragments

Quelle est la meilleure façon de contourner ce problème? Devrais-je diviser le cache en plus petites parties ou existe-t-il un moyen d'exclure certaines parties de la mise en cache? Quelle est la convention des rails dans ce cas?

index.html.erb

<% cache ["posts-index", @posts.map(&:id), @posts.map(&:updated_at).max, @posts.map {|post| post.user.profile.updated_at}.max] do %> 
    <%= render @posts %> 
<% end %> 

_post.html.erb

<% cache ['post', post, post.user.profile ] do %> 

    <div class="row> 
    <div class="col-md-2"> 
     <%= link_to user_path(post.user) do %> 
     <%= image_tag post.user.avatar.url(:base_thumb), class: 'post-avatar' %> 
     <% end %> 
    </div> 

    <div class="col-md-8"> 
     <span class="post-user-name"><%= post.user.full_name %></span> 
     <span class="post-updated"><%= local_time_ago(post.updated_at) %></span> 
     <div class="post-body"> 
     <%= post.body %> 
     </div> 

    <div class="col-md-2" style="text-align:right;"> 

     <!--############### THIS IS THE PART THAT SHOULD NOT BE CACHED #############--> 

     <% if policy(post).edit? && policy(post).delete? %> 
     <li class="dropdown"> 
      <ul class = "dropdown-menu dropdown-menu-right"> 
      <li> 
       <%= link_to "Edit Post", edit_post_path(post), remote: true, type: "button", 'data-toggle' => "modal", 'data-target' => "#updatepost_#{post.id}" %> 
      </li> 
      <li> 
       <a href="#" data-toggle="modal" role="button" data-target="#deletepost_<%= post.id %>">Delete Post</a> 
      </li> 
      </ul> 
     </li> 
     <% end %> 

     <!--########################## UNTIL HERE ############################--> 

    </div> 
    </div> 

    <div class = "row comment-top-row" style="padding-bottom:10px;"> 
    <div class="col-md-12 post-comment-form"> 
     <%= render partial: 'posts/post_comments/post_comment_form', locals: { post: post } %> 
    </div> 
    </div> 

    <div class = "row"> 
    <div class="col-md-12 post-comment-insert-<%= post.id%>"> 
     <%= render partial: 'posts/post_comments/post_comment', collection: post.post_comments.ordered.included, as: :post_comment, locals: {post: post} %> 
    </div> 
    </div> 

    <% if policy(post).edit? %> 
    <div class="modal fade updatepost" id="updatepost_<%= post.id %>" tabindex="-1" role="dialog" aria-labelledby="myModalLabel"> 
     <!-- FORM GETS RENDERED HERE VIA JS --> 
    </div> 
    <% end %> 

    <% if policy(post).delete? %> 
    <div class="modal fade" id="deletepost_<%= post.id %>" tabindex="-1" role="dialog" aria-labelledby="myModalLabel"> 
     ...... 
    </div> 
    <% end %> 

<% end %> 

Répondre

1

Doll russe est Caching moyen simple mais pratique pour la mise en cache, il n'y a pas d'options complexes ou convention pour exclure une partie du fragment à partir de cela. Au-dessus, c'est plus relatif aux stratégies de cache. Voici deux stratégies pour cette situation spécifique de l'utilisateur:

  1. Réorganiser individuellement et les fragments de cache manuellement, ce que je ne recommande pas. Parce que c'est plus complexe et ne tire pas parti des avantages de Russian Doll Caching. Pas aussi facile à maintenir. Voici un exemple:

index.html.erb

<% # pull out cache %> 
<%= render @posts %> 

_post.html.erb

<% cache post %> 
    <%= # first part %> 
<% end %> 

<% # without cache %> 
<%= # user specific part %> 

<% cache post %> 
    <%= # third part %> 
<% end %> 
  1. façon préférée: Ajouter current_user comme une partie de cache_key, ce qui signifie que vous aurez autant de caches de fragments que vos utilisateurs et que les fragments seront automatiquement invalidés chaque fois que le post ou l'utilisateur aura changé son empreinte digitale. C'est plus élégant et maintenable. Voici un exemple:

index.html.erb

<% cache ["posts-index", @posts.map(&:id), @posts.map(&:updated_at).max, @posts.map {|post| post.user.profile.updated_at}.max] do %> 
    <%= render @posts %> 
<% end %> 

_post.html.erb

<% cache ['post', post, post.user.profile, current_user ] do %> 
    <div class="row> 
    <div class="col-md-2"> 
     <%= link_to user_path(post.user) do %> 
     <%= image_tag post.user.avatar.url(:base_thumb), class: 'post-avatar' %> 
     <% end %> 
    </div> 

    <div class="col-md-8"> 
     <span class="post-user-name"><%= post.user.full_name %></span> 
     <span class="post-updated"><%= local_time_ago(post.updated_at) %></span> 
     <div class="post-body"> 
     <%= post.body %> 
     </div> 

    <div class="col-md-2" style="text-align:right;"> 
     <% if policy(post).edit? && policy(post).delete? %> 
     <li class="dropdown"> 
      <ul class = "dropdown-menu dropdown-menu-right"> 
      <li> 
       <%= link_to "Edit Post", edit_post_path(post), remote: true, type: "button", 'data-toggle' => "modal", 'data-target' => "#updatepost_#{post.id}" %> 
      </li> 
      <li> 
       <a href="#" data-toggle="modal" role="button" data-target="#deletepost_<%= post.id %>">Delete Post</a> 
      </li> 
      </ul> 
     </li> 
     <% end %> 
    </div> 
    </div> 

    <div class = "row comment-top-row" style="padding-bottom:10px;"> 
    <div class="col-md-12 post-comment-form"> 
     <%= render partial: 'posts/post_comments/post_comment_form', locals: { post: post } %> 
    </div> 
    </div> 

    <div class = "row"> 
    <div class="col-md-12 post-comment-insert-<%= post.id%>"> 
     <%= render partial: 'posts/post_comments/post_comment', collection: post.post_comments.ordered.included, as: :post_comment, locals: {post: post} %> 
    </div> 
    </div> 

    <% if policy(post).edit? %> 
    <div class="modal fade updatepost" id="updatepost_<%= post.id %>" tabindex="-1" role="dialog" aria-labelledby="myModalLabel"> 
     <!-- FORM GETS RENDERED HERE VIA JS --> 
    </div> 
    <% end %> 

    <% if policy(post).delete? %> 
    <div class="modal fade" id="deletepost_<%= post.id %>" tabindex="-1" role="dialog" aria-labelledby="myModalLabel"> 
     ...... 
    </div> 
    <% end %> 
<% end %> 
+0

abookyun, est cette deuxième façon assez bon? La mise en cache ne perdra-t-elle pas son but? Je veux dire que comme vous l'avez mentionné, le fragment sera réécrit pour chaque utilisateur. En plus de cela, ne va-t-il pas consommer trop de mémoire à long terme? –

+0

Pls également lire mon commentaire prev. J'ai oublié de mentionner (peut-être vous avez vu) que j'ai 'post_comment' imbriqué dans le' post' et 'post_comment_reply' imbriqué dans' post_comment'. Ceux-ci ne devraient être éditables que par le 'current_user', donc ceux-ci ont aussi des parties visibles uniquement par' current_user'. Est-ce que je dois changer ceux comme ceci ou «toucher» prend soin de cela? –

+0

@SzilardMagyar IMHO: Comme je l'ai dit, c'est un problème de stratégie, seulement s'il est possible de sauvegarder des requêtes lourdes comme des requêtes postées et des commentaires imbriqués, par exemple, si le template change fréquemment, . Vous pouvez lire cet article pour savoir comment la mise en cache affecte la vitesse de votre application https://signalvnoise.com/posts/3690-the-performance-impact-of-russian-doll-caching – abookyun