Last active
February 10, 2023 02:16
-
-
Save coorasse/7b64571aab6352d972188f4710ecb274 to your computer and use it in GitHub Desktop.
Eager loading of association with parameter in Rails
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
begin | |
require 'bundler/inline' | |
rescue LoadError => e | |
warn 'Bundler version 1.10 or later is required. Please update your Bundler' | |
raise e | |
end | |
gemfile(true) do | |
source 'https://rubygems.org' | |
gem 'rails', '~> 5.2' | |
gem 'sqlite3' | |
end | |
require 'active_record' | |
require 'minitest/autorun' | |
require 'logger' | |
ActiveRecord::Base.establish_connection(adapter: 'sqlite3', database: ':memory:') | |
ActiveRecord::Base.logger = Logger.new(STDOUT) | |
# create your tables here | |
ActiveRecord::Schema.define do | |
create_table :products, force: true do |t| | |
t.string :name | |
end | |
create_table :users, force: true do |t| | |
t.string :name | |
end | |
create_table :custom_names, force: true do |t| | |
t.string :text | |
t.references :user | |
t.references :product | |
end | |
end | |
class Product < ActiveRecord::Base | |
has_many :custom_names, inverse_of: :product | |
end | |
class CustomName < ActiveRecord::Base | |
belongs_to :user | |
belongs_to :product, inverse_of: :custom_names | |
end | |
class User < ActiveRecord::Base | |
end | |
book, apple, orange = Product.create([{ name: 'book' }, { name: 'apple' }, { name: 'orange' }]) | |
mario, luigi = User.create([{ name: 'Mario' }, { name: 'Luigi' }]) | |
CustomName.create([{ user: mario, product: book, text: 'libro' }, | |
{ user: luigi, product: book, text: 'buch' }, | |
{ user: mario, product: apple, text: 'mela' }]) | |
puts '=== N+1 QUERIES EXAMPLE ===' | |
Product.all.each do |product| | |
puts "product name: #{product.name}. mario names: #{product.custom_names.where(user: mario).map(&:text)}" | |
end | |
puts '=== JOIN EXAMPLE ===' | |
Product.joins(:custom_names).where(custom_names: { user: mario }).all.each do |product| | |
puts "product name: #{product.name}. mario names: #{product.custom_names.map(&:text)}" | |
end | |
puts '=== INCLUDES EXAMPLE ===' | |
Product.includes(:custom_names).where(custom_names: { user: mario }).all.each do |product| | |
puts "product name: #{product.name}. mario names: #{product.custom_names.map(&:text)}" | |
end | |
puts '=== GOOD EXAMPLE ===' | |
products = Product.all.to_a | |
ActiveRecord::Associations::Preloader.new.preload(products, :custom_names, CustomName.where(user: mario)) | |
products.each do |product| | |
puts "product name: #{product.name}. mario names: #{product.custom_names.map(&:text)}" | |
end |
Thank you! I corrected it!
This does not work with rails 6.0.
=== GOOD EXAMPLE ===
D, [2020-10-30T12:39:37.843010 #94979] DEBUG -- : Product Load (0.0ms) SELECT "products".* FROM "products"
D, [2020-10-30T12:39:37.845379 #94979] DEBUG -- : CustomName Load (0.1ms) SELECT "custom_names".* FROM "custom_names" WHERE "custom_names"."user_id" = ? AND "custom_names"."product_id" IN (?, ?, ?) [["user_id", 1], ["product_id", 1], ["product_id", 2], ["product_id", 3]]
D, [2020-10-30T12:39:37.845798 #94979] DEBUG -- : CustomName Load (0.0ms) SELECT "custom_names".* FROM "custom_names" WHERE "custom_names"."product_id" = ? [["product_id", 1]]
product name: book. mario names: ["libro", "buch"]
D, [2020-10-30T12:39:37.846143 #94979] DEBUG -- : CustomName Load (0.0ms) SELECT "custom_names".* FROM "custom_names" WHERE "custom_names"."product_id" = ? [["product_id", 2]]
product name: apple. mario names: ["mela"]
D, [2020-10-30T12:39:37.846450 #94979] DEBUG -- : CustomName Load (0.0ms) SELECT "custom_names".* FROM "custom_names" WHERE "custom_names"."product_id" = ? [["product_id", 3]]
product name: orange. mario names: []
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Hey Alessandro! Thanks for the article.
Just minor points that I had to go through to successfully run the script:
ApplicationRecord
to fixeager_loading.rb:38:in
': uninitialized constant ApplicationRecord (NameError)`:puts product.records_by_owner
) becauseProduct#records_by_owner
isn't defined.