Ashbury
Ashbury

Reputation: 2346

Rendering many partials in rails (500+) is slow

I made a partial of a for a song model with artist, title, duration, release etc.

I want to show all the artists songs on one page, sometimes they have a ton. The query takes 0.08 seconds, but I also see this:

Rendered artist/_song_listing.html.haml (18.2ms)
Rendered artist/_song_listing.html.haml (8.5ms)
Rendered artist/_song_listing.html.haml (7.5ms)
Rendered artist/_song_listing.html.haml (9.6ms)
Rendered artist/_song_listing.html.haml (18.6ms)
Rendered artist/_song_listing.html.haml (12.6ms)
Rendered artist/_song_listing.html.haml (7.8ms)
Rendered artist/_song_listing.html.haml (19.5ms)

(etc etc)

Ultimately this takes 14 seconds, which is way too long.

Is it wrong to use partials in this way? Is there any way to make this faster?

Edit:

ArtistController:

  def show

    @artist = Artist.find(params[:id])
    @songs = @artist.songs.order('published_at DESC').includes(:members)

show.html.haml:

  .panel.panel-default
    - @artist.songs.each do |song|
      =render 'song_listing', song: song

Exerpt from _song_listing (~500 times):

.row
  .col-xs-12
    .summary
      -if song.summary.present?
        ="#{song.summary.sanitize.strip.gsub("\u00A0"," ")}"
      -else
        %i
          No Summary

.row
  .col-xs-10
    %ul.list-inline
      - song.members.each do |member|
        %li
          %span
            %img{src:"#{member.image_url}", width: '20px', height: '20px', class: 'img-circle'}

Upvotes: 3

Views: 2069

Answers (3)

Cremz
Cremz

Reputation: 838

I know it's been ages, but I thought an improvement to the current answers might help others as well

  .panel.panel-default
    =render partial: 'song_listing', collection: @artist.songs, as: :song

This is much faster in terms of rendering. not as fast as inline rendering, but much better than doing a render for each item.

Upvotes: 2

aaron-coding
aaron-coding

Reputation: 2621

Is the load coming from the SQL queries? Try pre-loading in your controller.

@songs = Song.all.includes(:artist,:title)

Then something like

@songs.each do |song|
  # render logic here for each song
end

In the includes you would put any related associations, which are not loaded automatically.

This should make each partial rendering much faster, if SQL queries were your problem.

Further instructions to include from the first look up:

@artist = Artist.find(params[:id]).includes(:songs => [:members])
@songs = @artist.songs.order('published_at DESC')

I believe this will do the trick for you. However what you had earlier would still be OK. Not sure if the brackets around ":members" are required, but essentially you are saying, include Artist's songs, and for each song include it's members.

Upvotes: 3

pcm
pcm

Reputation: 319

It sounds like you are possibly doing a database lookup for each song. Try to load all the song data in a single query. It may also help to post your view code if indeed the rendering is the bottleneck.

Upvotes: 1

Related Questions