Skip to content

Add n_plus_one_only mode to Core#strict_loading!#41704

Merged
rafaelfranca merged 1 commit intorails:mainfrom
dinahshi:strict-loading-mode
Mar 25, 2021
Merged

Add n_plus_one_only mode to Core#strict_loading!#41704
rafaelfranca merged 1 commit intorails:mainfrom
dinahshi:strict-loading-mode

Conversation

@dinahshi
Copy link
Contributor

Add an optional mode argument to
Core#strict_loading! to support n_plus_one_only
mode. Currently, when we turn on strict_loading
for a single record, it will raise even if we are
loading an association that is relatively safe to
lazy load like a belongs_to. This can be helpful
for some use cases, but prevents us from using
strict_loading to identify only problematic
instances of lazy loading.

The n_plus_one_only argument allows us to turn
strict_loading on for a single record, and only
raise when a N+1 query is likely to be executed.
When loading associations on a single record,
this only happens when we go through a has_many
association type. Note that the has_many
association itself is not problematic as it only
requires one query. We do this by turning
strict_loading on for each record that is loaded
through the has_many. This ensures that any
subsequent lazy loads on these records will raise
a StrictLoadingViolationError.

For example, where a developer belongs_to a ship
and each ship has_many parts, we expect the
following behaviour:

  developer.strict_loading!(mode: :n_plus_one_only)

  # Do not raise when a belongs_to association
  # (:ship) loads its has_many association (:parts)
  assert_nothing_raised do
    developer.ship.parts.to_a
  end

  refute developer.ship.strict_loading?
  assert developer.ship.parts.all?(&:strict_loading?)
  assert_raises ActiveRecord::StrictLoadingViolationError do
    developer.ship.parts.first.trinkets.to_a
  end

cc @eileencodes @tenderlove

@dinahshi dinahshi force-pushed the strict-loading-mode branch 2 times, most recently from 6aec1f5 to 2c59901 Compare March 19, 2021 20:22
Copy link
Member

@eileencodes eileencodes left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you add a changelog and add the nodoc I commented on?

@dinahshi dinahshi force-pushed the strict-loading-mode branch from 3cadfb2 to 193db9c Compare March 22, 2021 19:54
Copy link
Member

@rafaelfranca rafaelfranca left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You need to fix the conflicts in the CHANGELOG

@dinahshi dinahshi force-pushed the strict-loading-mode branch from 193db9c to eeace1b Compare March 23, 2021 19:23
Add an optional mode argument to
Core#strict_loading! to support n_plus_one_only
mode. Currently, when we turn on strict_loading
for a single record, it will raise even if we are
loading an association that is relatively safe to
lazy load like a belongs_to. This can be helpful
for some use cases, but prevents us from using
strict_loading to identify only problematic
instances of lazy loading.

The n_plus_one_only argument allows us to turn
strict_loading on for a single record, and only
raise when a N+1 query is likely to be executed.
When loading associations on a single record,
this only happens when we go through a has_many
association type. Note that the has_many
association itself is not problematic as it only
requires one query. We do this by turning
strict_loading on for each record that is loaded
through the has_many. This ensures that any
subsequent lazy loads on these records will raise
a StrictLoadingViolationError.

For example, where a developer belongs_to a ship
and each ship has_many parts, we expect the
following behaviour:

  developer.strict_loading!(mode: :n_plus_one_only)

  # Do not raise when a belongs_to association
  # (:ship) loads its has_many association (:parts)
  assert_nothing_raised do
    developer.ship.parts.to_a
  end

  refute developer.ship.strict_loading?
  assert developer.ship.parts.all?(&:strict_loading?)
  assert_raises ActiveRecord::StrictLoadingViolationError do
    developer.ship.parts.first.trinkets.to_a
  end
@dinahshi dinahshi force-pushed the strict-loading-mode branch from 751ba32 to 5ec1cac Compare March 25, 2021 00:56
@rafaelfranca rafaelfranca merged commit 44c3ce2 into rails:main Mar 25, 2021
abhaynikam added a commit to abhaynikam/rails that referenced this pull request Apr 15, 2021
The return type was changed in the PR rails#41704 after addition of mode
option. The current documentation is misleading since
documentation puropose strict_loading! would return boolean whereas
it returns the current mode set.

I can across this issue while debugging issue: rails#41827 and thought
this should be brought to the attention.

PR fixes the issue and would always return boolean based on
strict_loading is enabled or disabled.

```
user.strict_loading! # => true
user.strict_loading!(false) # => false
user.strict_loading!(mode: :n_plus_one_only) # => true
```
@dinahshi dinahshi deleted the strict-loading-mode branch June 1, 2021 19:01
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants