Skip to content

Commit e92afc6

Browse files
authored
Fix include_optional_linkage_data with joins (#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 a3a2a7a commit e92afc6

File tree

4 files changed

+42
-4
lines changed

4 files changed

+42
-4
lines changed

lib/jsonapi/active_relation/join_manager.rb

+22-4
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

@@ -154,7 +172,7 @@ def perform_joins(records, options)
154172
next
155173
end
156174

157-
records, join_node = self.class.get_join_arel_node(records, options) {|records, options|
175+
records, join_node = self.class.get_join_arel_node(records, relationship, join_type, options) {|records, options|
158176
related_resource_klass.join_relationship(
159177
records: records,
160178
resource_type: related_resource_klass._type,
@@ -294,4 +312,4 @@ def add_relationships(relationships)
294312
end
295313
end
296314
end
297-
end
315+
end

test/fixtures/active_record.rb

+11
Original file line numberDiff line numberDiff line change
@@ -1059,6 +1059,8 @@ def context
10591059
module V3
10601060
class PostsController < JSONAPI::ResourceController
10611061
end
1062+
class MoonsController < JSONAPI::ResourceController
1063+
end
10621064
end
10631065

10641066
module V4
@@ -2042,6 +2044,15 @@ module Api
20422044
module V3
20432045
class PostResource < PostResource; end
20442046
class PreferencesResource < PreferencesResource; end
2047+
class PlanetResource < JSONAPI::Resource
2048+
end
2049+
class MoonResource < JSONAPI::Resource
2050+
has_one :planet, always_include_optional_linkage_data: true
2051+
2052+
def self.records(options = {})
2053+
Moon.joins(:planet).merge(Planet.where(name: 'Satern')) # sic
2054+
end
2055+
end
20452056
end
20462057
end
20472058

test/integration/requests/request_test.rb

+6
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

+3
Original file line numberDiff line numberDiff line change
@@ -312,6 +312,9 @@ class CatResource < JSONAPI::Resource
312312
jsonapi_link :author, except: [:destroy]
313313
jsonapi_links :tags, only: [:show, :create]
314314
end
315+
316+
jsonapi_resources :planets
317+
jsonapi_resources :moons
315318
end
316319

317320
JSONAPI.configuration.route_format = :camelized_route

0 commit comments

Comments
 (0)