testsum
testsum

Reputation: 71

Rails render partial in a loop

I am new to rails and I am trying to render a partial within a loop as such.

Here , books is an array eager loaded in controller.

 books.each do |book|
   <%= render 'books/book', :book => book %>
 end

This works fine. But when the books array is really huge, it takes time for the view to load completely. Is there any other efficient way using which the same can be achieved?. I tried partial with collection(like here) as well, but even that did not make much difference in the load time of books. Any suggestions would be highly appreciated. Thanks.

Upvotes: 7

Views: 5896

Answers (6)

user2553863
user2553863

Reputation: 752

To summarize what I found, the helper is the way to go, as Dima Melnik succintly said. For instance, in your case, you could write a helper like this:

module BooksHelper # Or ApplicationHelper to be used globally

   def helper_render_book(book)
     # Insert partial's content here
   end

end

and then use it like this:

books.each do |book|
   <%= helper_render_book(book) %>
end

I was using partials like you, and having the same problem. I was listing about 300 students, and it felt slow. The view was taking around 2500 ms. I thought it was the amount of filesystem operations (altough they surely are cached), and tried reading the partial into a variable (outside the loop) and then doing an inline render in the loop:

<%= render inline: partial_content, locals: {student: student} %>

With this change, the view was taking around 2000 ms. And then, I tried inserting the contents of the partial into a helper, like I suggest. It's not very elegant, it doesn't feel like The Rails Way, but it took the view rendering to around 1600 ms, so it's better for performance.

Upvotes: 1

user1519372
user1519372

Reputation: 41

How about using "proc" on your view top, and then call it in your loop.

<% book_proc = proc do |book| %>
  #your html call
  <% nil %><%# return nil to prevent print out in last string %>
<% end %>

<% books.each do |book| %>
  <%= book_proc.call(book) %>
<% end %>

Upvotes: 1

Mauro Nidola
Mauro Nidola

Reputation: 506

I recently worked on a project in which I needed to render a table with about 1000 rows and I obviously experienced performance issues.

When pagination cannot be applied (due to requirements) and speed is required, then helpers is the solution (as already answered by Dima Melnik).

To prove what i said, i give a link to a performance test produced by Ben Scofield: http://viget.com/extend/helpers-vs-partials-a-performance-question

Upvotes: 1

Ingo Plate
Ingo Plate

Reputation: 31

You write that you're new to ruby/rails, so have you ever tried using pagination to solve your performance-problem?

A pagination will split your list into parts of e.g. 20 books and sets a paginator mostly at the bottom of your table.

Upvotes: 0

Dima Melnik
Dima Melnik

Reputation: 884

Rendering partial in a loop consume too much time because of open/close partial file every iteration. Instead of partial try to use your own helper for this purpose.

Upvotes: 3

sansarp
sansarp

Reputation: 1466

If you have list of values to display in the same view then you can iterate the values in the same view instead of rendering a new partial each time. If it's not the case then it is better to pass values from controller to your view. Hope it helps.

Upvotes: 1

Related Questions