Reputation: 598
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
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