Add support for eager loading all rich text associations at once#39397
Add support for eager loading all rich text associations at once#39397kaspth merged 3 commits intorails:masterfrom
Conversation
actiontext/test/unit/model_test.rb
Outdated
There was a problem hiding this comment.
@dhh it seems that ActiveRecord::TestCase is not easy to use outside of the activerecord suite. I think this is preferably to putting the helpers directly in the single test and seems to follow the convention used in: actionview/test/activerecord/relation_cache_test.rb.
Open to other ideas if you have them. I wasn't ready to tackle more structural changes to ActiveRecord::TestCase based on my current understanding of the overall test suite.
There was a problem hiding this comment.
I tried fiddling around with this again today, but seems like the preference is to duplicate the query helpers vs making the existing AR::TestCase more accessible: #36031 (comment)
|
This pull request has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. |
75295c7 to
5df83ae
Compare
|
@dhh I've merged master, squashed, and added a CHANGELOG entry. Anything else to tackle on this PR? |
Co-authored-by: Kasper Timm Hansen <kaspth@gmail.com>
Co-authored-by: Kasper Timm Hansen <kaspth@gmail.com>
|
Sweet, thank you! |
…s run by ruby 3.0.0dev This pull request addresses the `ArgumentError: missing keywords: :sql, :name`, which has been reported at https://buildkite.com/rails/rails/builds/72990#c78d1e4c-5775-4758-9010-9ba71fdb6138 Follow up rails#39397 ```ruby $ ruby -v ruby 3.0.0dev (2020-11-24T22:48:19Z master 63ad55cd88) [x86_64-linux] $ cd actiontext $ bin/test test/unit/model_test.rb -n test_eager_loading Run options: -n test_eager_loading --seed 16493 E Error: ActionText::ModelTest#test_eager_loading: ArgumentError: missing keywords: :sql, :name /home/yahonda/src/github.com/rails/rails/actiontext/test/test_helper.rb:29:in `block in assert_queries' /home/yahonda/src/github.com/rails/rails/activesupport/lib/active_support/notifications/fanout.rb:186:in `finish' /home/yahonda/src/github.com/rails/rails/activesupport/lib/active_support/notifications/fanout.rb:63:in `block in finish' /home/yahonda/src/github.com/rails/rails/activesupport/lib/active_support/notifications/fanout.rb:63:in `each' /home/yahonda/src/github.com/rails/rails/activesupport/lib/active_support/notifications/fanout.rb:63:in `finish' /home/yahonda/src/github.com/rails/rails/activesupport/lib/active_support/notifications/instrumenter.rb:45:in `finish_with_state' /home/yahonda/src/github.com/rails/rails/activesupport/lib/active_support/notifications/instrumenter.rb:30:in `instrument' /home/yahonda/src/github.com/rails/rails/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb:688:in `log' /home/yahonda/src/github.com/rails/rails/activerecord/lib/active_record/connection_adapters/sqlite3/database_statements.rb:46:in `exec_query' /home/yahonda/src/github.com/rails/rails/activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb:536:in `select_prepared' /home/yahonda/src/github.com/rails/rails/activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb:67:in `select_all' /home/yahonda/src/github.com/rails/rails/activerecord/lib/active_record/connection_adapters/abstract/query_cache.rb:103:in `select_all' /home/yahonda/src/github.com/rails/rails/activerecord/lib/active_record/querying.rb:47:in `find_by_sql' /home/yahonda/src/github.com/rails/rails/activerecord/lib/active_record/relation.rb:850:in `block in exec_queries' /home/yahonda/src/github.com/rails/rails/activerecord/lib/active_record/relation.rb:868:in `skip_query_cache_if_necessary' /home/yahonda/src/github.com/rails/rails/activerecord/lib/active_record/relation.rb:835:in `exec_queries' /home/yahonda/src/github.com/rails/rails/activerecord/lib/active_record/relation.rb:638:in `load' /home/yahonda/src/github.com/rails/rails/activerecord/lib/active_record/relation.rb:249:in `records' /home/yahonda/src/github.com/rails/rails/activerecord/lib/active_record/relation.rb:244:in `to_ary' /home/yahonda/src/github.com/rails/rails/activerecord/lib/active_record/relation/finder_methods.rb:553:in `find_nth_with_limit' /home/yahonda/src/github.com/rails/rails/activerecord/lib/active_record/relation/finder_methods.rb:538:in `find_nth' /home/yahonda/src/github.com/rails/rails/activerecord/lib/active_record/relation/finder_methods.rb:122:in `first' /home/yahonda/src/github.com/rails/rails/activerecord/lib/active_record/relation/finder_methods.rb:153:in `last' /home/yahonda/src/github.com/rails/rails/actiontext/test/unit/model_test.rb:93:in `block (2 levels) in <class:ModelTest>' /home/yahonda/src/github.com/rails/rails/actiontext/test/test_helper.rb:33:in `assert_queries' /home/yahonda/src/github.com/rails/rails/actiontext/test/unit/model_test.rb:93:in `block in <class:ModelTest>' Error: ActionText::ModelTest#test_eager_loading: ArgumentError: missing keywords: :sql, :name /home/yahonda/src/github.com/rails/rails/actiontext/test/test_helper.rb:29:in `block in assert_queries' /home/yahonda/src/github.com/rails/rails/activesupport/lib/active_support/notifications/fanout.rb:186:in `finish' /home/yahonda/src/github.com/rails/rails/activesupport/lib/active_support/notifications/fanout.rb:63:in `block in finish' /home/yahonda/src/github.com/rails/rails/activesupport/lib/active_support/notifications/fanout.rb:63:in `each' /home/yahonda/src/github.com/rails/rails/activesupport/lib/active_support/notifications/fanout.rb:63:in `finish' /home/yahonda/src/github.com/rails/rails/activesupport/lib/active_support/notifications/instrumenter.rb:45:in `finish_with_state' /home/yahonda/src/github.com/rails/rails/activesupport/lib/active_support/notifications/instrumenter.rb:30:in `instrument' /home/yahonda/src/github.com/rails/rails/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb:688:in `log' /home/yahonda/src/github.com/rails/rails/activerecord/lib/active_record/connection_adapters/sqlite3/database_statements.rb:98:in `exec_rollback_db_transaction' /home/yahonda/src/github.com/rails/rails/activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb:378:in `rollback_db_transaction' /home/yahonda/src/github.com/rails/rails/activerecord/lib/active_record/connection_adapters/abstract/query_cache.rb:22:in `rollback_db_transaction' /home/yahonda/src/github.com/rails/rails/activerecord/lib/active_record/connection_adapters/abstract/transaction.rb:205:in `rollback' /home/yahonda/src/github.com/rails/rails/activerecord/lib/active_record/connection_adapters/abstract/transaction.rb:302:in `block in rollback_transaction' /home/yahonda/src/github.com/rails/rails/activesupport/lib/active_support/concurrency/load_interlock_aware_monitor.rb:26:in `block (2 levels) in synchronize' /home/yahonda/src/github.com/rails/rails/activesupport/lib/active_support/concurrency/load_interlock_aware_monitor.rb:25:in `handle_interrupt' /home/yahonda/src/github.com/rails/rails/activesupport/lib/active_support/concurrency/load_interlock_aware_monitor.rb:25:in `block in synchronize' /home/yahonda/src/github.com/rails/rails/activesupport/lib/active_support/concurrency/load_interlock_aware_monitor.rb:21:in `handle_interrupt' /home/yahonda/src/github.com/rails/rails/activesupport/lib/active_support/concurrency/load_interlock_aware_monitor.rb:21:in `synchronize' /home/yahonda/src/github.com/rails/rails/activerecord/lib/active_record/connection_adapters/abstract/transaction.rb:300:in `rollback_transaction' /home/yahonda/src/github.com/rails/rails/activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb:328:in `rollback_transaction' /home/yahonda/src/github.com/rails/rails/activerecord/lib/active_record/test_fixtures.rb:168:in `block in teardown_fixtures' /home/yahonda/src/github.com/rails/rails/activerecord/lib/active_record/test_fixtures.rb:167:in `each' /home/yahonda/src/github.com/rails/rails/activerecord/lib/active_record/test_fixtures.rb:167:in `teardown_fixtures' /home/yahonda/src/github.com/rails/rails/activerecord/lib/active_record/test_fixtures.rb:16:in `after_teardown' /home/yahonda/src/github.com/rails/rails/activesupport/lib/active_support/testing/setup_and_teardown.rb:51:in `after_teardown' bin/test test/unit/model_test.rb:90 Finished in 0.117256s, 8.5284 runs/s, 0.0000 assertions/s. 1 runs, 0 assertions, 0 failures, 1 errors, 0 skips $ ``` Co-authored-by: Ryuta Kamizono <kamipo@gmail.com>
|
@swanson Is this implemented in ActiveStorage? I think the same approach can be used if not. |
It's not, only ActionText at the moment. |
…ds on an attachment at once Currently Active Storage [variant tracking](rails#37901) runs a query for each attachment to check for a variant. Regular Rails n+1 prevention techniques (`includes`) cannot prevent this. This PR adds `with_all_variant_records`, as well as allowing `includes` to work as expected on Active Storage attachments. ```ruby user.vlogs.with_all_variant_records.map do |vlog| vlog.representation(resize: "100x100").processed end ``` Fixes several of the comments in rails#37901 In implementing this, I borrowed heavily from the style of rails#39397
Docs for rails#40842 + rails#39397 [ci skip]
…ds on an attachment at once Currently Active Storage [variant tracking](rails/rails#37901) runs a query for each attachment to check for a variant. Regular Rails n+1 prevention techniques (`includes`) cannot prevent this. This PR adds `with_all_variant_records`, as well as allowing `includes` to work as expected on Active Storage attachments. ```ruby user.vlogs.with_all_variant_records.map do |vlog| vlog.representation(resize: "100x100").processed end ``` Fixes several of the comments in rails/rails#37901 In implementing this, I borrowed heavily from the style of rails/rails#39397
Docs for rails/rails#40842 + rails/rails#39397 [ci skip]
Summary
ActionText provides
with_rich_text_#{name}helpers to make it easy to preload rich text associations. This works great for single rich text fields on a model, but if you have multiple rich text fields, it will cause multiple queries to the ActionText table to load each one.Consider the case of a model with lots of dynamic, user-generated content
When trying to display all of the content for a
Pageusing eager loading:Rails will run a total of 6 queries (one to load
Page, six individualActionTextloads).This PR adds a
with_all_rich_textthat useseager_loadand reflects onhas_rich_textassociations to bulk load all rich text associations.Other Information
Per #37976, ActionText internals are currently in-flux but wanted to see if there was interest in adding this feature in a future release, or if it fits better as an application-specific helper.