fail with nested preloading using rails v7.0
Closed this issue · 2 comments
gigorok commented
Hello, thanks for this gem!
I've been using the n1_loader gem (version 1.6.3) in my Ruby on Rails application and have run into an issue when using nested preloading. Whenever I try to use nested preloading like in the bug report, it throws a NoMethodError with the message "undefined method `future_classes' for N1Loader::LoaderCollection".
Bug report:
require 'bundler/inline'
gemfile(true) do
source 'https://rubygems.org'
git_source(:github) { |repo| "https://github.com/#{repo}.git" }
gem 'activerecord', '~> 7.0.0'
gem 'n1_loader', '1.6.3', require: 'n1_loader/active_record'
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)
ActiveRecord::Schema.define do
create_table :authors, force: true do |t|
end
create_table :posts, force: true do |t|
t.integer :author_id
t.text :body
end
create_table :comments, force: true do |t|
t.integer :post_id
end
end
class Author < ActiveRecord::Base
has_many :posts
end
class Post < ActiveRecord::Base
has_many :comments
belongs_to :author
n1_optimized :lines_count do |posts|
posts.each do |post|
fulfill(post, post.body.lines.count)
end
end
end
class Comment < ActiveRecord::Base
belongs_to :post
end
class BugTest < Minitest::Test
def test_nested_preloading
author = Author.create!
post = Post.create!(author:, body: "body\n123")
comment = Comment.create!(post:)
assert_equal comment, Comment.preload(:post).first
assert_equal comment, Comment.preload(post: %i[author]).first
assert_equal comment, Comment.preload(post: %i[lines_count]).first
assert_equal comment, Comment.preload(post: %i[author lines_count]).first # fail here
assert_equal comment.post.lines_count, 2
end
end
The bug report results:
1) Error:
BugTest#test_future_preloading:
NoMethodError: undefined method `future_classes' for #<N1Loader::LoaderCollection:0x00000001135e5ad8 @loader_class=#<Class:0x0000000113444c60>, @elements=[#<Post id: 1, author_id: 1, body: "body\n123">]>
loaders.flat_map(&:future_classes).uniq
^^^^^^^^^
/Users/igor.gonchar/.rbenv/versions/3.1.2/lib/ruby/gems/3.1.0/gems/activerecord-7.0.4.2/lib/active_record/associations/preloader/branch.rb:27:in `each'
/Users/igor.gonchar/.rbenv/versions/3.1.2/lib/ruby/gems/3.1.0/gems/activerecord-7.0.4.2/lib/active_record/associations/preloader/branch.rb:27:in `flat_map'
/Users/igor.gonchar/.rbenv/versions/3.1.2/lib/ruby/gems/3.1.0/gems/activerecord-7.0.4.2/lib/active_record/associations/preloader/branch.rb:27:in `immediate_future_classes'
/Users/igor.gonchar/.rbenv/versions/3.1.2/lib/ruby/gems/3.1.0/gems/activerecord-7.0.4.2/lib/active_record/associations/preloader/branch.rb:22:in `future_classes'
/Users/igor.gonchar/.rbenv/versions/3.1.2/lib/ruby/gems/3.1.0/gems/activerecord-7.0.4.2/lib/active_record/associations/preloader/batch.rb:21:in `block in call'
...
Environment:
Ruby version: 3.1.2
Rails version: 7.0.4.2
n1_loader version: 1.6.3
Additional Information:
I have fixed this error by defining the future_classes
method like this.
N1Loader::LoaderCollection.define_method :future_classes do
[]
end
Is it the right solution?
Please let me know if there is any additional information I can provide to help resolve this issue. Thank you.