【问题标题】:How make caching work with pagination and search form?如何使缓存与分页和搜索表单一起使用?
【发布时间】:2017-08-25 02:23:46
【问题描述】:

我在 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

【问题讨论】:

  • 当您说“它不起作用”时,您能详细说明一下吗?分页是否出现并且不正确?还是没有分页?您的日志中有错误吗?
  • 是的,它不起作用。现在我有 5 个产品和分页设置每页 1 个产品。所以现在有 5 页,每页显示所有产品。

标签: ruby-on-rails ruby ruby-on-rails-3 caching pagination


【解决方案1】:

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

  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 集合缓存

渲染助手还可以缓存为 收藏。它甚至可以将前面的示例与每个通过 一次读取所有缓存模板,而不是一一读取。这是 通过在渲染集合时传递 cached: true 来完成:

之前渲染的所有缓存模板将在 一次以更快的速度。此外,没有的模板 尚未缓存的将被写入缓存并在下一次被多次提取 渲染。

否则,如果您是 Multi Fetch Fragments gem 启用此功能。

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

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

【讨论】:

  • 一切正常。但是现在缓存不使用 product_helper.rb 是吗?是的,我使用 Rails 5。
  • 正确,这意味着您不能在产品更新时使您的缓存失效。您可以将 Proc 传递给 cache: 调用,我会更新我的答案。
猜你喜欢
  • 2017-01-25
  • 2014-06-04
  • 1970-01-01
  • 2013-03-22
  • 2016-03-05
  • 1970-01-01
  • 2013-08-01
  • 2018-11-12
  • 1970-01-01
相关资源
最近更新 更多