Skip to content

Commit ed56e59

Browse files
committed
deprecate, join, preload, eager load of instance dependent associations.
Closes #15024. These operations happen before instances are created. The current behavior is misleading and can result in broken behavior.
1 parent f55f5e2 commit ed56e59

File tree

6 files changed

+56
-4
lines changed

6 files changed

+56
-4
lines changed

activerecord/CHANGELOG.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,12 @@
1+
* Deprecate joining, eager loading and preloading of instance dependent
2+
associations without replacement. These operations happen before instances
3+
are created. The current behavior is unexpected and can result in broken
4+
behavior.
5+
6+
Fixes #15024.
7+
8+
*Yves Senn*
9+
110
* Fixed HABTM's CollectionAssociation size calculation.
211

312
HABTM should fall back to using the normal CollectionAssociation's size

activerecord/lib/active_record/associations.rb

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -419,6 +419,10 @@ def association_instance_set(name, association)
419419
# has_many :birthday_events, ->(user) { where starts_on: user.birthday }, class_name: 'Event'
420420
# end
421421
#
422+
# Note: Joining, eager loading and preloading of these associations is not fully possibly.
423+
# These operations happen before instance creation. The scope will be called with a +nil+ argument.
424+
# This can lead to unexpected behavior and is deprecated.
425+
#
422426
# == Association callbacks
423427
#
424428
# Similar to the normal callbacks that hook into the life cycle of an Active Record object,

activerecord/lib/active_record/associations/join_dependency.rb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -215,6 +215,7 @@ def build(associations, base_klass)
215215
associations.map do |name, right|
216216
reflection = find_reflection base_klass, name
217217
reflection.check_validity!
218+
reflection.check_eager_loadable!
218219

219220
if reflection.options[:polymorphic]
220221
raise EagerLoadPolymorphicError.new(reflection)

activerecord/lib/active_record/associations/preloader.rb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -175,6 +175,7 @@ def preloader_for(reflection, owners, rhs_klass)
175175
if owners.first.association(reflection.name).loaded?
176176
return AlreadyLoaded
177177
end
178+
reflection.check_preloadable!
178179

179180
case reflection.macro
180181
when :has_many

activerecord/lib/active_record/reflection.rb

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -278,6 +278,20 @@ def check_validity_of_inverse!
278278
end
279279
end
280280

281+
def check_preloadable!
282+
return unless scope
283+
284+
if scope.arity > 0
285+
ActiveSupport::Deprecation.warn <<-WARNING
286+
The association scope '#{name}' is instance dependent (the scope block takes an argument).
287+
Preloading happens before the individual instances are created. This means that there is no instance
288+
being passed to the association scope. This will most likely result in broken or incorrect behavior.
289+
Joining, Preloading and eager loading of these associations is deprecated and will be removed in the future.
290+
WARNING
291+
end
292+
end
293+
alias :check_eager_loadable! :check_preloadable!
294+
281295
def join_id_for(owner) #:nodoc:
282296
key = (source_macro == :belongs_to) ? foreign_key : active_record_primary_key
283297
owner[key]

activerecord/test/cases/associations/eager_test.rb

Lines changed: 27 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -826,11 +826,15 @@ def test_limited_eager_with_numeric_in_association
826826
end
827827

828828
def test_preload_with_interpolation
829-
post = Post.includes(:comments_with_interpolated_conditions).find(posts(:welcome).id)
830-
assert_equal [comments(:greetings)], post.comments_with_interpolated_conditions
829+
assert_deprecated do
830+
post = Post.includes(:comments_with_interpolated_conditions).find(posts(:welcome).id)
831+
assert_equal [comments(:greetings)], post.comments_with_interpolated_conditions
832+
end
831833

832-
post = Post.joins(:comments_with_interpolated_conditions).find(posts(:welcome).id)
833-
assert_equal [comments(:greetings)], post.comments_with_interpolated_conditions
834+
assert_deprecated do
835+
post = Post.joins(:comments_with_interpolated_conditions).find(posts(:welcome).id)
836+
assert_equal [comments(:greetings)], post.comments_with_interpolated_conditions
837+
end
834838
end
835839

836840
def test_polymorphic_type_condition
@@ -1232,4 +1236,23 @@ def test_deep_including_through_habtm
12321236
assert_equal 2, author.posts.size
12331237
}
12341238
end
1239+
1240+
test "include instance dependent associations is deprecated" do
1241+
message = "association scope 'posts_with_signature' is"
1242+
assert_deprecated message do
1243+
begin
1244+
Author.includes(:posts_with_signature).to_a
1245+
rescue NoMethodError
1246+
# it's expected that preloading of this association fails
1247+
end
1248+
end
1249+
1250+
assert_deprecated message do
1251+
Author.preload(:posts_with_signature).to_a rescue NoMethodError
1252+
end
1253+
1254+
assert_deprecated message do
1255+
Author.eager_load(:posts_with_signature).to_a
1256+
end
1257+
end
12351258
end

0 commit comments

Comments
 (0)