-
Notifications
You must be signed in to change notification settings - Fork 906
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Avoid N+1 queries coming from #version_limit when destroying records #1511
base: master
Are you sure you want to change the base?
Avoid N+1 queries coming from #version_limit when destroying records #1511
Conversation
ca5d339
to
2c8a96d
Compare
Specs are currently failing on `master` on my local machine when I try to run specs with `BUNDLE_GEMFILE=/home/david/code/paper_trail/gemfiles/rails_6.1.gemfile bundle exec rspec`. This isn't yet reflected in any CI builds on `master`, but I believe that it would be, if a build were to be triggered on `master`. The same error is also occurring in recent PRs that have been put up (e.g. [this PR][1] with [this failed build][2] and [this PR][3] with [this failed build][4]). [1]: paper-trail-gem#1509 [2]: https://github.com/paper-trail-gem/paper_trail/actions/runs/13835939334/job/38733099092?pr=1509 [3]: paper-trail-gem#1511 [4]: https://github.com/paper-trail-gem/paper_trail/actions/runs/13916744592/job/38941085149?pr=1511 I'm not sure why these errors have started occurring now, without any changes in `master` since [the last commit on `master`][5] that passed all checks. Maybe `bundler` changed its behavior, and we are pulling in a new/recent version of `bundler` with some relevant behavior change? [5]: paper-trail-gem@94e9c0d But, anyway, the errors seem to be caused by the extraction of various gems from the Ruby standard library into standalone gems, specifically: 1. `bigdecimal` 1. `drb` 1. `logger` 1. `mutex_m` This change adds those gems as development dependencies of `paper_trail`. Additionally, this change adds a `require "logger"` statement to `spec/spec_helper.rb`. This isn't needed for the other gems (I'm guessing because `activerecord` and/or `actionpack` have `require` statements for `bigdecimal`, `drb`, and `mutex_m`?), but it is needed for `logger`; without it, we get an error when trying to boot specs about `NameError: uninitialized constant ActiveSupport::LoggerThreadSafeLevel::Logger`.
Specs are currently failing on `master` on my local machine when I try to run specs with `BUNDLE_GEMFILE=/home/david/code/paper_trail/gemfiles/rails_6.1.gemfile bundle exec rspec`. This isn't yet reflected in any CI builds on `master`, but I believe that it would be, if a build were to be triggered on `master`. The same error is also occurring in recent PRs that have been put up (e.g. [this PR][1] with [this failed build][2] and [this PR][3] with [this failed build][4]). [1]: paper-trail-gem#1509 [2]: https://github.com/paper-trail-gem/paper_trail/actions/runs/13835939334/job/38733099092?pr=1509 [3]: paper-trail-gem#1511 [4]: https://github.com/paper-trail-gem/paper_trail/actions/runs/13916744592/job/38941085149?pr=1511 I'm not sure why these errors have started occurring now, without any changes in `master` since [the last commit on `master`][5] that passed all checks. Maybe `bundler` changed its behavior, and we are pulling in a new/recent version of `bundler` with some relevant behavior change? [5]: paper-trail-gem@94e9c0d But, anyway, the errors seem to be caused by the extraction of various gems from the Ruby standard library into standalone gems, specifically: 1. `bigdecimal` 1. `drb` 1. `mutex_m` This change adds those gems as development dependencies of `paper_trail`. Although they are not yet causing errors, the following gems were causing a warning for me when I ran specs using Ruby 3.4.2 with `BUNDLE_GEMFILE=/home/david/code/paper_trail/gemfiles/rails_6.1.gemfile bundle exec rspec`: 1. `benchmark` 1. `logger` These are the warnings: > /home/david/code/paper_trail/spec/spec_helper.rb:64: warning: logger was loaded from the standard library, but will no longer be part of the default gems starting from Ruby 3.5.0. > You can add logger to your Gemfile or gemspec to silence this warning. > /home/david/.rbenv/versions/3.4.2/lib/ruby/gems/3.4.0/gems/activesupport-6.1.7.10/lib/active_support/dependencies.rb:299: warning: benchmark was loaded from the standard library, but will no longer be part of the default gems starting from Ruby 3.5.0. > You can add benchmark to your Gemfile or gemspec to silence this warning. > Also please contact the author of activesupport-6.1.7.10 to request adding benchmark into its gemspec. To avoid these warnings, I am also adding these two gems as development dependencies. Additionally, this change adds a `require "logger"` statement to `spec/spec_helper.rb`. This isn't needed for the other gems (I'm guessing because `activerecord` and/or `actionpack` have `require` statements for `bigdecimal`, `drb`, and `mutex_m`?), but it seems to be needed for `logger`; without it, we get an error when trying to boot specs about `NameError: uninitialized constant ActiveSupport::LoggerThreadSafeLevel::Logger`.
Specs are failing for reasons not related to this change. I submitted this PR to fix them: #1512. |
Specs are currently failing on `master` on my local machine when I try to run specs with `BUNDLE_GEMFILE=/home/david/code/paper_trail/gemfiles/rails_6.1.gemfile bundle exec rspec`. This isn't yet reflected in any CI builds on `master`, but I believe that it would be, if a build were to be triggered on `master`. The same error is also occurring in recent PRs that have been put up (e.g. [this PR][1] with [this failed build][2] and [this PR][3] with [this failed build][4]). [1]: paper-trail-gem#1509 [2]: https://github.com/paper-trail-gem/paper_trail/actions/runs/13835939334/job/38733099092?pr=1509 [3]: paper-trail-gem#1511 [4]: https://github.com/paper-trail-gem/paper_trail/actions/runs/13916744592/job/38941085149?pr=1511 I'm not sure why these errors have started occurring now, without any changes in `master` since [the last commit on `master`][5] that passed all checks. Maybe `bundler` changed its behavior, and we are pulling in a new/recent version of `bundler` with some relevant behavior change? [5]: paper-trail-gem@94e9c0d But, anyway, the errors seem to be caused by the extraction of various gems from the Ruby standard library into standalone gems, specifically: 1. `bigdecimal` 1. `drb` 1. `mutex_m` This change adds those gems as development dependencies of `paper_trail`. Although they are not yet causing errors, the following gems were causing a warning for me when I ran specs using Ruby 3.4.2 with `BUNDLE_GEMFILE=/home/david/code/paper_trail/gemfiles/rails_6.1.gemfile bundle exec rspec`: 1. `benchmark` 1. `logger` These are the warnings: > /home/david/code/paper_trail/spec/spec_helper.rb:64: warning: logger was loaded from the standard library, but will no longer be part of the default gems starting from Ruby 3.5.0. > You can add logger to your Gemfile or gemspec to silence this warning. > /home/david/.rbenv/versions/3.4.2/lib/ruby/gems/3.4.0/gems/activesupport-6.1.7.10/lib/active_support/dependencies.rb:299: warning: benchmark was loaded from the standard library, but will no longer be part of the default gems starting from Ruby 3.5.0. > You can add benchmark to your Gemfile or gemspec to silence this warning. > Also please contact the author of activesupport-6.1.7.10 to request adding benchmark into its gemspec. To avoid these warnings, I am also adding these two gems as development dependencies. Additionally, this change adds a `require "logger"` statement to `spec/spec_helper.rb`. This isn't needed for the other gems (I'm guessing because `activerecord` and/or `actionpack` have `require` statements for `bigdecimal`, `drb`, and `mutex_m`?), but it seems to be needed for `logger`; without it, we get an error when trying to boot specs about `NameError: uninitialized constant ActiveSupport::LoggerThreadSafeLevel::Logger`.
* Add as development dependencies gems extracted from Ruby stdlib Specs are currently failing on `master` on my local machine when I try to run specs with `BUNDLE_GEMFILE=/home/david/code/paper_trail/gemfiles/rails_6.1.gemfile bundle exec rspec`. This isn't yet reflected in any CI builds on `master`, but I believe that it would be, if a build were to be triggered on `master`. The same error is also occurring in recent PRs that have been put up (e.g. [this PR][1] with [this failed build][2] and [this PR][3] with [this failed build][4]). [1]: #1509 [2]: https://github.com/paper-trail-gem/paper_trail/actions/runs/13835939334/job/38733099092?pr=1509 [3]: #1511 [4]: https://github.com/paper-trail-gem/paper_trail/actions/runs/13916744592/job/38941085149?pr=1511 I'm not sure why these errors have started occurring now, without any changes in `master` since [the last commit on `master`][5] that passed all checks. Maybe `bundler` changed its behavior, and we are pulling in a new/recent version of `bundler` with some relevant behavior change? [5]: 94e9c0d But, anyway, the errors seem to be caused by the extraction of various gems from the Ruby standard library into standalone gems, specifically: 1. `bigdecimal` 1. `drb` 1. `mutex_m` This change adds those gems as development dependencies of `paper_trail`. Although they are not yet causing errors, the following gems were causing a warning for me when I ran specs using Ruby 3.4.2 with `BUNDLE_GEMFILE=/home/david/code/paper_trail/gemfiles/rails_6.1.gemfile bundle exec rspec`: 1. `benchmark` 1. `logger` These are the warnings: > /home/david/code/paper_trail/spec/spec_helper.rb:64: warning: logger was loaded from the standard library, but will no longer be part of the default gems starting from Ruby 3.5.0. > You can add logger to your Gemfile or gemspec to silence this warning. > /home/david/.rbenv/versions/3.4.2/lib/ruby/gems/3.4.0/gems/activesupport-6.1.7.10/lib/active_support/dependencies.rb:299: warning: benchmark was loaded from the standard library, but will no longer be part of the default gems starting from Ruby 3.5.0. > You can add benchmark to your Gemfile or gemspec to silence this warning. > Also please contact the author of activesupport-6.1.7.10 to request adding benchmark into its gemspec. To avoid these warnings, I am also adding these two gems as development dependencies. Additionally, this change adds a `require "logger"` statement to `spec/spec_helper.rb`. This isn't needed for the other gems (I'm guessing because `activerecord` and/or `actionpack` have `require` statements for `bigdecimal`, `drb`, and `mutex_m`?), but it seems to be needed for `logger`; without it, we get an error when trying to boot specs about `NameError: uninitialized constant ActiveSupport::LoggerThreadSafeLevel::Logger`. * Add empty commit to trigger GitHub Actions build
Woops, I'm sorry, this branch and PR are currently in a bad state, because I made some changes to it for the sake of merging them into my own fork, forgetting about the fact that the branch was also being used for this PR. 😥 I will fix the branch up (and pull in the recently merged fix for specs failing on |
a8f5811
to
3e4a080
Compare
Done. The diff is back to the intended much, much smaller size, and, having pulled in #1512, all GitHub Actions checks are now passing. |
@@ -385,7 +385,7 @@ def sibling_versions | |||
# | |||
# @api private | |||
def version_limit | |||
klass = item.class |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Calling item
here is essentially what was causing the N+1 query, since instantiating the version's item
requires querying the database for the item
's attributes.
This change avoids that database query by instead just referencing the item_subtype
or item_type
fields of the version record, which does not require any additional database query.
Fixes #1510
Thank you for your contribution!
Check the following boxes:
master
(if not - rebase it).code introduces user-observable changes.
and description in grammatically correct, complete sentences.
Avoiding N+1 queries when destroying a record with a
has_many
dependent: :destroy
associationThis change avoids N+1 queries that otherwise currently occur on the
master
branch when destroying a record with ahas_many
dependent: :destroy
association where thehas_many
model is tracked by PaperTrail.My thoughts about this PR
Some of the things mentioned below are somewhat questionable/hacky. I understand if a PR in this form isn't really desired. But I believe that this change does fix the bug linked above, and I personally think that the changes herein are beneficial improvements to the gem and to its test suite.
Background context
I believe that the N+1 queries that this PR aims to remove were introduced by this change, and this current change essentially undoes that specific linked change in #1309 (though this current change handles the fact that
item_subtype
is an optional column in a slightly different way than did the original code prior to that change that I believe introduced this N+1 query).Adding
n_plus_one_control
gemIn order to test this change, this PR adds the
n_plus_one_control
gem as a development dependency. I understand that adding dependencies (even development-only dependencies) is a somewhat significant change, and that we might not want to add that gem for the sake of (at least for now) a single test. Nevertheless, it seemed to me like an effective way to test this change, and also that having then_plus_one_control
gem available might also be useful to write other specs in the future related to N+1 queries (or, rather, to a lack thereof), and so I'm including that gem in this proposed change.Using an instance variable in the spec
I think that the nature of how that gem works (maybe specifically in conjunction with the fact that the spec being added herein destroys the
Customer
record that is somewhat the subject of the spec?) necessitates capturing theCustomer
record with an instance variable, so I disabled theRSpec/InstanceVariable
cop for that spec.Hacking
PostVersion
to act like it has noitem_subtype
methodIn working on this change, in one iteration, I wrote code that assumes that the object into which the
PaperTrail::VersionConcern
module has been included will respond to anitem_subtype
message (i.e. have such a method). Specifically, I had written(item_subtype || item_type).constantize
. Although this code will fail in any project that uses PaperTrail but which does not add anitem_subtype
column for the versions table, all specs nevertheless passed (when executed withDB=sqlite bundle exec appraisal rails-8.0 rspec
). This implied to me that there is not currently any spec coverage/awareness of the fact thatitem_subtype
is an optional column that will not be available in all projects.I believe that this is the observation that was being made by @jaredbeck here:
The reason that the test suite doesn't have coverage of this possibility (not having an
item_subtype
method) is because all of the version models in the test suite inherit fromPaperTrail::Version
, which, in the spec setup, uses theversions
table, which is defined with anitem_subtype
column. So all of the version models in the test suite respond toitem_subtype
, even if their respective tables (e.g.post_versions
) do not have anitem_subtype
column.This differs from the situation of real applications using
paper_trail
, where in many (most?) of those applications the PaperTrail version model(s) will not respond to anitem_subtype
method.To try to give the test suite some awareness of this possibility, I hacked one of the version models --
PostVersion
-- to raise an error if #item_subtype is called and to returnfalse
when queried withrespond_to?(:item_subtype)
. This is ugly/hacky, but it does at least have the beneficial effect that the problematic iteration of my code change that I mentioned above would be caught by some failing specs.