This repository has been archived by the owner on Jul 11, 2020. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 9
/
render_json_meta.rb
112 lines (93 loc) · 3.44 KB
/
render_json_meta.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
module RenderJsonMeta
extend ActiveSupport::Concern
included do
##
# Hooks into ActiveModelSerializer's ActionController::Serialization `_render_option_json` method
def _render_option_json(resource, options)
# All modules that are included will be able to add to the metadata hash
metadata = (options[:meta] || {}).tap do |metadata|
_add_metadata(resource, metadata)
end
options[:meta] = metadata unless metadata.blank?
super
end
end
##
# Default metadata method (a no-op) that does not call `super`
module MetadataDefault
def _add_metadata(resource, metadata); end
end
##
# For AssociationRelations, add known `where_values_hash` to the meta data
module MetadataWhereValues
def _add_metadata(resource, metadata)
if ActiveRecord::AssociationRelation === resource && resource.respond_to?(:where_values_hash)
metadata[:where_values] = resource.where_values_hash
end
super
end
end
##
# Returns the `natural_key` for the resource
module MetadataNaturalKey
def _add_metadata(resource, metadata)
_collect_metadata(:natural_key, resource, metadata) do |model|
model.class.natural_key if model.class.respond_to?(:natural_key) && model.class.natural_key
end
super
end
end
##
# For AssociationRelations, add known `nested_resource_names` to the meta data
module MetadataNestedResources
def _add_metadata(resource, metadata)
_collect_metadata(:nested_resources, resource, metadata) do |model|
model.class.nested_resource_names if model.class.respond_to?(:nested_resource_names)
end
super
end
end
##
# Adds `read_only` attributes from the serializer of the resource, or traverse
# the AssociationRelation/Relation for each one of the collection's `read_only` attributes
module MetadataReadOnly
def _add_metadata(resource, metadata)
_collect_metadata(:read_only, resource, metadata) do |model|
serializer = model.try(:active_model_serializer)
if serializer.respond_to?(:read_only)
serializer._read_only if serializer.read_only
end
end
super
end
end
private
def _collect_metadata(key, resource, metadata, &block)
if ActiveRecord::AssociationRelation === resource || ActiveRecord::Relation === resource
resource.each { |model| _assign_metadata(key, model, metadata, &block) }
else
_assign_metadata(key, resource, metadata, &block)
end
end
def _assign_metadata(attribute_key, resource, metadata)
class_key = resource.class.name.underscore
# quick return if attribute is already computed
return if metadata[class_key] && metadata[class_key][attribute_key]
if results = yield(resource)
metadata[class_key] ||= {}
metadata[class_key].merge!({ attribute_key => results })
end
end
end
# Hook all of the RenderJsonMeta modules into ActionController
# Each module will be chained together on the `_add_meta_data` method.
ActiveSupport.on_load(:action_controller) do
include ::RenderJsonMeta
# Modules could not be included within the concern, likely
# because the context is lost from her in the on_load block
include ::RenderJsonMeta::MetadataDefault
include ::RenderJsonMeta::MetadataNaturalKey
include ::RenderJsonMeta::MetadataWhereValues
include ::RenderJsonMeta::MetadataNestedResources
include ::RenderJsonMeta::MetadataReadOnly
end