如何使缓存与分页和搜索表单一起工作?

How make caching work with pagination and search form?

我在 rails 上与 ruby 合作,我的产品视图已缓存,我可以通过搜索表单找到产品。我也想使用分页,但是添加后,它没有用,也没有搜索表单。找到代码行,但不确定如何使用它,代码如下。

<% cache ["v1-#{params[:page]-#{params[:q]", cache_key_for_products]
> do %>

我的代码

Index.html.erb

<div class="products">
  <div class="container">
    <center><h1>All products</h1></center>
    <div class="row">
      <% cache(cache_key_for_products) do %>
      <%= render @products %>
      <% end %>
    </div>
    <%= will_paginate @comments, :container => false %>
  </div>
</div>

_product.html.erb

<% cache product do %>
<div class="col-md-3 col-lg-3 col-sm-6 col-xs-12">
  <div class="product-block">
    <h4 id="product-name"><%= product.name %></h4>
    <%= link_to product_path(product), class: 'product_link' do %>
      <%= image_tag(product.image_url, class: "img-responsive") %>
    <% end %>
    <div class="price">
      <h4>&pound; <%= product.price %></h4>
    </div>
  </div>
</div>
<% end %>

products_helper.rb

module ProductsHelper
  def cache_key_for_products
    count          = Product.count
    max_updated_at = Product.maximum(:updated_at).try(:utc).try(:to_s, :number)
    "products/#{params[:q] || "all"}-#{count}-#{max_updated_at}#{signed_in? && current_user.admin? ? "-admin" : "normal"}"
  end
end

products_controller.rb

def index
    if params[:q].present?
      search_term = params[:q]
      if Rails.env.development?
        @products = Product.where("name LIKE ?", "%#{search_term}%")
      else
        @products = Product.where("name ilike ?", "%#{search_term}%")
      end
    else
      @products = Product.all.paginate(:page => params[:page], :per_page => 30)
    end
  end

在您的控制器中,您似乎在不执行搜索时正确分页,但还需要将分页添加到您的搜索查询中:

  def index
    if params[:q].present?
      search_term = params[:q]
      if Rails.env.development?
        @products = Product.where("name LIKE ?", "%#{search_term}%").paginate(:page => params[:page], :per_page => 30)
      else
        @products = Product.where("name ilike ?", "%#{search_term}%").paginate(:page => params[:page], :per_page => 30)
      end
    else
      @products = Product.all.paginate(:page => params[:page], :per_page => 30)
    end
  end

您还缓存了每个搜索结果集,这意味着相同的产品可能会在许多不同的搜索中被缓存多次。这将很快使您的缓存膨胀。最好每个产品都缓存一次,不管搜索如何,都从缓存中获取这些产品。

我看到您正在缓存每个产品(_product.html.erb 部分)。在 index.html.erb 中将代码更改为:

<div class="products">
  <div class="container">
    <center><h1>All products</h1></center>
    <div class="row">
      <%= render @products, cache: true %>
    </div>
    <%= will_paginate @comments, :container => false %>
  </div>
</div>

这将利用 Rails 5 has built in:

的多提取片段缓存

1.3.1 Collection caching

The render helper can also cache individual templates rendered for a collection. It can even one up the previous example with each by reading all cache templates at once instead of one by one. This is done by passing cached: true when rendering the collection:

<%= render partial: 'products/product', collection: @products, cached: true %> All cached templates from previous renders will be fetched at once with much greater speed. Additionally, the templates that haven't yet been cached will be written to cache and multi fetched on the next render.

否则,如果您 < Rails 5,请使用 Multi Fetch Fragments gem 启用此功能。

index.html.erb 中,您可以将集合缓存呈现修改为这样的内容以使用自定义缓存键:

<%= render @products, cache: Proc.new{|item| [item, 'show']} %>