rest_framework 0.9.14 → 0.9.16
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/VERSION +1 -1
- data/app/views/layouts/rest_framework.html.erb +1 -2
- data/app/views/rest_framework/_head.html.erb +3 -2
- data/app/views/rest_framework/_heading.html.erb +1 -1
- data/app/views/rest_framework/routes_and_forms/_html_form.html.erb +3 -3
- data/app/views/rest_framework/routes_and_forms/_raw_form.html.erb +1 -1
- data/lib/rest_framework/filters/base_filter.rb +1 -1
- data/lib/rest_framework/filters/{model_ordering_filter.rb → ordering_filter.rb} +6 -3
- data/lib/rest_framework/filters/{model_query_filter.rb → query_filter.rb} +10 -7
- data/lib/rest_framework/filters/ransack_filter.rb +1 -1
- data/lib/rest_framework/filters/{model_search_filter.rb → search_filter.rb} +6 -4
- data/lib/rest_framework/filters.rb +3 -3
- data/lib/rest_framework/mixins/base_controller_mixin.rb +39 -63
- data/lib/rest_framework/mixins/bulk_model_controller_mixin.rb +1 -1
- data/lib/rest_framework/mixins/model_controller_mixin.rb +103 -69
- data/lib/rest_framework/serializers/native_serializer.rb +7 -3
- data/lib/rest_framework/utils.rb +13 -3
- data/lib/rest_framework.rb +16 -16
- data/vendor/assets/javascripts/rest_framework/external.min.js +618 -575
- data/vendor/assets/stylesheets/rest_framework/external.min.css +12 -19
- metadata +8 -8
@@ -2,13 +2,17 @@
|
|
2
2
|
module RESTFramework::Mixins::BaseModelControllerMixin
|
3
3
|
BASE64_REGEX = /data:(.*);base64,(.*)/
|
4
4
|
BASE64_TRANSLATE = ->(field, value) {
|
5
|
+
return value unless BASE64_REGEX.match?(value)
|
6
|
+
|
5
7
|
_, content_type, payload = value.match(BASE64_REGEX).to_a
|
6
8
|
return {
|
7
9
|
io: StringIO.new(Base64.decode64(payload)),
|
8
10
|
content_type: content_type,
|
9
|
-
filename: "
|
11
|
+
filename: "file_#{field}#{Rack::Mime::MIME_TYPES.invert[content_type]}",
|
10
12
|
}
|
11
13
|
}
|
14
|
+
ACTIVESTORAGE_KEYS = [:io, :content_type, :filename, :identify, :key]
|
15
|
+
|
12
16
|
include RESTFramework::BaseControllerMixin
|
13
17
|
|
14
18
|
RRF_BASE_MODEL_CONFIG = {
|
@@ -43,14 +47,24 @@ module RESTFramework::Mixins::BaseModelControllerMixin
|
|
43
47
|
native_serializer_associations_limit_query_param: "associations_limit",
|
44
48
|
native_serializer_include_associations_count: false,
|
45
49
|
|
46
|
-
# Attributes for
|
47
|
-
|
50
|
+
# Attributes for filtering, ordering, and searching.
|
51
|
+
filter_backends: [
|
52
|
+
RESTFramework::QueryFilter,
|
53
|
+
RESTFramework::OrderingFilter,
|
54
|
+
RESTFramework::SearchFilter,
|
55
|
+
],
|
56
|
+
filter_recordset_before_find: true,
|
57
|
+
filter_fields: nil,
|
48
58
|
ordering_fields: nil,
|
49
59
|
ordering_query_param: "ordering",
|
50
60
|
ordering_no_reorder: false,
|
51
61
|
search_fields: nil,
|
52
62
|
search_query_param: "search",
|
53
63
|
search_ilike: false,
|
64
|
+
ransack_options: nil,
|
65
|
+
ransack_query_param: "q",
|
66
|
+
ransack_distinct: true,
|
67
|
+
ransack_distinct_query_param: "distinct",
|
54
68
|
|
55
69
|
# Options for association assignment.
|
56
70
|
permit_id_assignment: true,
|
@@ -58,21 +72,11 @@ module RESTFramework::Mixins::BaseModelControllerMixin
|
|
58
72
|
|
59
73
|
# Option for `recordset.create` vs `Model.create` behavior.
|
60
74
|
create_from_recordset: true,
|
61
|
-
|
62
|
-
# Control if filtering is done before find.
|
63
|
-
filter_recordset_before_find: true,
|
64
|
-
|
65
|
-
# Options for `ransack` filtering.
|
66
|
-
ransack_options: nil,
|
67
|
-
ransack_query_param: "q",
|
68
|
-
ransack_distinct: true,
|
69
|
-
ransack_distinct_query_param: "distinct",
|
70
75
|
}
|
71
76
|
|
72
77
|
module ClassMethods
|
73
78
|
IGNORE_VALIDATORS_WITH_KEYS = [:if, :unless].freeze
|
74
79
|
|
75
|
-
# Get the model for this controller.
|
76
80
|
def get_model
|
77
81
|
return @model if @model
|
78
82
|
return (@model = self.model) if self.model
|
@@ -86,8 +90,8 @@ module RESTFramework::Mixins::BaseModelControllerMixin
|
|
86
90
|
raise RESTFramework::UnknownModelError, self
|
87
91
|
end
|
88
92
|
|
89
|
-
# Override
|
90
|
-
def
|
93
|
+
# Override to include ActiveRecord i18n-translated column names.
|
94
|
+
def label_for(s)
|
91
95
|
return self.get_model.human_attribute_name(s, default: super)
|
92
96
|
end
|
93
97
|
|
@@ -115,10 +119,10 @@ module RESTFramework::Mixins::BaseModelControllerMixin
|
|
115
119
|
end
|
116
120
|
|
117
121
|
# Get a field's config, including defaults.
|
118
|
-
def
|
122
|
+
def field_config_for(f)
|
119
123
|
f = f.to_sym
|
120
|
-
@
|
121
|
-
return @
|
124
|
+
@_field_config_for ||= {}
|
125
|
+
return @_field_config_for[f] if @_field_config_for[f]
|
122
126
|
|
123
127
|
config = self.field_config&.dig(f) || {}
|
124
128
|
|
@@ -145,7 +149,7 @@ module RESTFramework::Mixins::BaseModelControllerMixin
|
|
145
149
|
}.to_h.compact.presence
|
146
150
|
end
|
147
151
|
|
148
|
-
return @
|
152
|
+
return @_field_config_for[f] = config.compact
|
149
153
|
end
|
150
154
|
|
151
155
|
# Get metadata about the resource's fields.
|
@@ -171,7 +175,7 @@ module RESTFramework::Mixins::BaseModelControllerMixin
|
|
171
175
|
metadata = {
|
172
176
|
type: nil,
|
173
177
|
kind: nil,
|
174
|
-
label: self.
|
178
|
+
label: self.label_for(f),
|
175
179
|
primary_key: nil,
|
176
180
|
required: nil,
|
177
181
|
read_only: nil,
|
@@ -303,14 +307,14 @@ module RESTFramework::Mixins::BaseModelControllerMixin
|
|
303
307
|
end
|
304
308
|
|
305
309
|
# Serialize any field config.
|
306
|
-
metadata[:config] = self.
|
310
|
+
metadata[:config] = self.field_config_for(f).presence
|
307
311
|
|
308
312
|
next [f, metadata.compact]
|
309
313
|
}.to_h
|
310
314
|
end
|
311
315
|
|
312
316
|
# Get a hash of metadata to be rendered in the `OPTIONS` response.
|
313
|
-
def
|
317
|
+
def options_metadata
|
314
318
|
return super.merge(
|
315
319
|
{
|
316
320
|
primary_key: self.get_model.primary_key,
|
@@ -396,9 +400,8 @@ module RESTFramework::Mixins::BaseModelControllerMixin
|
|
396
400
|
return self.class.get_fields(input_fields: self.class.fields)
|
397
401
|
end
|
398
402
|
|
399
|
-
|
400
|
-
|
401
|
-
return self.class.get_options_metadata
|
403
|
+
def options_metadata
|
404
|
+
return self.class.options_metadata
|
402
405
|
end
|
403
406
|
|
404
407
|
# Get a list of parameters allowed for the current action.
|
@@ -408,7 +411,7 @@ module RESTFramework::Mixins::BaseModelControllerMixin
|
|
408
411
|
@_get_allowed_parameters = self.allowed_parameters
|
409
412
|
return @_get_allowed_parameters if @_get_allowed_parameters
|
410
413
|
|
411
|
-
#
|
414
|
+
# Assemble strong parameters.
|
412
415
|
variations = []
|
413
416
|
hash_variations = {}
|
414
417
|
reflections = self.class.get_model.reflections
|
@@ -417,12 +420,13 @@ module RESTFramework::Mixins::BaseModelControllerMixin
|
|
417
420
|
|
418
421
|
# ActiveStorage Integration: `has_one_attached`.
|
419
422
|
if reflections.key?("#{f}_attachment")
|
423
|
+
hash_variations[f] = ACTIVESTORAGE_KEYS
|
420
424
|
next f
|
421
425
|
end
|
422
426
|
|
423
427
|
# ActiveStorage Integration: `has_many_attached`.
|
424
428
|
if reflections.key?("#{f}_attachments")
|
425
|
-
hash_variations[f] =
|
429
|
+
hash_variations[f] = ACTIVESTORAGE_KEYS
|
426
430
|
next nil
|
427
431
|
end
|
428
432
|
|
@@ -434,6 +438,7 @@ module RESTFramework::Mixins::BaseModelControllerMixin
|
|
434
438
|
# Return field if it's not an association.
|
435
439
|
next f unless ref = reflections[f]
|
436
440
|
|
441
|
+
# Add `_id`/`_ids` variations for associations.
|
437
442
|
if self.permit_id_assignment && id_field = RESTFramework::Utils.get_id_field(f, ref)
|
438
443
|
if id_field.ends_with?("_ids")
|
439
444
|
hash_variations[id_field] = []
|
@@ -442,31 +447,36 @@ module RESTFramework::Mixins::BaseModelControllerMixin
|
|
442
447
|
end
|
443
448
|
end
|
444
449
|
|
450
|
+
# Add `_attributes` variations for associations.
|
445
451
|
if self.permit_nested_attributes_assignment
|
446
|
-
hash_variations["#{f}_attributes"] =
|
452
|
+
hash_variations["#{f}_attributes"] = (
|
453
|
+
self.class.field_config_for(f)[:sub_fields] + ["_destroy"]
|
454
|
+
)
|
447
455
|
end
|
448
456
|
|
449
|
-
# Associations are not allowed to be submitted in their bare form
|
457
|
+
# Associations are not allowed to be submitted in their bare form (if they are submitted that
|
458
|
+
# way, they will be translated to either ID assignment or nested attributes assignment).
|
450
459
|
next nil
|
451
460
|
}.compact
|
452
461
|
@_get_allowed_parameters += variations
|
453
462
|
@_get_allowed_parameters << hash_variations
|
463
|
+
|
454
464
|
return @_get_allowed_parameters
|
455
465
|
end
|
456
466
|
|
457
|
-
|
458
|
-
def get_serializer_class
|
467
|
+
def serializer_class
|
459
468
|
return super || RESTFramework::NativeSerializer
|
460
469
|
end
|
461
470
|
|
462
|
-
|
463
|
-
|
464
|
-
|
465
|
-
|
466
|
-
|
467
|
-
|
468
|
-
|
469
|
-
|
471
|
+
def apply_filters(data)
|
472
|
+
# TODO: Compatibility; remove in 1.0.
|
473
|
+
if filtered_data = self.try(:get_filtered_data, data)
|
474
|
+
return filtered_data
|
475
|
+
end
|
476
|
+
|
477
|
+
return self.filter_backends&.reduce(data) { |d, filter|
|
478
|
+
filter.new(controller: self).filter_data(d)
|
479
|
+
} || data
|
470
480
|
end
|
471
481
|
|
472
482
|
# Use strong parameters to filter the request body using the configured allowed parameters.
|
@@ -492,6 +502,45 @@ module RESTFramework::Mixins::BaseModelControllerMixin
|
|
492
502
|
end
|
493
503
|
end
|
494
504
|
|
505
|
+
# ActiveStorage Integration: Translate base64 encoded attachments to upload objects.
|
506
|
+
#
|
507
|
+
# rubocop:disable Layout/LineLength
|
508
|
+
#
|
509
|
+
# Example base64 images (red, green, and blue squares):
|
510
|
+
# data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAoAAAAKCAYAAACNMs+9AAAAFUlEQVR42mP8z8BQz0AEYBxVSF+FABJADveWkH6oAAAAAElFTkSuQmCC
|
511
|
+
# data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAoAAAAKCAYAAACNMs+9AAAAFUlEQVR42mNk+M9Qz0AEYBxVSF+FAAhKDveksOjmAAAAAElFTkSuQmCC
|
512
|
+
# data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAoAAAAKCAYAAACNMs+9AAAAFUlEQVR42mNkYPhfz0AEYBxVSF+FAP5FDvcfRYWgAAAAAElFTkSuQmCC
|
513
|
+
#
|
514
|
+
# rubocop:enable Layout/LineLength
|
515
|
+
has_many_attached_scalar_data = {}
|
516
|
+
self.class.get_model.attachment_reflections.keys.each do |k|
|
517
|
+
if data[k].is_a?(Array)
|
518
|
+
data[k] = data[k].map { |v|
|
519
|
+
if v.is_a?(String)
|
520
|
+
v = BASE64_TRANSLATE.call(k, v)
|
521
|
+
|
522
|
+
# Remember scalars because Rails strong params will remove it.
|
523
|
+
if v.is_a?(String)
|
524
|
+
has_many_attached_scalar_data[k] ||= []
|
525
|
+
has_many_attached_scalar_data[k] << v
|
526
|
+
end
|
527
|
+
elsif v.is_a?(Hash)
|
528
|
+
if v[:io].is_a?(String)
|
529
|
+
v[:io] = StringIO.new(Base64.decode64(v[:io]))
|
530
|
+
end
|
531
|
+
end
|
532
|
+
|
533
|
+
next v
|
534
|
+
}
|
535
|
+
elsif data[k].is_a?(Hash)
|
536
|
+
if data[k][:io].is_a?(String)
|
537
|
+
data[k][:io] = StringIO.new(Base64.decode64(data[k][:io]))
|
538
|
+
end
|
539
|
+
elsif data[k].is_a?(String)
|
540
|
+
data[k] = BASE64_TRANSLATE.call(k, data[k])
|
541
|
+
end
|
542
|
+
end
|
543
|
+
|
495
544
|
# Filter the request body with strong params. If `bulk` is true, then we apply allowed
|
496
545
|
# parameters to the `_json` key of the request body.
|
497
546
|
body_params = if allowed_params == true
|
@@ -503,6 +552,15 @@ module RESTFramework::Mixins::BaseModelControllerMixin
|
|
503
552
|
ActionController::Parameters.new(data).permit(*allowed_params)
|
504
553
|
end
|
505
554
|
|
555
|
+
# ActiveStorage Integration: Workaround for Rails strong params not allowing you to permit an
|
556
|
+
# array containing a mix of scalars and hashes. This is needed for `has_many_attached`, because
|
557
|
+
# API consumers must be able to provide scalar `signed_id` values for existing attachments along
|
558
|
+
# with hashes for new attachments. It's worth mentioning that base64 scalars are converted to
|
559
|
+
# hashes that conform to the ActiveStorage API.
|
560
|
+
has_many_attached_scalar_data.each do |k, v|
|
561
|
+
body_params[k].unshift(*v)
|
562
|
+
end
|
563
|
+
|
506
564
|
# Filter primary key, if configured.
|
507
565
|
if self.filter_pk_from_request_body && bulk_mode != :update
|
508
566
|
body_params.delete(pk)
|
@@ -511,27 +569,6 @@ module RESTFramework::Mixins::BaseModelControllerMixin
|
|
511
569
|
# Filter fields in `exclude_body_fields`.
|
512
570
|
(self.exclude_body_fields || []).each { |f| body_params.delete(f) }
|
513
571
|
|
514
|
-
# ActiveStorage Integration: Translate base64 encoded attachments to upload objects.
|
515
|
-
#
|
516
|
-
# rubocop:disable Layout/LineLength
|
517
|
-
#
|
518
|
-
# Example base64 image:
|
519
|
-
# data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAAApgAAAKYB3X3/OAAAABl0RVh0U29mdHdhcmUAd3d3Lmlua3NjYXBlLm9yZ5vuPBoAAANCSURBVEiJtZZPbBtFFMZ/M7ubXdtdb1xSFyeilBapySVU8h8OoFaooFSqiihIVIpQBKci6KEg9Q6H9kovIHoCIVQJJCKE1ENFjnAgcaSGC6rEnxBwA04Tx43t2FnvDAfjkNibxgHxnWb2e/u992bee7tCa00YFsffekFY+nUzFtjW0LrvjRXrCDIAaPLlW0nHL0SsZtVoaF98mLrx3pdhOqLtYPHChahZcYYO7KvPFxvRl5XPp1sN3adWiD1ZAqD6XYK1b/dvE5IWryTt2udLFedwc1+9kLp+vbbpoDh+6TklxBeAi9TL0taeWpdmZzQDry0AcO+jQ12RyohqqoYoo8RDwJrU+qXkjWtfi8Xxt58BdQuwQs9qC/afLwCw8tnQbqYAPsgxE1S6F3EAIXux2oQFKm0ihMsOF71dHYx+f3NND68ghCu1YIoePPQN1pGRABkJ6Bus96CutRZMydTl+TvuiRW1m3n0eDl0vRPcEysqdXn+jsQPsrHMquGeXEaY4Yk4wxWcY5V/9scqOMOVUFthatyTy8QyqwZ+kDURKoMWxNKr2EeqVKcTNOajqKoBgOE28U4tdQl5p5bwCw7BWquaZSzAPlwjlithJtp3pTImSqQRrb2Z8PHGigD4RZuNX6JYj6wj7O4TFLbCO/Mn/m8R+h6rYSUb3ekokRY6f/YukArN979jcW+V/S8g0eT/N3VN3kTqWbQ428m9/8k0P/1aIhF36PccEl6EhOcAUCrXKZXXWS3XKd2vc/TRBG9O5ELC17MmWubD2nKhUKZa26Ba2+D3P+4/MNCFwg59oWVeYhkzgN/JDR8deKBoD7Y+ljEjGZ0sosXVTvbc6RHirr2reNy1OXd6pJsQ+gqjk8VWFYmHrwBzW/n+uMPFiRwHB2I7ih8ciHFxIkd/3Omk5tCDV1t+2nNu5sxxpDFNx+huNhVT3/zMDz8usXC3ddaHBj1GHj/As08fwTS7Kt1HBTmyN29vdwAw+/wbwLVOJ3uAD1wi/dUH7Qei66PfyuRj4Ik9is+hglfbkbfR3cnZm7chlUWLdwmprtCohX4HUtlOcQjLYCu+fzGJH2QRKvP3UNz8bWk1qMxjGTOMThZ3kvgLI5AzFfo379UAAAAASUVORK5CYII=
|
520
|
-
#
|
521
|
-
# rubocop:enable Layout/LineLength
|
522
|
-
self.class.get_model.attachment_reflections.keys.each do |k|
|
523
|
-
next unless (body_params[k].is_a?(String) && body_params[k].match?(BASE64_REGEX)) ||
|
524
|
-
(body_params[k].is_a?(Array) && body_params[k].all? { |v|
|
525
|
-
v.is_a?(String) && v.match?(BASE64_REGEX)
|
526
|
-
})
|
527
|
-
|
528
|
-
if body_params[k].is_a?(Array)
|
529
|
-
body_params[k] = body_params[k].map { |v| BASE64_TRANSLATE.call(k, v) }
|
530
|
-
else
|
531
|
-
body_params[k] = BASE64_TRANSLATE.call(k, body_params[k])
|
532
|
-
end
|
533
|
-
end
|
534
|
-
|
535
572
|
return body_params
|
536
573
|
end
|
537
574
|
alias_method :get_create_params, :get_body_params
|
@@ -551,13 +588,12 @@ module RESTFramework::Mixins::BaseModelControllerMixin
|
|
551
588
|
|
552
589
|
# Get the records this controller has access to *after* any filtering is applied.
|
553
590
|
def get_records
|
554
|
-
return @records ||= self.
|
591
|
+
return @records ||= self.apply_filters(self.get_recordset)
|
555
592
|
end
|
556
593
|
|
557
|
-
# Get a single record by primary key or another column, if allowed. The return value is
|
558
|
-
# exposed to the view as the `@record` instance variable.
|
594
|
+
# Get a single record by primary key or another column, if allowed. The return value is memoized
|
595
|
+
# and exposed to the view as the `@record` instance variable.
|
559
596
|
def get_record
|
560
|
-
# Cache the result.
|
561
597
|
return @record if @record
|
562
598
|
|
563
599
|
find_by_key = self.class.get_model.primary_key
|
@@ -582,7 +618,7 @@ module RESTFramework::Mixins::BaseModelControllerMixin
|
|
582
618
|
self.get_recordset
|
583
619
|
end
|
584
620
|
|
585
|
-
# Return the record. Route key is always `:id` by Rails convention.
|
621
|
+
# Return the record. Route key is always `:id` by Rails' convention.
|
586
622
|
if is_pk
|
587
623
|
return @record = collection.find(request.path_parameters[:id])
|
588
624
|
else
|
@@ -609,11 +645,9 @@ module RESTFramework::Mixins::BaseModelControllerMixin
|
|
609
645
|
# This is kinda slow, so perhaps we should eventually integrate `errors` serialization into
|
610
646
|
# the serializer directly. This would fail for active model serializers, but maybe we don't
|
611
647
|
# care?
|
612
|
-
|
648
|
+
s = RESTFramework::Utils.wrap_ams(self.serializer_class)
|
613
649
|
serialized_records = records.map do |record|
|
614
|
-
|
615
|
-
{errors: record.errors.presence}.compact,
|
616
|
-
)
|
650
|
+
s.new(record, controller: self).serialize.merge!({errors: record.errors.presence}.compact)
|
617
651
|
end
|
618
652
|
|
619
653
|
return serialized_records
|
@@ -195,7 +195,7 @@ class RESTFramework::Serializers::NativeSerializer < RESTFramework::Serializers:
|
|
195
195
|
attachment_reflections = @model.attachment_reflections
|
196
196
|
|
197
197
|
fields.each do |f|
|
198
|
-
field_config = @controller.class.
|
198
|
+
field_config = @controller.class.field_config_for(f)
|
199
199
|
next if field_config[:write_only]
|
200
200
|
|
201
201
|
if f.in?(column_names)
|
@@ -259,18 +259,22 @@ class RESTFramework::Serializers::NativeSerializer < RESTFramework::Serializers:
|
|
259
259
|
serializer_methods[f] = f
|
260
260
|
includes_map[f] = {"#{f}_attachment": :blob}
|
261
261
|
self.define_singleton_method(f) do |record|
|
262
|
-
|
262
|
+
attached = record.send(f)
|
263
|
+
next attached.attachment ? {signed_id: attached.signed_id, url: attached.url} : nil
|
263
264
|
end
|
264
265
|
elsif ref.macro == :has_many_attached
|
265
266
|
serializer_methods[f] = f
|
266
267
|
includes_map[f] = {"#{f}_attachments": :blob}
|
267
268
|
self.define_singleton_method(f) do |record|
|
268
269
|
# Iterating the collection yields attachment objects.
|
269
|
-
next record.send(f).map
|
270
|
+
next record.send(f).map { |a| {signed_id: a.signed_id, url: a.url} }
|
270
271
|
end
|
271
272
|
end
|
272
273
|
elsif @model.method_defined?(f)
|
273
274
|
methods << f
|
275
|
+
else
|
276
|
+
# Assume anything else is a virtual column.
|
277
|
+
columns << f
|
274
278
|
end
|
275
279
|
end
|
276
280
|
|
data/lib/rest_framework/utils.rb
CHANGED
@@ -28,7 +28,7 @@ module RESTFramework::Utils
|
|
28
28
|
[f, {}]
|
29
29
|
}.to_h if metadata[:fields].is_a?(Array)
|
30
30
|
metadata[:fields]&.each do |field, cfg|
|
31
|
-
cfg[:label] = controller.
|
31
|
+
cfg[:label] = controller.label_for(field) unless cfg[:label]
|
32
32
|
end
|
33
33
|
end
|
34
34
|
|
@@ -47,7 +47,7 @@ module RESTFramework::Utils
|
|
47
47
|
|
48
48
|
# Insert action label if it's not provided.
|
49
49
|
if controller
|
50
|
-
metadata[:label] ||= controller.
|
50
|
+
metadata[:label] ||= controller.label_for(k)
|
51
51
|
end
|
52
52
|
|
53
53
|
next [
|
@@ -159,9 +159,10 @@ module RESTFramework::Utils
|
|
159
159
|
)
|
160
160
|
parsed_fields += fields_hash[:include].map(&:to_s) if fields_hash[:include]
|
161
161
|
parsed_fields -= fields_hash[:exclude].map(&:to_s) if fields_hash[:exclude]
|
162
|
+
parsed_fields -= fields_hash[:except].map(&:to_s) if fields_hash[:except]
|
162
163
|
|
163
164
|
# Warn for any unknown keys.
|
164
|
-
(fields_hash.keys - [:only, :include, :exclude]).each do |k|
|
165
|
+
(fields_hash.keys - [:only, :except, :include, :exclude]).each do |k|
|
165
166
|
Rails.logger.warn("RRF: Unknown key in fields hash: #{k}")
|
166
167
|
end
|
167
168
|
|
@@ -233,4 +234,13 @@ module RESTFramework::Utils
|
|
233
234
|
|
234
235
|
return nil
|
235
236
|
end
|
237
|
+
|
238
|
+
# Wrap a serializer with an adapter if it is an ActiveModel::Serializer.
|
239
|
+
def self.wrap_ams(s)
|
240
|
+
if defined?(ActiveModel::Serializer) && (s < ActiveModel::Serializer)
|
241
|
+
return RESTFramework::ActiveModelSerializerAdapterFactory.for(s)
|
242
|
+
end
|
243
|
+
|
244
|
+
return s
|
245
|
+
end
|
236
246
|
end
|
data/lib/rest_framework.rb
CHANGED
@@ -31,57 +31,57 @@ module RESTFramework
|
|
31
31
|
EXTERNAL_ASSETS = {
|
32
32
|
# Bootstrap
|
33
33
|
"bootstrap.min.css" => {
|
34
|
-
url: "https://cdn.jsdelivr.net/npm/bootstrap@5.3.
|
35
|
-
sri: "sha384-
|
34
|
+
url: "https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css",
|
35
|
+
sri: "sha384-QWTKZyjpPEjISv5WaRU9OFeRpok6YctnYmDr5pNlyT2bRjXh0JMhjY6hW+ALEwIH",
|
36
36
|
},
|
37
37
|
"bootstrap.min.js" => {
|
38
|
-
url: "https://cdn.jsdelivr.net/npm/bootstrap@5.3.
|
39
|
-
sri: "sha384-
|
38
|
+
url: "https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js",
|
39
|
+
sri: "sha384-YvpcrYf0tY3lHB60NNkmXc5s9fDVZLESaAA55NDzOxhy9GkcIdslK1eN7N6jIeHz",
|
40
40
|
},
|
41
41
|
|
42
42
|
# Bootstrap Icons
|
43
43
|
"bootstrap-icons.min.css" => {
|
44
|
-
url: "https://cdn.jsdelivr.net/npm/bootstrap-icons@1.
|
44
|
+
url: "https://cdn.jsdelivr.net/npm/bootstrap-icons@1.11.3/font/bootstrap-icons.min.css",
|
45
45
|
inline_fonts: true,
|
46
46
|
},
|
47
47
|
|
48
48
|
# Highlight.js
|
49
49
|
"highlight.min.js" => {
|
50
|
-
url: "https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.
|
51
|
-
sri: "sha512-
|
50
|
+
url: "https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.11.0/highlight.min.js",
|
51
|
+
sri: "sha512-6QBAC6Sxc4IF04SvIg0k78l5rP5YgVjmHX2NeArelbxM3JGj4imMqfNzEta3n+mi7iG3nupdLnl3QrbfjdXyTg==",
|
52
52
|
},
|
53
53
|
"highlight-json.min.js" => {
|
54
|
-
url: "https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.
|
55
|
-
sri: "sha512-
|
54
|
+
url: "https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.11.0/languages/json.min.js",
|
55
|
+
sri: "sha512-8JO7/pRnd1Ce8OBXWQg85e5wNPJdBaQdN8w4oDa+HelMXaLwCxTdbzdWHmJtWR9AmcI6dOln4FS5/KrzpxqqfQ==",
|
56
56
|
},
|
57
57
|
"highlight-xml.min.js" => {
|
58
|
-
url: "https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.
|
59
|
-
sri: "sha512
|
58
|
+
url: "https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.11.0/languages/xml.min.js",
|
59
|
+
sri: "sha512-/vq6wbS2Qkv8Hj4mP3Jd/m6MbnIrquzZiUt9tIluQfe332IQeFDrSIK7j2cjAyn6/9Ntb2WMPbo1CAxu26NViA==",
|
60
60
|
},
|
61
61
|
"highlight-a11y-dark.min.css" => {
|
62
|
-
url: "https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.
|
62
|
+
url: "https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.11.0/styles/a11y-dark.min.css",
|
63
63
|
sri: "sha512-Vj6gPCk8EZlqnoveEyuGyYaWZ1+jyjMPg8g4shwyyNlRQl6d3L9At02ZHQr5K6s5duZl/+YKMnM3/8pDhoUphg==",
|
64
64
|
extra_tag_attrs: {class: "rrf-dark-mode"},
|
65
65
|
},
|
66
66
|
"highlight-a11y-light.min.css" => {
|
67
|
-
url: "https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.
|
67
|
+
url: "https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.11.0/styles/a11y-light.min.css",
|
68
68
|
sri: "sha512-WDk6RzwygsN9KecRHAfm9HTN87LQjqdygDmkHSJxVkVI7ErCZ8ZWxP6T8RvBujY1n2/E4Ac+bn2ChXnp5rnnHA==",
|
69
69
|
extra_tag_attrs: {class: "rrf-light-mode"},
|
70
70
|
},
|
71
71
|
|
72
72
|
# NeatJSON
|
73
73
|
"neatjson.min.js" => {
|
74
|
-
url: "https://cdn.jsdelivr.net/npm/neatjson@0.10.
|
74
|
+
url: "https://cdn.jsdelivr.net/npm/neatjson@0.10.6/javascript/neatjson.min.js",
|
75
75
|
exclude_from_docs: true,
|
76
76
|
},
|
77
77
|
|
78
78
|
# Trix
|
79
79
|
"trix.min.css" => {
|
80
|
-
url: "https://unpkg.com/trix@2.0.
|
80
|
+
url: "https://unpkg.com/trix@2.0.8/dist/trix.css",
|
81
81
|
exclude_from_docs: true,
|
82
82
|
},
|
83
83
|
"trix.min.js" => {
|
84
|
-
url: "https://unpkg.com/trix@2.0.
|
84
|
+
url: "https://unpkg.com/trix@2.0.8/dist/trix.umd.min.js",
|
85
85
|
exclude_from_docs: true,
|
86
86
|
},
|
87
87
|
}.map { |name, cfg|
|