ruby 31 lines · 8 steps

Aggregating post stats in a Rails scope

A single scope computes per-author aggregates in SQL, with reader methods that gracefully fall back when the columns aren't loaded.

Explained by highlit
1class Author < ApplicationRecord
2 has_many :posts
3 
4 scope :with_post_stats, -> {
5 left_joins(:posts)
6 .select(
7 "authors.*",
8 "COUNT(posts.id) AS posts_count",
9 "COALESCE(SUM(posts.views), 0) AS total_views",
10 "MAX(posts.published_at) AS last_published_at"
11 )
12 .group("authors.id")
13 }
14 
15 def posts_count
16 read_attribute(:posts_count) || posts.count
17 end
18 
19 def total_views
20 read_attribute(:total_views).to_i
21 end
22 
23 def last_published_at
24 value = read_attribute(:last_published_at)
25 value.is_a?(String) ? Time.zone.parse(value) : value
26 end
27 
28 def active_publisher?
29 last_published_at.present? && last_published_at > 90.days.ago
30 end
31end
01 / 01
STEP 01

Walkthrough

Space play step click any line
Three takeaways
  1. 1Pushing COUNT/SUM/MAX into a single grouped query avoids N+1 queries across authors.
  2. 2Aliased SQL columns surface as read-only attributes you access with read_attribute.
  3. 3Guarding computed readers keeps models correct whether or not the aggregate scope was applied.

Related explainers

Share this explainer

Here's the card — post it anywhere.

Aggregating post stats in a Rails scope — share card
Made with highlit — turn any snippet into a walkthrough like this in about a minute.
Explain your code