rails从片段缓存中省略了一些部分

时间:2016-04-06 18:56:55

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

我有一个使用pundit gem进行授权的rails 4 app。如果我像下面的代码那样进行俄语玩偶片段缓存,那么用于授权的条件语句也将被缓存,这是不好的,因为编辑/删除按钮应仅适用于post.user

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

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

1 个答案:

答案 0 :(得分:2)

俄罗斯玩偶缓存是一种简单但方便的缓存方式,没有复杂的选项或惯例可以从中排除部分碎片。除此之外,它还与缓存策略相关。以下是针对此用户特定情况的两种策略:

  1. 手动重新排列和缓存片段,我不推荐。因为它更复杂,并没有利用俄罗斯娃娃缓存的优势。也不是那么可维护。这是一个例子:
  2. 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的一部分,这意味着您将拥有与用户大致相同的片段缓存,并且只要帖子或用户更改了指纹,片段就会自动失效。这更优雅,更易于维护。这是一个例子:
    2. 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 %>