【问题标题】:rails leaving out some parts from fragment cachingrails 从片段缓存中遗漏了一些部分
【发布时间】:2016-07-27 09:06:53
【问题描述】:

我有一个使用 pundit gem 进行授权的 rails 4 应用程序。如果我像下面的代码那样做俄罗斯娃娃片段缓存,用于授权的条件语句也会被缓存,这不好,因为编辑/删除按钮应该只对post.user可用。

解决这个问题的好方法是什么?我应该将缓存分成更小的部分还是有办法排除缓存的某些部分?在这种情况下,rails 约定是什么?

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 %>

【问题讨论】:

    标签: ruby-on-rails caching authorization pundit fragment-caching


    【解决方案1】:

    Russian Doll Caching 是一种简单但方便的缓存方式,没有复杂的选项或约定可以从中排除部分片段。除此之外,它更多地与缓存策略有关。以下是针对这种用户特定情况的两种策略:

    1. 单独重新排列并手动缓存片段,我不建议这样做。因为它更复杂并且没有利用俄罗斯娃娃缓存的优势。也不那么可维护。这是一个例子:

    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. 首选方式:将current_user 添加为cache_key 的一部分,这意味着您将拥有与您的用户一样多的片段缓存,并且每当帖子或用户更改指纹时片段将自动失效。这更加优雅和可维护。这是一个例子:

    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 %>
    

    【讨论】:

    • abookyun,这第二种方式够好吗?缓存不会失去它的目的吗?我的意思是,正如您提到的,将为每个用户重写片段。除此之外,从长远来看会不会消耗太多内存?
    • 请阅读我的上一条评论。我忘了提到(也许你看到了)我有 post_comment 嵌套到 postpost_comment_reply 嵌套到 post_comment。这些也应该只能由current_user 编辑,因此它们也有一些部分只有current_user 才能看到。我必须像这样改变那些还是touch 照顾那个?
    • @SzilardMagyar 恕我直言:正如我所说,这是一个策略问题,只有当有机会保存嵌套帖子和 cmets 查询等繁重的请求时,我认为这已经足够了,相比之下,如果模板经常变化,你需要另一个模板缓存结构。您可以阅读这篇文章来感受缓存如何影响您的应用速度signalvnoise.com/posts/…
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-02-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-12-05
    • 1970-01-01
    • 2019-12-23
    相关资源
    最近更新 更多