rest_framework 0.9.14 → 0.9.16
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/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|
|