【问题标题】:Ruby on Rails: alternative to nested partials (which are too slow)Ruby on Rails:替代嵌套部分(太慢)
【发布时间】:2014-12-16 15:51:11
【问题描述】:

我需要我的 Rails 应用程序来生成巨大的表(大约 5-7 列,大约 2000-3000 行),它是供公司内部使用的,所以我们不关心流量等等。

正在显示的对象的结构应该是相当灵活的:当某些列被添加/更改/删除时,它只在一个地方被更改(除了修改数据库架构),所有的视图(索引、显示、编辑表单) 自动更新。

我之前完全没有使用 Rails 的经验。我将部分作为重用代码的一种方式(这是一件好事),因此,我没有看到使用嵌套的子子子部分没有什么不好的。比如说,我有几个模型,index 每个模型的视图 renders 通用部分 gen_index,对于表格的每个单元格都有特殊的部分 gen_field_view

同样的部分gen_field_view 是从show 视图中渲染出来的,所以,我真的很想把它作为一个部分。

如果我只有 600 行和 5 列,这个部分会被渲染 3000 次。这对我来说是一个巨大的惊喜,因为 Rails 如此困难:目前生成页面大约需要 7 秒。如果我删除 gen_field_view 部分并将其直接包含到 gen_index 部分中,大约需要 3 秒:快两倍多(无论如何这很慢,但这是不同的故事)。

在这种情况下,我们似乎应该避免嵌套部分,但是,我们还应该使用什么来重用视图代码?

我们或许可以从模型中的某个方法返回 html 代码,但它实际上扼杀了 Rails 的想法,而且毕竟不方便。

【问题讨论】:

  • 如果你在开发中运行,那么检查生产中的速度有多快 - 在开发中,rails 会更多地检查磁盘上的部分是否发生了变化
  • @FrederickCheung 你是对的,在生产中它的工作速度大约快 2-3 倍。但即便如此,如果我删除部分并直接包含它,差异大约是 2 倍。我对 Rails 中的局部执行缓慢感到非常失望。

标签: ruby-on-rails


【解决方案1】:

使用缓存策略怎么样?你可以使用rail's fragment cashing feature:

<% Product.all.each do |p| %>
  <% cache(p) do %>
    <%= render partial: 'some_partial', locals: {product: p} %>
  <% end %>
<% end %>

【讨论】:

  • 为什么要使用 gem 来执行此操作,因为它已集成在 rails 4 中(请参阅github.com/rails/cache_digests)?再加上这颗宝石看起来不再维护了 (github.com/n8/multi_fetch_fragments)
  • @DimitriJorge 出于某种原因,使用cache 你建议它甚至比没有它需要更长的时间:没有缓存:Completed 200 OK in 7666ms (Views: 7458.6ms | ActiveRecord: 202.6ms),有缓存:Completed 200 OK in 8135ms (Views: 7917.0ms | ActiveRecord: 212.3ms)
  • 第一次渲染应该需要更长的时间是的,但理论上应该更快
  • 奇怪的是,下面是7697ms,还是比没有缓存慢一点。
【解决方案2】:

你可以尝试的一些事情是

  • Caching 主要部分结果将在记录未更新时重复使用
  • 在页面上将记录渲染为json并渲染表格行的模板,然后使用javascript渲染实际表格

    <div id="data" data-records="<%= @products.to_json %>"></div>
    
    <script>
    jQuery.each(jQuery("#data").data("records"), function(record) {
      jQuery("<li>").text(record.title).appendTo("#my-table")
    })
    </script>
    
  • 使用 will_paginate 之类的 gem 进行分页,然后减少同时显示在页面上的记录数量
  • 使用将 html 呈现为字符串的演示对象

    class ModelPresentation
      def initialize(model)
        @model = model
      end
    
      def render
        [title, rate].join
      end
    
      def title
        "<h3>@model.title</h3>"
      end
    
      def rates
        "<span>Rate #{@model.score}</span>"
      end
    end
    

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-12-28
    • 2011-06-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-07-07
    • 2016-02-26
    相关资源
    最近更新 更多