Skip to content

Commit e7fdd23

Browse files
pjungwirarenoir
authored andcommitted
Fix include_optional_linkage_data with joins (cerebris#1450)
When the user adds a join in `records`, it confuses `get_join_arel_node` because it finds the same number of joins before & after adding a join for `include_optional_linkage_data` (or equivalently for `always_include_*_linkage_data`). This commit falls back to searching the existing arel nodes for a compatible join and uses that if found.
1 parent 7117fb8 commit e7fdd23

File tree

4 files changed

+42
-4
lines changed

4 files changed

+42
-4
lines changed

lib/jsonapi/active_relation/join_manager.rb

Lines changed: 22 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ def join_details_by_relationship(relationship)
7070
@join_details[segment]
7171
end
7272

73-
def self.get_join_arel_node(records, options = {})
73+
def self.get_join_arel_node(records, relationship, join_type, options = {})
7474
init_join_sources = records.arel.join_sources
7575
init_join_sources_length = init_join_sources.length
7676

@@ -80,9 +80,27 @@ def self.get_join_arel_node(records, options = {})
8080
if join_sources.length > init_join_sources_length
8181
last_join = (join_sources - init_join_sources).last
8282
else
83+
# Try to find a pre-existing join for this table.
84+
# We can get here if include_optional_linkage_data is true
85+
# (or always_include_to_xxx_linkage_data),
86+
# and the user's custom `records` method has already added that join.
87+
#
88+
# If we want a left join and there is already an inner/left join,
89+
# then we can use that.
90+
# If we want an inner join and there is alrady an inner join,
91+
# then we can use that (but not a left join, since that doesn't filter things out).
92+
valid_join_types = [Arel::Nodes::InnerJoin]
93+
valid_join_types << Arel::Nodes::OuterJoin if join_type == :left
94+
table_name = relationship.resource_klass._table_name
95+
96+
last_join = join_sources.find { |j|
97+
valid_join_types.any? { |t| j.is_a?(t) } && j.left.name == table_name
98+
}
99+
end
100+
101+
if last_join.nil?
83102
# :nocov:
84103
warn "get_join_arel_node: No join added"
85-
last_join = nil
86104
# :nocov:
87105
end
88106

@@ -160,7 +178,7 @@ def perform_joins(records, options)
160178
next
161179
end
162180

163-
records, join_node = self.class.get_join_arel_node(records, options) {|records, options|
181+
records, join_node = self.class.get_join_arel_node(records, relationship, join_type, options) {|records, options|
164182
related_resource_klass.join_relationship(
165183
records: records,
166184
resource_type: related_resource_klass._type,
@@ -300,4 +318,4 @@ def add_relationships(relationships)
300318
end
301319
end
302320
end
303-
end
321+
end

test/fixtures/active_record.rb

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1079,6 +1079,8 @@ def context
10791079
module V3
10801080
class PostsController < JSONAPI::ResourceController
10811081
end
1082+
class MoonsController < JSONAPI::ResourceController
1083+
end
10821084
end
10831085

10841086
module V4
@@ -2087,6 +2089,15 @@ module Api
20872089
module V3
20882090
class PostResource < PostResource; end
20892091
class PreferencesResource < PreferencesResource; end
2092+
class PlanetResource < JSONAPI::Resource
2093+
end
2094+
class MoonResource < JSONAPI::Resource
2095+
has_one :planet, always_include_optional_linkage_data: true
2096+
2097+
def self.records(options = {})
2098+
Moon.joins(:planet).merge(Planet.where(name: 'Satern')) # sic
2099+
end
2100+
end
20902101
end
20912102
end
20922103

test/integration/requests/request_test.rb

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1855,4 +1855,10 @@ def test_destroy_singleton_not_found
18551855
JSONAPI.configuration = original_config
18561856
$test_user = $original_test_user
18571857
end
1858+
1859+
def test_include_optional_linkage_data_with_join
1860+
get "/api/v3/moons", headers: { 'Accept' => JSONAPI::MEDIA_TYPE }
1861+
assert_jsonapi_response 200
1862+
refute_nil json_response['data'][0]['relationships']['planet']
1863+
end
18581864
end

test/test_helper.rb

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -357,6 +357,9 @@ class CatResource < JSONAPI::Resource
357357
jsonapi_link :author, except: [:destroy]
358358
jsonapi_links :tags, only: [:show, :create]
359359
end
360+
361+
jsonapi_resources :planets
362+
jsonapi_resources :moons
360363
end
361364

362365
JSONAPI.configuration.route_format = :camelized_route

0 commit comments

Comments
 (0)