Strict Loading Using :n_plus_one_only Mode Does Not Eagerly Load Child Associations In Rails 7.2.

Rails strict_loading mode is to prevent lazy loading of associations.

When the strict_loading mode is used, the associated records will have to be eager loaded using includes else a ActiveRecord::StrictLoadingViolationError will be raised.

This mode helps in identifying and fixing N+1 query issues by ensuring that certain associations are loaded eagerly to avoid performance bottlenecks.

class Client < ApplicationRecord
  has_many :projects
end
Client.strict_loading.first.projects 

# raises ActiveRecord::StrictLoadingViolationError
class Client < ApplicationRecord
  has_many :projects, strict_loading: true
end
Client.first.projects

# raises ActiveRecord::StrictLoadingViolationError
Client.includes(:projects).first.projects
  
  Client Load (0.7ms)  SELECT "clients".* FROM "clients" ORDER BY "clients"."id" ASC LIMIT $1  [["LIMIT", 1]]
  Project Load (2.4ms)  SELECT "projects".* FROM "projects" WHERE "projects"."client_id" = $1  [["client_id", 1]]

# =>                      
[#<Project:0x00000011133aaa48
  id: 1,
  client_id: 1,
  name: "Miru",
  description: "Time tracking">,
 #<Project:0x0000001111f150b0
  id: 2,
  client_id: 1,
  name: "Azure.com",
  description: "Cloud Computing">
]

Before

Strict loading in :n_plus_one_only mode is specifically designed to address performance issues that can arise when navigating through deeply nested associations

It allows direct loading of associations while restricting deeper traversal, preventing potential N+1 query issues and surprises related to ordering inconsistencies.

client = Client.find(1)
client.strict_loading!(mode: :n_plus_one_only)
client.projects.first

# SELECT "projects".* FROM "projects" WHERE "projects"."client_id" = $1  [["client_id", 1]] -- non-deterministic order

Where as navigating through deeply nested associations throws error

client.projects.first.timesheets # raises ActiveRecord::StrictLoadingViolationError

After

Strict loading using :n_plus_one_only does not eagerly load child associations.

With this change, child associations are no longer eagerly loaded, to match intended behavior and to prevent non-deterministic order issues caused by calling methods like first or last. As first and last don’t cause an N+1 by themselves, calling child associations will no longer raise.

It means associations are eagerly loaded and child associations are lazy loaded.

client = Client.find(1)
client.strict_loading!(mode: :n_plus_one_only)
client.projects.first

# SELECT "projects".* FROM "projects" WHERE "projects"."client_id" = $1  [["client_id", 1]] -- non-deterministic order

client.projects.first.timesheets # no longer raises error

Summary

With Strict loading, we can prevent lazy loading of associations as it raises ActiveRecord::StrictLoadingViolationError if the associated records are not eager loaded.

But With strict_loading!(mode: :n_plus_one_only), associations are eagerly loaded and child associations are lazy loaded.

Need help on your Ruby on Rails or React project?

Join Our Newsletter