mycellius
mycellius

Reputation: 598

Should I keep a value in the child association AND parent to avoid an extra query?

Let's say I have a Book, which has_many Photos. When a user visits /books/1 I want to display each of the book's photos in a gallery, but on the index page (/books) I only want to display one photo for each book. Note that I've added a column to the Photos table called hero_image which will contain a boolean value.

Out of a book's 50 photos, only 1 will ever be a hero_image. In order to get all of the hero images for the index page, would it not be more efficient to simple include a column on the Book table such as hero_image that contains the same value (image-url) as the Photo that is a hero_image? Doing so would save me an extra query to the database which would look up Photos based on the hero_image field and the id of the books being displayed.

Another important consideration is that I frequently update every Photo through a rake task, so if I was to include an after_update callback that updates a Photo's parent if hero_image_changed? (using ActiveModel::Dirty) then that would also be somewhat expensive (there are a LOT of photos and each of them would trigger the aforementioned callback)

Upvotes: 1

Views: 40

Answers (1)

MrYoshiji
MrYoshiji

Reputation: 54882

You can define a simple has_one defining the principal_photo among the related photos:

class Book < ActiveRecord::Base
  has_many :photos
  has_one :principal_photo, -> { where(principal: true) }, class_name: 'Photo'

Eager Loading:

@books = Book.where(id: 1..999).includes(:principal_photo)

This code allows you to eager-load only the most relevant image and not all photos from a Book scope. This will produce only 2 SQL requests, one for retrieving the Book records and another one to retrieve their related Photo record defined as principal. This will save you from the pain of caching data and the callback hell behind it.

Upvotes: 1

Related Questions