Skip to content

Commit 9d3a199

Browse files
authored
Merge pull request #5398 from rmosolgo/association-load-fix
Fix association loads with different scopes on the same object
2 parents ea9d1ea + 49ea523 commit 9d3a199

File tree

2 files changed

+88
-4
lines changed

2 files changed

+88
-4
lines changed

lib/graphql/dataloader/active_record_association_source.rb

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,12 @@ def load(record)
3131
def fetch(records)
3232
record_classes = Set.new.compare_by_identity
3333
associated_classes = Set.new.compare_by_identity
34+
scoped_fetch = !@scope.nil?
3435
records.each do |record|
36+
if scoped_fetch
37+
assoc = record.association(@association)
38+
assoc.reset
39+
end
3540
if record_classes.add?(record.class)
3641
reflection = record.class.reflect_on_association(@association)
3742
if !reflection.polymorphic? && reflection.klass
@@ -48,9 +53,16 @@ def fetch(records)
4853

4954
::ActiveRecord::Associations::Preloader.new(records: records, associations: @association, available_records: available_records, scope: @scope).call
5055

51-
loaded_associated_records = records.map { |r| r.public_send(@association) }
56+
loaded_associated_records = records.map { |r|
57+
assoc = r.association(@association)
58+
lar = assoc.target
59+
if scoped_fetch
60+
assoc.reset
61+
end
62+
lar
63+
}
5264

53-
if @scope.nil?
65+
if !scoped_fetch
5466
# Don't cache records loaded via scope because they might have reduced `SELECT`s
5567
# Could check .select_values here?
5668
records_by_model = {}

spec/graphql/dataloader/active_record_association_source_spec.rb

Lines changed: 74 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,77 @@
33

44
describe GraphQL::Dataloader::ActiveRecordAssociationSource do
55
if testing_rails?
6+
class VulfpeckSchema < GraphQL::Schema
7+
class Album < GraphQL::Schema::Object
8+
field :name, String
9+
end
10+
class Band < GraphQL::Schema::Object
11+
field :albums, [Album] do
12+
argument :genre, String, required: false
13+
argument :reverse, Boolean, required: false, default_value: false
14+
argument :unscoped, Boolean, required: false, default_value: false
15+
end
16+
17+
def albums(genre: nil, reverse:, unscoped:)
18+
if unscoped
19+
scope = nil
20+
else
21+
scope = ::Album
22+
if genre
23+
scope = scope.where(band_genre: genre)
24+
end
25+
26+
scope = if reverse
27+
scope.order(name: :desc)
28+
else
29+
scope.order(:name)
30+
end
31+
end
32+
dataload_association(:albums, scope: scope)
33+
end
34+
end
35+
36+
class Query < GraphQL::Schema::Object
37+
field :band, Band do
38+
argument :name, String
39+
end
40+
41+
def band(name:)
42+
::Band.find_by(name: name)
43+
end
44+
end
45+
46+
query(Query)
47+
use GraphQL::Dataloader
48+
end
49+
50+
it "works with different scopes on the same object at runtime" do
51+
query_str = <<~GRAPHQL
52+
{
53+
band(name: "Vulfpeck") {
54+
allAlbums: albums {
55+
name
56+
}
57+
unscopedAlbums: albums(unscoped: true) {
58+
name
59+
}
60+
reverseAlbums: albums(reverse: true) {
61+
name
62+
}
63+
countryAlbums: albums(genre: "country") {
64+
name
65+
}
66+
}
67+
}
68+
GRAPHQL
69+
70+
result = VulfpeckSchema.execute(query_str)
71+
assert_equal ["Mit Peck", "My First Car"], result["data"]["band"]["allAlbums"].map { |a| a["name"] }
72+
assert_equal ["Mit Peck", "My First Car"], result["data"]["band"]["unscopedAlbums"].map { |a| a["name"] }
73+
assert_equal ["My First Car", "Mit Peck"], result["data"]["band"]["reverseAlbums"].map { |a| a["name"] }
74+
assert_equal [], result["data"]["band"]["countryAlbums"]
75+
end
76+
677
it_dataloads "queries for associated records when the association isn't already loaded" do |d|
778
my_first_car = ::Album.find(2)
879
homey = ::Album.find(4)
@@ -135,10 +206,11 @@
135206
one_month_ago = 1.month.ago.end_of_day
136207
albums_by_band_1 = d.with(GraphQL::Dataloader::ActiveRecordAssociationSource, :albums, Album.where("created_at >= ?", one_month_ago)).request(wilco)
137208
albums_by_band_2 = d.with(GraphQL::Dataloader::ActiveRecordAssociationSource, :albums, Album.where("created_at >= ?", one_month_ago)).request(chon)
138-
albums_by_band = [albums_by_band_1.load, albums_by_band_2.load]
209+
albums_by_band_3 = d.with(GraphQL::Dataloader::ActiveRecordAssociationSource, :albums, Album.where("created_at <= ?", one_month_ago)).request(wilco)
210+
albums_by_band = [albums_by_band_1.load, albums_by_band_2.load, albums_by_band_3.load]
139211
end
140212

141-
assert_equal [[6], [4, 5]], albums_by_band.map { |al| al.map(&:id) }
213+
assert_equal [[6], [4, 5], []], albums_by_band.map { |al| al.map(&:id) }
142214
expected_log = if Rails::VERSION::STRING > "8"
143215
'SELECT "albums".* FROM "albums" WHERE (created_at >= ?) AND "albums"."band_id" IN (?, ?)'
144216
else

0 commit comments

Comments
 (0)