jpie 0.4.5 → 1.0.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 +4 -4
- data/.gitignore +21 -0
- data/.rspec +3 -0
- data/.rubocop.yml +35 -110
- data/.travis.yml +7 -0
- data/Gemfile +21 -0
- data/Gemfile.lock +312 -0
- data/README.md +2072 -140
- data/Rakefile +3 -14
- data/bin/console +15 -0
- data/bin/setup +8 -0
- data/jpie.gemspec +18 -35
- data/kiln/app/resources/user_message_resource.rb +2 -0
- data/lib/jpie.rb +3 -24
- data/lib/json_api/active_storage/deserialization.rb +106 -0
- data/lib/json_api/active_storage/detection.rb +74 -0
- data/lib/json_api/active_storage/serialization.rb +32 -0
- data/lib/json_api/configuration.rb +58 -0
- data/lib/json_api/controllers/base_controller.rb +26 -0
- data/lib/json_api/controllers/concerns/controller_helpers.rb +223 -0
- data/lib/json_api/controllers/concerns/resource_actions.rb +657 -0
- data/lib/json_api/controllers/relationships_controller.rb +504 -0
- data/lib/json_api/controllers/resources_controller.rb +6 -0
- data/lib/json_api/errors/parameter_not_allowed.rb +19 -0
- data/lib/json_api/railtie.rb +75 -0
- data/lib/json_api/resources/active_storage_blob_resource.rb +11 -0
- data/lib/json_api/resources/resource.rb +238 -0
- data/lib/json_api/resources/resource_loader.rb +35 -0
- data/lib/json_api/routing.rb +72 -0
- data/lib/json_api/serialization/deserializer.rb +362 -0
- data/lib/json_api/serialization/serializer.rb +320 -0
- data/lib/json_api/support/active_storage_support.rb +85 -0
- data/lib/json_api/support/collection_query.rb +406 -0
- data/lib/json_api/support/instrumentation.rb +42 -0
- data/lib/json_api/support/param_helpers.rb +51 -0
- data/lib/json_api/support/relationship_guard.rb +16 -0
- data/lib/json_api/support/relationship_helpers.rb +74 -0
- data/lib/json_api/support/resource_identifier.rb +87 -0
- data/lib/json_api/support/responders.rb +100 -0
- data/lib/json_api/support/response_helpers.rb +10 -0
- data/lib/json_api/support/sort_parsing.rb +21 -0
- data/lib/json_api/support/type_conversion.rb +21 -0
- data/lib/json_api/testing/test_helper.rb +76 -0
- data/lib/json_api/testing.rb +3 -0
- data/lib/{jpie → json_api}/version.rb +2 -2
- data/lib/json_api.rb +50 -0
- data/lib/rubocop/cop/custom/hash_value_omission.rb +53 -0
- metadata +50 -169
- data/.cursor/rules/dependencies.mdc +0 -19
- data/.cursor/rules/examples.mdc +0 -16
- data/.cursor/rules/git.mdc +0 -14
- data/.cursor/rules/project_structure.mdc +0 -30
- data/.cursor/rules/publish_gem.mdc +0 -73
- data/.cursor/rules/security.mdc +0 -14
- data/.cursor/rules/style.mdc +0 -15
- data/.cursor/rules/testing.mdc +0 -16
- data/.overcommit.yml +0 -35
- data/CHANGELOG.md +0 -164
- data/LICENSE.txt +0 -21
- data/PUBLISHING.md +0 -111
- data/examples/basic_example.md +0 -146
- data/examples/including_related_resources.md +0 -491
- data/examples/pagination.md +0 -303
- data/examples/relationships.md +0 -114
- data/examples/resource_attribute_configuration.md +0 -147
- data/examples/resource_meta_configuration.md +0 -244
- data/examples/rspec_testing.md +0 -130
- data/examples/single_table_inheritance.md +0 -160
- data/lib/jpie/configuration.rb +0 -12
- data/lib/jpie/controller/crud_actions.rb +0 -141
- data/lib/jpie/controller/error_handling/handler_setup.rb +0 -124
- data/lib/jpie/controller/error_handling/handlers.rb +0 -109
- data/lib/jpie/controller/error_handling.rb +0 -23
- data/lib/jpie/controller/json_api_validation.rb +0 -193
- data/lib/jpie/controller/parameter_parsing.rb +0 -78
- data/lib/jpie/controller/related_actions.rb +0 -45
- data/lib/jpie/controller/relationship_actions.rb +0 -291
- data/lib/jpie/controller/relationship_validation.rb +0 -117
- data/lib/jpie/controller/rendering.rb +0 -154
- data/lib/jpie/controller.rb +0 -45
- data/lib/jpie/deserializer.rb +0 -110
- data/lib/jpie/errors.rb +0 -117
- data/lib/jpie/generators/resource_generator.rb +0 -116
- data/lib/jpie/generators/templates/resource.rb.erb +0 -31
- data/lib/jpie/railtie.rb +0 -42
- data/lib/jpie/resource/attributable.rb +0 -112
- data/lib/jpie/resource/inferrable.rb +0 -43
- data/lib/jpie/resource/sortable.rb +0 -93
- data/lib/jpie/resource.rb +0 -147
- data/lib/jpie/routing.rb +0 -59
- data/lib/jpie/serializer.rb +0 -205
|
@@ -0,0 +1,320 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module JSONAPI
|
|
4
|
+
class Serializer
|
|
5
|
+
include ActiveStorageSupport
|
|
6
|
+
|
|
7
|
+
# Class method for generating the JSON:API object
|
|
8
|
+
def self.jsonapi_object
|
|
9
|
+
obj = { version: JSONAPI.configuration.jsonapi_version }
|
|
10
|
+
obj[:meta] = JSONAPI.configuration.jsonapi_meta if JSONAPI.configuration.jsonapi_meta
|
|
11
|
+
obj
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def initialize(record, definition: nil, base_definition: nil)
|
|
15
|
+
@record = record
|
|
16
|
+
@definition = definition || ResourceLoader.find_for_model(record.class)
|
|
17
|
+
@base_definition = base_definition
|
|
18
|
+
@sti_subclass = nil # Cache for sti_subclass? check
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def to_hash(include: [], fields: {}, document_meta: nil)
|
|
22
|
+
{
|
|
23
|
+
jsonapi: jsonapi_object,
|
|
24
|
+
data: serialize_record(fields),
|
|
25
|
+
included: serialize_included(include, fields),
|
|
26
|
+
meta: document_meta
|
|
27
|
+
}.compact
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def serialize_record(fields = {})
|
|
31
|
+
{
|
|
32
|
+
type: record_type,
|
|
33
|
+
id: record_id,
|
|
34
|
+
attributes: serialize_attributes(fields),
|
|
35
|
+
relationships: serialize_relationships,
|
|
36
|
+
links: serialize_links,
|
|
37
|
+
meta: record_meta
|
|
38
|
+
}.compact
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
private
|
|
42
|
+
|
|
43
|
+
attr_reader :record, :definition
|
|
44
|
+
|
|
45
|
+
def base_definition
|
|
46
|
+
@base_definition ||= definition
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
def record_type
|
|
50
|
+
if definition.name.end_with?("Resource")
|
|
51
|
+
RelationshipHelpers.resource_type_name(definition)
|
|
52
|
+
else
|
|
53
|
+
record.class.name.underscore.pluralize
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
def record_id
|
|
58
|
+
record.id.to_s
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
def serialize_attributes(fields = {})
|
|
62
|
+
type_fields = extract_type_fields(fields)
|
|
63
|
+
return {} if type_fields.empty? && fields.any?
|
|
64
|
+
|
|
65
|
+
attributes = build_attributes_hash
|
|
66
|
+
return attributes if type_fields.empty?
|
|
67
|
+
|
|
68
|
+
attributes.slice(*type_fields.map(&:to_sym))
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
def extract_type_fields(fields)
|
|
72
|
+
fields[record_type.to_sym] || []
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
def build_attributes_hash
|
|
76
|
+
permitted_attrs = definition.permitted_attributes.map(&:to_sym)
|
|
77
|
+
attributes = {}
|
|
78
|
+
definition_instance = definition.new(record, {})
|
|
79
|
+
|
|
80
|
+
permitted_attrs.each do |attr_sym|
|
|
81
|
+
attributes[attr_sym] = get_attribute_value(definition_instance, attr_sym)
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
attributes.compact
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
def get_attribute_value(definition_instance, attr_sym)
|
|
88
|
+
return definition_instance.public_send(attr_sym) if definition_instance.respond_to?(attr_sym, false)
|
|
89
|
+
|
|
90
|
+
attr_name = attr_sym.to_s
|
|
91
|
+
return record.attributes[attr_name] if model_has_attribute?(attr_name)
|
|
92
|
+
|
|
93
|
+
nil
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
def model_has_attribute?(attr_name)
|
|
97
|
+
record.respond_to?(:attributes) &&
|
|
98
|
+
record.attributes.is_a?(Hash) &&
|
|
99
|
+
record.attributes.key?(attr_name)
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
def serialize_relationships
|
|
103
|
+
relationships = {}
|
|
104
|
+
relationship_definitions = definition.relationship_definitions
|
|
105
|
+
|
|
106
|
+
relationship_definitions.each do |rel_def|
|
|
107
|
+
serialize_relationship(rel_def, relationships)
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
relationships
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
def serialize_relationship(rel_def, relationships)
|
|
114
|
+
association_name = rel_def[:name]
|
|
115
|
+
|
|
116
|
+
if active_storage_attachment?(association_name, record.class)
|
|
117
|
+
return serialize_active_storage_relationship_wrapper(rel_def, relationships, association_name)
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
serialize_regular_relationship(rel_def, relationships, association_name)
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
def serialize_active_storage_relationship_wrapper(rel_def, relationships, association_name)
|
|
124
|
+
relationships[association_name] = {
|
|
125
|
+
data: serialize_active_storage_relationship(association_name, record),
|
|
126
|
+
meta: rel_def[:meta]
|
|
127
|
+
}.compact
|
|
128
|
+
end
|
|
129
|
+
|
|
130
|
+
def serialize_regular_relationship(rel_def, relationships, association_name)
|
|
131
|
+
association = record.class.reflect_on_association(association_name)
|
|
132
|
+
return unless association
|
|
133
|
+
|
|
134
|
+
relationships[association_name] = {
|
|
135
|
+
data: serialize_relationship_data(association),
|
|
136
|
+
meta: rel_def[:meta]
|
|
137
|
+
}.compact
|
|
138
|
+
end
|
|
139
|
+
|
|
140
|
+
def serialize_relationship_data(association)
|
|
141
|
+
related = record.public_send(association.name)
|
|
142
|
+
|
|
143
|
+
if association.collection?
|
|
144
|
+
serialize_collection_relationship(related, association)
|
|
145
|
+
elsif related
|
|
146
|
+
serialize_single_relationship(related, association)
|
|
147
|
+
end
|
|
148
|
+
end
|
|
149
|
+
|
|
150
|
+
def serialize_collection_relationship(related, association)
|
|
151
|
+
return [] if related.nil?
|
|
152
|
+
|
|
153
|
+
related.map { |r| serialize_identifier_for_related(r, association) }
|
|
154
|
+
end
|
|
155
|
+
|
|
156
|
+
def serialize_single_relationship(related, association)
|
|
157
|
+
serialize_identifier_for_related(related, association)
|
|
158
|
+
end
|
|
159
|
+
|
|
160
|
+
def serialize_identifier_for_related(related_record, association)
|
|
161
|
+
base_def_for_related, use_instance_class = determine_sti_definition(related_record)
|
|
162
|
+
|
|
163
|
+
RelationshipHelpers.serialize_resource_identifier(
|
|
164
|
+
related_record,
|
|
165
|
+
association:,
|
|
166
|
+
resource_class: definition,
|
|
167
|
+
use_instance_class:,
|
|
168
|
+
base_resource_class: base_def_for_related
|
|
169
|
+
)
|
|
170
|
+
end
|
|
171
|
+
|
|
172
|
+
def determine_sti_definition(_related_record)
|
|
173
|
+
[nil, true]
|
|
174
|
+
end
|
|
175
|
+
|
|
176
|
+
def serialize_links
|
|
177
|
+
links = { self: "/#{record_type}/#{record_id}" }
|
|
178
|
+
add_active_storage_download_link(links) if active_storage_blob?
|
|
179
|
+
links
|
|
180
|
+
end
|
|
181
|
+
|
|
182
|
+
def active_storage_blob?
|
|
183
|
+
defined?(::ActiveStorage) && record.is_a?(::ActiveStorage::Blob)
|
|
184
|
+
end
|
|
185
|
+
|
|
186
|
+
def add_active_storage_download_link(links)
|
|
187
|
+
links[:download] = rails_blob_path || fallback_blob_path
|
|
188
|
+
rescue StandardError
|
|
189
|
+
links[:download] = fallback_blob_path
|
|
190
|
+
end
|
|
191
|
+
|
|
192
|
+
def rails_blob_path
|
|
193
|
+
Rails.application.routes.url_helpers.rails_blob_path(record, only_path: true)
|
|
194
|
+
end
|
|
195
|
+
|
|
196
|
+
def fallback_blob_path
|
|
197
|
+
"/rails/active_storage/blobs/#{record.signed_id}/#{record.filename}"
|
|
198
|
+
end
|
|
199
|
+
|
|
200
|
+
def serialize_included(includes, fields = {})
|
|
201
|
+
return [] if includes.empty?
|
|
202
|
+
|
|
203
|
+
included_records = []
|
|
204
|
+
processed = Set.new
|
|
205
|
+
|
|
206
|
+
includes.each do |include_path|
|
|
207
|
+
serialize_include_path(record, include_path, fields, included_records, processed)
|
|
208
|
+
end
|
|
209
|
+
|
|
210
|
+
included_records
|
|
211
|
+
end
|
|
212
|
+
|
|
213
|
+
def serialize_include_path(current_record, include_path, fields, included_records, processed)
|
|
214
|
+
path_parts = include_path.split(".")
|
|
215
|
+
association_name = path_parts.first.to_sym
|
|
216
|
+
|
|
217
|
+
return unless valid_include_association?(current_record, association_name)
|
|
218
|
+
|
|
219
|
+
related_array = get_related_records(current_record, association_name)
|
|
220
|
+
related_array.each do |related_record|
|
|
221
|
+
serialize_and_process_record(related_record, fields, included_records, processed)
|
|
222
|
+
serialize_nested_path(related_record, path_parts, fields, included_records, processed)
|
|
223
|
+
end
|
|
224
|
+
end
|
|
225
|
+
|
|
226
|
+
def valid_include_association?(current_record, association_name)
|
|
227
|
+
current_definition = ResourceLoader.find_for_model(current_record.class)
|
|
228
|
+
relationship_def = RelationshipHelpers.find_relationship_definition(current_definition, association_name)
|
|
229
|
+
return false unless relationship_def
|
|
230
|
+
|
|
231
|
+
# Check for ActiveStorage attachments
|
|
232
|
+
return true if self.class.active_storage_attachment?(association_name, current_record.class)
|
|
233
|
+
|
|
234
|
+
association = current_record.class.reflect_on_association(association_name)
|
|
235
|
+
association.present?
|
|
236
|
+
end
|
|
237
|
+
|
|
238
|
+
def get_related_records(current_record, association_name)
|
|
239
|
+
# Handle ActiveStorage attachments specially
|
|
240
|
+
if self.class.active_storage_attachment?(association_name, current_record.class)
|
|
241
|
+
attachment = current_record.public_send(association_name)
|
|
242
|
+
return [] unless attachment.respond_to?(:attached?) && attachment.attached?
|
|
243
|
+
return attachment.blobs.to_a if attachment.is_a?(::ActiveStorage::Attached::Many)
|
|
244
|
+
|
|
245
|
+
return [attachment.blob].compact
|
|
246
|
+
|
|
247
|
+
end
|
|
248
|
+
|
|
249
|
+
related = current_record.public_send(association_name)
|
|
250
|
+
Array(related)
|
|
251
|
+
end
|
|
252
|
+
|
|
253
|
+
def serialize_and_process_record(related_record, fields, included_records, processed)
|
|
254
|
+
record_key = build_record_key(related_record)
|
|
255
|
+
return if processed.include?(record_key)
|
|
256
|
+
|
|
257
|
+
serializer = self.class.new(related_record)
|
|
258
|
+
included_records << serializer.serialize_record(fields)
|
|
259
|
+
processed.add(record_key)
|
|
260
|
+
end
|
|
261
|
+
|
|
262
|
+
def build_record_key(related_record)
|
|
263
|
+
"#{related_record.class.name}-#{related_record.id}"
|
|
264
|
+
end
|
|
265
|
+
|
|
266
|
+
def serialize_nested_path(related_record, path_parts, fields, included_records, processed)
|
|
267
|
+
return unless path_parts.length > 1
|
|
268
|
+
|
|
269
|
+
nested_path = path_parts[1..].join(".")
|
|
270
|
+
serialize_include_path(related_record, nested_path, fields, included_records, processed)
|
|
271
|
+
end
|
|
272
|
+
|
|
273
|
+
def jsonapi_object
|
|
274
|
+
self.class.jsonapi_object
|
|
275
|
+
end
|
|
276
|
+
|
|
277
|
+
def record_meta
|
|
278
|
+
custom_meta = custom_meta_from_definition
|
|
279
|
+
default_meta = build_default_meta
|
|
280
|
+
|
|
281
|
+
# Merge defaults with custom meta (custom meta can override defaults)
|
|
282
|
+
return unless default_meta.any? || custom_meta.any?
|
|
283
|
+
|
|
284
|
+
default_meta.merge(custom_meta)
|
|
285
|
+
end
|
|
286
|
+
|
|
287
|
+
def custom_meta_from_definition
|
|
288
|
+
meta = nil
|
|
289
|
+
|
|
290
|
+
# Try instance method on Resource class first (dynamic, has access to model via resource)
|
|
291
|
+
if definition.method_defined?(:meta)
|
|
292
|
+
# Directly instantiate the resource class - all resources inherit from ApplicationResource
|
|
293
|
+
# which has initialize(resource = nil, context = {}) and attr_reader :resource
|
|
294
|
+
instance = definition.new(@record, {})
|
|
295
|
+
meta = instance.meta
|
|
296
|
+
# Fall back to class method (static)
|
|
297
|
+
elsif (class_meta = definition.resource_meta)
|
|
298
|
+
meta = class_meta.is_a?(Proc) ? class_meta.call(record) : class_meta
|
|
299
|
+
end
|
|
300
|
+
|
|
301
|
+
# Convert meta to hash if it's not nil
|
|
302
|
+
meta = meta.to_h if meta.respond_to?(:to_h) && !meta.is_a?(Hash)
|
|
303
|
+
meta || {}
|
|
304
|
+
end
|
|
305
|
+
|
|
306
|
+
def build_default_meta
|
|
307
|
+
default_timestamp_meta
|
|
308
|
+
end
|
|
309
|
+
|
|
310
|
+
def default_timestamp_meta
|
|
311
|
+
meta = {}
|
|
312
|
+
|
|
313
|
+
meta[:created_at] = record.created_at.iso8601 if record.respond_to?(:created_at) && record.created_at.present?
|
|
314
|
+
|
|
315
|
+
meta[:updated_at] = record.updated_at.iso8601 if record.respond_to?(:updated_at) && record.updated_at.present?
|
|
316
|
+
|
|
317
|
+
meta
|
|
318
|
+
end
|
|
319
|
+
end
|
|
320
|
+
end
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "active_support/concern"
|
|
4
|
+
|
|
5
|
+
module JSONAPI
|
|
6
|
+
module ActiveStorageSupport
|
|
7
|
+
extend ActiveSupport::Concern
|
|
8
|
+
|
|
9
|
+
module ClassMethods
|
|
10
|
+
def active_storage_attachment?(association_name, model_class)
|
|
11
|
+
ActiveStorage::Detection.attachment?(association_name, model_class)
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def active_storage_blob_type?(type)
|
|
15
|
+
ActiveStorage::Detection.blob_type?(type)
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def active_storage_attachment?(association_name, model_class = nil)
|
|
20
|
+
return self.class.active_storage_attachment?(association_name, model_class) if model_class
|
|
21
|
+
|
|
22
|
+
resolved_model_class = if respond_to?(:model_class, true)
|
|
23
|
+
send(:model_class)
|
|
24
|
+
elsif respond_to?(:resource_model_class, true)
|
|
25
|
+
send(:resource_model_class)
|
|
26
|
+
elsif respond_to?(:resource, true) && (res = send(:resource)) && res.respond_to?(:class)
|
|
27
|
+
res.class
|
|
28
|
+
else
|
|
29
|
+
raise NotImplementedError,
|
|
30
|
+
"Must implement resource_model_class or provide model_class parameter"
|
|
31
|
+
end
|
|
32
|
+
self.class.active_storage_attachment?(association_name, resolved_model_class)
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def extract_active_storage_params_from_hash(params_hash, model_class)
|
|
36
|
+
ActiveStorage::Deserialization.extract_params_from_hash(params_hash, model_class)
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def attach_active_storage_files(record, attachment_params, resource_class: nil)
|
|
40
|
+
ActiveStorage::Deserialization.attach_files(record, attachment_params, definition: resource_class)
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def purge_on_nil_enabled?(attachment_name, resource_class)
|
|
44
|
+
ActiveStorage::Deserialization.purge_on_nil_enabled?(attachment_name, resource_class)
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def append_only_enabled?(attachment_name, resource_class)
|
|
48
|
+
ActiveStorage::Deserialization.append_only_enabled?(attachment_name, resource_class)
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
def find_relationship_definition(attachment_name, resource_class)
|
|
52
|
+
ActiveStorage::Deserialization.find_relationship_definition(attachment_name, resource_class)
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
def filter_active_storage_from_includes(includes_hash, current_model_class)
|
|
56
|
+
ActiveStorage::Detection.filter_from_includes(includes_hash, current_model_class)
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
def filter_polymorphic_from_includes(includes_hash, current_model_class)
|
|
60
|
+
ActiveStorage::Detection.filter_polymorphic_from_includes(includes_hash, current_model_class)
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
def serialize_active_storage_relationship(attachment_name, record)
|
|
64
|
+
ActiveStorage::Serialization.serialize_relationship(attachment_name, record)
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
def serialize_blob_identifier(blob)
|
|
68
|
+
ActiveStorage::Serialization.serialize_blob_identifier(blob)
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
def process_active_storage_attachment(attrs, association_name, id_or_ids, singular:)
|
|
72
|
+
ActiveStorage::Deserialization.process_attachment(attrs, association_name, id_or_ids, singular:)
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
def find_blob_by_signed_id(signed_id)
|
|
76
|
+
ActiveStorage::Deserialization.find_blob_by_signed_id(signed_id)
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
private
|
|
80
|
+
|
|
81
|
+
def resource_model_class
|
|
82
|
+
raise NotImplementedError, "Must implement resource_model_class or override active_storage_attachment?"
|
|
83
|
+
end
|
|
84
|
+
end
|
|
85
|
+
end
|