Skip to content

Commit

Permalink
Support association strict_loading option (#1607)
Browse files Browse the repository at this point in the history
strict_loading was added to Rails 6.1 to prevent lazy loading of associations.

As adding it to an association declaration can have a massive impact on the way the record and its association is treated, it can be useful to ensure in a test suite the presence of this option.

This adds support for adding the strict_loading option to an association declaration.

Co-authored-by: Jose Blanco <jose.blanco@thoughtbot.com>
  • Loading branch information
rhannequin and laicuRoot authored Feb 27, 2024
1 parent 6488e3a commit 30407f2
Show file tree
Hide file tree
Showing 5 changed files with 482 additions and 0 deletions.
51 changes: 51 additions & 0 deletions lib/shoulda/matchers/active_record/association_matcher.rb
Original file line number Diff line number Diff line change
Expand Up @@ -217,6 +217,36 @@ module ActiveRecord
# should belong_to(:organization).touch(true)
# end
#
# ##### strict_loading
#
# Use `strict_loading` to assert that the `:strict_loading` option was specified.
#
# class Organization < ActiveRecord::Base
# has_many :people, strict_loading: true
# end
#
# # RSpec
# RSpec.describe Organization, type: :model do
# it { should have_many(:people).strict_loading(true) }
# end
#
# # Minitest (Shoulda)
# class OrganizationTest < ActiveSupport::TestCase
# should have_many(:people).strict_loading(true)
# end
#
# Default value is true when no argument is specified
#
# # RSpec
# RSpec.describe Organization, type: :model do
# it { should have_many(:people).strict_loading }
# end
#
# # Minitest (Shoulda)
# class OrganizationTest < ActiveSupport::TestCase
# should have_many(:people).strict_loading
# end
#
# ##### autosave
#
# Use `autosave` to assert that the `:autosave` option was specified.
Expand Down Expand Up @@ -1128,6 +1158,11 @@ def touch(touch = true)
self
end

def strict_loading(strict_loading = true)
@options[:strict_loading] = strict_loading
self
end

def join_table(join_table_name)
@options[:join_table_name] = join_table_name
self
Expand Down Expand Up @@ -1170,6 +1205,7 @@ def matches?(subject)
conditions_correct? &&
validate_correct? &&
touch_correct? &&
strict_loading_correct? &&
submatchers_match?
end

Expand Down Expand Up @@ -1414,6 +1450,21 @@ def touch_correct?
end
end

def strict_loading_correct?
return true unless options.key?(:strict_loading)

if option_verifier.correct_for_boolean?(:strict_loading, options[:strict_loading])
return true
end

@missing = [
"#{name} should have strict_loading set to ",
options[:strict_loading].to_s,
].join

false
end

def class_has_foreign_key?(klass)
@missing = validate_foreign_key(klass)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,10 @@ def has_and_belongs_to_many_name
reflection.options[:through]
end

def strict_loading?
reflection.options.fetch(:strict_loading, subject.strict_loading_by_default)
end

protected

attr_reader :reflection, :subject
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,10 @@ def actual_value_for_class_name
reflector.associated_class
end

def actual_value_for_strict_loading
reflection.strict_loading?
end

def actual_value_for_option(name)
option_value = reflection.options[name]

Expand Down
18 changes: 18 additions & 0 deletions spec/support/unit/helpers/application_configuration_helpers.rb
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,24 @@ def with_belongs_to_as_optional_by_default(&block)
)
end

def with_strict_loading_by_default_enabled(&block)
configuring_application(
::ActiveRecord::Base,
:strict_loading_by_default,
true,
&block
)
end

def with_strict_loading_by_default_disabled(&block)
configuring_application(
::ActiveRecord::Base,
:strict_loading_by_default,
false,
&block
)
end

private

def configuring_application(config, name, value)
Expand Down
Loading

0 comments on commit 30407f2

Please sign in to comment.