How to eager-load fixture associations in Rails 6.1?

strict_loading_by_default was added to ActiveRecord 6.1. How can we eager load fixture associations to make tests pass once this flag is used?

class ApplicationRecord < ActiveRecord::Base
  self.strict_loading_by_default = true
end

# app/models/post.rb
class Post < ApplicationRecord
  belongs_to :author
end

# app/models/author.rb
class Author < ApplicationRecord; end

# test/fixtures/posts.yml
my_post:
  author: my_author

# test/fixtures/authors.yml
my_author: {}

# test/models/post_test.rb
class PostTest < ActiveSupport::TestCase
  test "post belongs to author" do
    post = posts(:my_post)

    assert post.author # Minitest::UnexpectedError: ActiveRecord::StrictLoadingViolationError: 
                       # `Author` called on `Post` is marked for strict_loading and cannot be lazily loaded.
  end
end

I think this is a bug. Can you please test if https://github.com/rails/rails/pull/40792 fixes it for you?

1 Like

Thanks @ghiculescu, it works!

FYI that’s merged and on the 6-1-stable branch now.

Thanks @ghiculescu, good news :+1:

I gave another try to this strict_loading feature, both using self.strict_loading_by_default = true on the model and by passing .strict_loading to the association. However because of the new fix described in this thread, the actual N+1 query problems don’t get caught in tests and thus the parity between test and prod is lost (no exceptions are raised in tests even when executing code with N+1 queries, but exceptions are raised once running the same code in prod).

Therefore, what is the proper/official way to do non-regression testing of associations which are strictly loaded? Is this documented somewhere? Is there any way to restore the functionality even when using fixtures, or does it mean we cannot use fixtures any more? Should the tests be rewritten? What is the new alternative?

@ghiculescu or others, any advice? Any insight would be very much appreciated, thanks :blush:

OK it seems that my problems are not about fixtures (thanks @ghiculescu for the guidance in the GitHub issue), however I didn’t manage to enforce strict loading in this example, any ideas?

If you eager load an association with a specified :limit option, it will be ignored, returning all the associated objects:

class Picture < ActiveRecord::Base
  has_many :most_recent_comments, -> { order('id DESC').limit(10) }, class_name: 'Comment'
end

Picture.includes(:most_recent_comments).first.most_recent_comments # => returns all associated comments.

Eager loading is supported with polymorphic associations.

class Address < ActiveRecord::Base
  belongs_to :addressable, polymorphic: true
end

A call that tries to eager load the addressable model

Address.includes(:addressable)

This will execute one query to load the addresses and load the addressables with one query per addressable type. For example, if all the addressables are either of class Person or Company, then a total of 3 queries will be executed. The list of addressable types to load is determined on the back of the addresses loaded.

Did you have a fix on this issue? I have the same problem with Facing same issue but no response from anyone and couldnt find this topic troubleshooting in google.

@Lexingtonn the specific issue I had (there might be others) was that find_by doesn’t care about eager loading. A fix was proposed by Alex in the thread I linked:

1 Like