forest_admin_datasource_active_record 1.39.3 → 1.40.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 900ccccbc0c8a7ae95c5eee13a67dca16bbad7add14ac849381a95246878393d
|
|
4
|
+
data.tar.gz: 7fb49021e33e83ed9cb8e01a39a813b4e261fae73e8d6d32e936092f843e7aad
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: dcda7837f4a0d0b6658c10ae3245d9e31ab3933d7302b414e7560716f1cf6ccfb261f4ccc1e93dac131384cfb927cca9b5cb412c6ebace19cff563b24398d67b
|
|
7
|
+
data.tar.gz: 43d723551915aace679d91971d5264f70e91f2adbd4a5bde9bc153884a69364292d5fbb7d33e2584794ca5f7009358ee783cdf930b2521035e5ef12e31b70f63
|
|
@@ -88,6 +88,60 @@ module ForestAdminDatasourceActiveRecord
|
|
|
88
88
|
%i[destroy destroy_async delete_all].include?(association.options[:dependent])
|
|
89
89
|
end
|
|
90
90
|
|
|
91
|
+
# join_foreign_key can fall back to the through model's own PK (see
|
|
92
|
+
# valid_many_to_many_source? below); that PK usually still exists as a column, so
|
|
93
|
+
# "column missing" alone doesn't catch every unrepresentable case -- a composite key is
|
|
94
|
+
# unrepresentable too, even when every individual column exists: GeneratorField looks
|
|
95
|
+
# fields up by the raw key, so a composite key never resolves. A composite key can reach
|
|
96
|
+
# us either as a real Array, or (via an explicit primary_key: option on the source)
|
|
97
|
+
# already flattened by Rails into a mangled String like '["a", "b"]' -- neither is ever a
|
|
98
|
+
# real column name, so checking column membership catches both forms uniformly, on
|
|
99
|
+
# whichever collection each key is actually resolved against downstream (#370).
|
|
100
|
+
def unrepresentable_many_to_many?(association, through_reflection)
|
|
101
|
+
[
|
|
102
|
+
[association.join_foreign_key, through_reflection.klass],
|
|
103
|
+
[through_reflection.foreign_key, through_reflection.klass],
|
|
104
|
+
[association.association_primary_key, association.klass]
|
|
105
|
+
].any? { |key, klass| !klass.column_names.include?(key) }
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
# True only for a belongs_to source: ThroughReflection#join_foreign_key delegates to
|
|
109
|
+
# the source reflection, and only belongs_to overrides it to return a real FK column.
|
|
110
|
+
# Any other source macro falls back to AssociationReflection#active_record_primary_key
|
|
111
|
+
# -- the through model's own primary key column (honoring a custom primary_key:, and
|
|
112
|
+
# possibly composite), not a genuine join column (#370).
|
|
113
|
+
def valid_many_to_many_source?(association)
|
|
114
|
+
association.source_reflection&.belongs_to?
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
def build_many_to_many_field(association, through_reflection, is_polymorphic, source_polymorphic)
|
|
118
|
+
ForestAdminDatasourceToolkit::Schema::Relations::ManyToManySchema.new(
|
|
119
|
+
foreign_collection: format_model_name(association.klass.name),
|
|
120
|
+
origin_key: through_reflection.foreign_key,
|
|
121
|
+
origin_key_target: through_reflection.join_foreign_key,
|
|
122
|
+
foreign_key: association.join_foreign_key,
|
|
123
|
+
foreign_key_target: association.association_primary_key,
|
|
124
|
+
through_collection: format_model_name(through_reflection.klass.name),
|
|
125
|
+
origin_type_field: is_polymorphic ? through_reflection.type : nil,
|
|
126
|
+
origin_type_value: is_polymorphic ? @model.name : nil,
|
|
127
|
+
foreign_type_field: source_polymorphic ? association.source_reflection.foreign_type : nil,
|
|
128
|
+
foreign_type_value: source_polymorphic ? association.options[:source_type] : nil
|
|
129
|
+
)
|
|
130
|
+
end
|
|
131
|
+
|
|
132
|
+
def add_many_to_many_field(association, through_reflection, is_polymorphic, source_polymorphic)
|
|
133
|
+
if unrepresentable_many_to_many?(association, through_reflection)
|
|
134
|
+
warn_unrepresentable_many_to_many(association, through_reflection)
|
|
135
|
+
return
|
|
136
|
+
end
|
|
137
|
+
|
|
138
|
+
add_field(
|
|
139
|
+
association.name.to_s,
|
|
140
|
+
build_many_to_many_field(association, through_reflection, is_polymorphic, source_polymorphic)
|
|
141
|
+
)
|
|
142
|
+
warn_identity_join(association, through_reflection) unless valid_many_to_many_source?(association)
|
|
143
|
+
end
|
|
144
|
+
|
|
91
145
|
# rubocop:disable Metrics/BlockNesting
|
|
92
146
|
def fetch_associations
|
|
93
147
|
associations(@model, support_polymorphic_relations: @support_polymorphic_relations).each do |association|
|
|
@@ -99,23 +153,10 @@ module ForestAdminDatasourceActiveRecord
|
|
|
99
153
|
is_polymorphic = through_reflection.options[:as].present?
|
|
100
154
|
source_polymorphic = association.source_reflection&.polymorphic? &&
|
|
101
155
|
association.options[:source_type].present?
|
|
156
|
+
many_to_many_shape = is_polymorphic || source_polymorphic
|
|
102
157
|
|
|
103
|
-
if
|
|
104
|
-
|
|
105
|
-
association.name.to_s,
|
|
106
|
-
ForestAdminDatasourceToolkit::Schema::Relations::ManyToManySchema.new(
|
|
107
|
-
foreign_collection: format_model_name(association.klass.name),
|
|
108
|
-
origin_key: through_reflection.foreign_key,
|
|
109
|
-
origin_key_target: through_reflection.join_foreign_key,
|
|
110
|
-
foreign_key: association.join_foreign_key,
|
|
111
|
-
foreign_key_target: association.association_primary_key,
|
|
112
|
-
through_collection: format_model_name(through_reflection.klass.name),
|
|
113
|
-
origin_type_field: is_polymorphic ? through_reflection.type : nil,
|
|
114
|
-
origin_type_value: is_polymorphic ? @model.name : nil,
|
|
115
|
-
foreign_type_field: source_polymorphic ? association.source_reflection.foreign_type : nil,
|
|
116
|
-
foreign_type_value: source_polymorphic ? association.options[:source_type] : nil
|
|
117
|
-
)
|
|
118
|
-
)
|
|
158
|
+
if many_to_many_shape
|
|
159
|
+
add_many_to_many_field(association, through_reflection, is_polymorphic, source_polymorphic)
|
|
119
160
|
else
|
|
120
161
|
add_field(
|
|
121
162
|
association.name.to_s,
|
|
@@ -186,21 +227,7 @@ module ForestAdminDatasourceActiveRecord
|
|
|
186
227
|
source_polymorphic = association.source_reflection&.polymorphic? &&
|
|
187
228
|
association.options[:source_type].present?
|
|
188
229
|
|
|
189
|
-
|
|
190
|
-
association.name.to_s,
|
|
191
|
-
ForestAdminDatasourceToolkit::Schema::Relations::ManyToManySchema.new(
|
|
192
|
-
foreign_collection: format_model_name(association.klass.name),
|
|
193
|
-
origin_key: through_reflection.foreign_key,
|
|
194
|
-
origin_key_target: through_reflection.join_foreign_key,
|
|
195
|
-
foreign_key: association.join_foreign_key,
|
|
196
|
-
foreign_key_target: association.association_primary_key,
|
|
197
|
-
through_collection: format_model_name(through_reflection.klass.name),
|
|
198
|
-
origin_type_field: is_polymorphic ? through_reflection.type : nil,
|
|
199
|
-
origin_type_value: is_polymorphic ? @model.name : nil,
|
|
200
|
-
foreign_type_field: source_polymorphic ? association.source_reflection.foreign_type : nil,
|
|
201
|
-
foreign_type_value: source_polymorphic ? association.options[:source_type] : nil
|
|
202
|
-
)
|
|
203
|
-
)
|
|
230
|
+
add_many_to_many_field(association, through_reflection, is_polymorphic, source_polymorphic)
|
|
204
231
|
elsif association.inverse_of&.polymorphic?
|
|
205
232
|
add_field(
|
|
206
233
|
association.name.to_s,
|
|
@@ -303,6 +330,38 @@ module ForestAdminDatasourceActiveRecord
|
|
|
303
330
|
klass
|
|
304
331
|
end
|
|
305
332
|
|
|
333
|
+
def warn_unrepresentable_many_to_many(association, through_reflection)
|
|
334
|
+
logger = ActiveSupport::Logger.new($stdout)
|
|
335
|
+
logger.warn(
|
|
336
|
+
"[ForestAdmin] ⚠️ Skipping association '#{association.name}' in model '#{@model.name}': " \
|
|
337
|
+
'this relation cannot be represented as a Forest Admin many-to-many -- its join keys must ' \
|
|
338
|
+
'each be a single existing column, on the through collection ' \
|
|
339
|
+
"'#{format_model_name(through_reflection.klass.name)}' or the foreign collection " \
|
|
340
|
+
"'#{format_model_name(association.klass.name)}' (composite/query_constraints keys are " \
|
|
341
|
+
'not supported).'
|
|
342
|
+
)
|
|
343
|
+
end
|
|
344
|
+
|
|
345
|
+
# join_foreign_key/association_primary_key are guaranteed to be single, real, existing
|
|
346
|
+
# columns here: unrepresentable_many_to_many? above already checks column membership for
|
|
347
|
+
# both (and for origin_key) before this is ever called.
|
|
348
|
+
#
|
|
349
|
+
# Deliberately a diagnostic, not a deprecation notice: this shape is common (any
|
|
350
|
+
# has_many/has_one :through sourced from a plain has_one/has_many, not just polymorphic
|
|
351
|
+
# ones) and the relation is kept published to avoid narrowing the schema -- see #370.
|
|
352
|
+
# No removal is promised or planned.
|
|
353
|
+
def warn_identity_join(association, through_reflection)
|
|
354
|
+
logger = ActiveSupport::Logger.new($stdout)
|
|
355
|
+
logger.warn(
|
|
356
|
+
"[ForestAdmin] ⚠️ Association '#{association.name}' in model '#{@model.name}' is published " \
|
|
357
|
+
"as a many-to-many joining '#{format_model_name(through_reflection.klass.name)}'." \
|
|
358
|
+
"'#{association.join_foreign_key}' to " \
|
|
359
|
+
"'#{format_model_name(association.klass.name)}'.'#{association.association_primary_key}': " \
|
|
360
|
+
"its source association is not a belongs_to, so this join uses each side's own identifier " \
|
|
361
|
+
'rather than a dedicated foreign key column -- see #370 for background.'
|
|
362
|
+
)
|
|
363
|
+
end
|
|
364
|
+
|
|
306
365
|
def warn_missing_polymorphic_columns(association)
|
|
307
366
|
missing_columns = []
|
|
308
367
|
missing_columns << association.foreign_key unless schema[:fields][association.foreign_key]
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: forest_admin_datasource_active_record
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 1.
|
|
4
|
+
version: 1.40.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Matthieu
|
|
@@ -9,7 +9,7 @@ authors:
|
|
|
9
9
|
autorequire:
|
|
10
10
|
bindir: exe
|
|
11
11
|
cert_chain: []
|
|
12
|
-
date: 2026-08-
|
|
12
|
+
date: 2026-08-27 00:00:00.000000000 Z
|
|
13
13
|
dependencies:
|
|
14
14
|
- !ruby/object:Gem::Dependency
|
|
15
15
|
name: activerecord
|