Skip to content

Instantly share code, notes, and snippets.

@allspiritseve
Last active January 1, 2016 07:59
Show Gist options
  • Save allspiritseve/8115357 to your computer and use it in GitHub Desktop.
Save allspiritseve/8115357 to your computer and use it in GitHub Desktop.
Performance tips for Ruby on Rails

Re: This tweet

Partials as opposed to inlining?

Inlining, collection partials, helpers, or builder objects. Partials shouldn't be the only tool in your belt for reducing duplicated view code.

What's the alternative to AR instantiation? Better queries? find_each?

Depends on the situation.

With ActiveRecord it is easy to load the same object multiple times, especially when the same objects are being used in various places in the view, possibly filtered or grouped differently. I was able to cut my benchmark times in half by writing some helper classes that memoize a collection of AR objects and then expose methods to filter / group them as needed in the view. Here's a simplistic example:

# Original view

- assignment_types.each do |assignment_type|
  - assignment_type.assignments.each do |assignment|

# My proposed solution:

class CourseData
  def initialize(course)
    @course = course
  end
  
  def assignment_types
    @assignment_types ||= @course.assignment_types
  end
  
  def assignments_for_assignment_type(assignment_type)
    assignments_by_assignment_type_id[assignment_type.id]
  end
  
  private
  
  def assignments
    @assignments ||= @course.assignments
  end
  
  def assignments_by_assignment_type_id
    @assignments_by_assignment_type_id ||= assignments.group_by(&:assignment_type_id)
  end
end

- current_course_data.assignment_types.each do |assignment_type|
  - current_course_data.assignments_for_assignment_type(assignment_type).each do |assignment|

I ended up writing a few of these to optimize for different use cases (e.g. a professor generally looks at data for all students in a course, whereas a student generally looks at their own data).

If the problem is too many AR objects being loaded, but not many duplicates, then I think the solution is to rely on the database more. In simple cases, pluck can be used to get a few values directly. We've been using Postgres views to calculate cache keys, aggregate data, and perform complex filtering that was too unwieldy in a scope or class method.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment