将partial转换为method / block以获得速度

我有一个循环,呈现部分

1000.times do |i| render partial: 'test', locals: {i: i} end 

对于foreach渲染调用,这非常慢,最长可达0.1 ms,即使部分仅打印出i

 my_partial = render_to_method(partial: 'test') 1000.times do |i| my_partial(locals: {i: i}) end 

现在这应该以更快的方式做同样的事情吧? 但我不知道该怎么做。

更新:

我试过这样做:

 Haml::Engine.new(File.read(File.expand_path File.dirname(FILE)+"/../table/#{column.macro}/_#{column.display_type}.haml")) .‌​render(OpenStruct.new({column_value: column_value, object: object})) 

两个主要缺点:

  • 视图的路径不会像使用渲染时那样观察回退(parital:’partial’将在当前视图dir,某些gem以及视图/应用程序中查找parital。
  • Rails视图助手不再可用

更新2:

许多答案试图通过使用其他技术来解决问题。 我的真实应用这种技术无法应用。 https://github.com/antpaw/bhf/blob/master/app/views/bhf/pages/_platform.haml#L54主要是因为这一行是一个动态字符串,有时会链接到甚至不存在的部分在gem中并在main_app中定义。 我想知道为什么做一些如此基本的事情是如此困难:1。抓住观点。 2.渲染它。 (3.再次渲染。)

更新3:

@Flash Gordon建议这个https://gist.github.com/antpaw/d6670c23d6f08e35812e#file-gistfile1-haml-L54

 template = lookup_context.find_template "#{column.macro}/#{column.display_type}", ['bhf/table'], true template.render(self, {column_value: column_value, object: object}) 

它几乎与locals有一些麻烦。 但它已经感觉就像你抓住模板的部分,渲染部分很好分开。

以下是我以前的一个答案的例子。 它是从PartialRenderer源中提取的。

 - local_names = [:i] - partials = {} - 1000.times do |i| - name = 'name_%s' % (i % 10) - partials[name] ||= lookup_context.find_template(name, lookup_context.prefixes, true, local_names) = partials[name].render(self, i: i) 

我建议你用一个辅助方法包装它。 请记住,locals的名称在这里出现两次 :首先在local_names作为数组,第二个在hash的键中作为#render方法的第二个参数传递。

我喜欢这个问题,但它可能是“工作的错误工具”

基本上:

  1. 如果部分是简单的 – 考虑不使用部分,开销是不值得的
  2. 如果部分是复杂的 – 那么渲染1000个事物将花费时间,其中部分开销只是一小部分,你需要一个计划B

B计划:

  1. 最初渲染25-50-100 ….东西,并在用户滚动时从服务器获取其他记录 – http://railscasts.com/episodes/114-endless-page
  2. 从服务器发送一个JSON数组,让客户端JS遍历集合并呈现HTML – 这样部分模板仍然可以在rails中呈现,客户端JS可以做gsub
  3. 尽可能地缓存所有内容 – 这不包括不幸的forms,这通常是最慢的渲染组件

PS你试过细胞吗? https://github.com/apotonick/cells

这是一个有趣的命题,似乎比我想象的更难找到它的信息。 但是从我从response对象的实现中可以看出,我认为应该可以将输出附加( << )到response对象的stream对象。 这将在必要时作为字符串呈现到response#body #body中。

棘手的部分是找到一个定义my_partial方法的好地方。 虽然在View执行此操作并不常见,但仍然应该可以,我认为您应该可以直接访问response对象。 否则,您可以在帮助器中定义它,但您可能不希望在控制器中使用此代码。

对不起,如果这是一个想法而不是一个答案,但我没有时间正确测试它。

您可以添加辅助方法并使用content_tag 。 这实现了让方法作为局部工作的目标。

 def my_partial(i) content_tag(:div, i, class: 'iterator') end 

出于可读性的考虑,如果你的部分内容很多,那么使用带有content_tag辅助方法可能不是一个好的解决方案。

另一种建议:您可以渲染包含循环的单个部分,而不是在循环内多次渲染相同的部分。 如果需要仅为一个对象重用partial,则可以将对象作为数组传递。

这是一个更真实的例子:

 # index.html.erb <%= render partial: 'dogs', locals: {dogs: @dogs} %> # show.html.erb <%= render partial: 'dogs', locals: {dogs: [@dog]} %> # _dogs.html.erb <% dogs.each do |dog| %> <%= dog.name %> <% end %> 

使用:collection选项:

 = render partial: 'test', collection: 10.times.to_a, as: :i 

文档: http : //guides.rubyonrails.org/layouts_and_rendering.html#using-partials

资料来源: https : //github.com/rails/rails/blob/master/actionview/lib/action_view/renderer/partial_renderer.rb#L284

如果你需要多次渲染而且速度很慢,我建议你不要多次调用render 。 我知道,我是队长很明显。

如果locals包含简单的字符串或数字,请尝试渲染一次视图,然后只用实际变量替换部分。

 text = render(partial: 'test', locals: {i: '$'}) 1000.times do |i| output[i] = text.gsub('$', i) end