Search code examples
ruby-on-railsrubyperformanceruby-on-rails-4partial

Convert a partial to method/block for speed


I have a loop that renders a partial

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

this is really slow, up to 0.1 ms for foreach render call, even if the partial only prints out i

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

Now this should be doing the same thing way faster right? But I don't know how to do this.

update:

I've tried the to do it this way:

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})) 

two major drawbacks:

  • The path to the views will not watch for fallbacks like it does when you do it with render (parital: 'partial' will look for the parital in the current view dir, in some gems and also in the view/application.
  • The Rails view helpers aren't available any more

update 2:

Many of the answers try to solve the problem by using other techniques. I my real application this techniques can't be applied. https://github.com/antpaw/bhf/blob/master/app/views/bhf/pages/_platform.haml#L54‌​ mainly because this line is a dynamic string that sometimes links to partials that don't even exsist in the gem and are defined in the main_app. I wonder why it's so hard to do something that is so basic: 1. grab the view. 2. render it. (3. render it again.)

update 3:

@Flash Gordon suggested this 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})

it almost works just having some troubles with locals. But it already feels like the part where you grab the template and the render part is well separated.


Solution

  • Here is an example from one of my previous answers. It's extracted from PartialRenderer sources.

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

    I'd recommend you to wrap it with a helper method. Keep in mind that locals' names appear here twice: first in local_names as an array and second in hash's keys passed as the second argument of #render method.