Module: WCC::Contentful::ModelMethods
- Defined in:
- lib/wcc/contentful/model_methods.rb
Overview
This module is included by all models and defines instance methods that are not dynamically generated.
Constant Summary collapse
- MODEL_LAYER_CONTEXT_KEYS =
The set of options keys that are specific to the Model layer and shouldn’t be passed down to the Store layer.
%i[ preview backlinks ].freeze
Instance Method Summary collapse
-
#resolve(depth: 1, fields: nil, context: sys.context.to_h, **options) ⇒ Object
Resolves all links in an entry to the specified depth.
-
#resolved?(depth: 1, fields: nil) ⇒ Boolean
Determines whether the object has been resolved up to the prescribed depth.
-
#to_h(stack = nil) ⇒ Object
Turns the current model into a hash representation as though it had been retrieved from the Contentful API.
Instance Method Details
#resolve(depth: 1, fields: nil, context: sys.context.to_h, **options) ⇒ Object
Resolves all links in an entry to the specified depth.
Each link in the entry is recursively retrieved from the store until the given depth is satisfied. Depth resolution is unlimited, circular references will be resolved to the same object.
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 |
# File 'lib/wcc/contentful/model_methods.rb', line 32 def resolve(depth: 1, fields: nil, context: sys.context.to_h, **) raise ArgumentError, "Depth must be > 0 (was #{depth})" unless depth && depth > 0 return self if resolved?(depth: depth, fields: fields) fields = fields.map { |f| f.to_s.camelize(:lower) } if fields.present? fields ||= self.class::FIELDS typedef = self.class.content_type_definition links = fields.select { |f| %i[Asset Link].include?(typedef.fields[f].type) } store = context[:preview] ? self.class.services.preview_store : self.class.services.store raw_link_ids = links.map { |field_name| raw.dig('fields', field_name) } .flat_map do |raw_value| _try_map(raw_value) { |v| v.dig('sys', 'id') if v.dig('sys', 'type') == 'Link' } end raw_link_ids = raw_link_ids.compact backlinked_ids = (context[:backlinks]&.map { |m| m.id } || []) has_unresolved_raw_links = (raw_link_ids - backlinked_ids).any? if has_unresolved_raw_links raw = _instrument 'resolve', id: id, depth: depth, backlinks: backlinked_ids do # use include param to do resolution store.find_by(content_type: self.class.content_type, filter: { 'sys.id' => id }, options: context.except(*MODEL_LAYER_CONTEXT_KEYS).merge!({ include: [depth, 10].min })) end raise WCC::Contentful::ResolveError, "Cannot find #{self.class.content_type} with ID #{id}" unless raw @raw = raw.freeze links.each { |f| instance_variable_set("@#{f}", raw.dig('fields', f)) } end links.each { |f| _resolve_field(f, depth, context, ) } self end |
#resolved?(depth: 1, fields: nil) ⇒ Boolean
Determines whether the object has been resolved up to the prescribed depth.
73 74 75 76 77 78 79 80 81 82 |
# File 'lib/wcc/contentful/model_methods.rb', line 73 def resolved?(depth: 1, fields: nil) raise ArgumentError, "Depth must be > 0 (was #{depth})" unless depth && depth > 0 fields = fields.map { |f| f.to_s.camelize(:lower) } if fields.present? fields ||= self.class::FIELDS typedef = self.class.content_type_definition links = fields.select { |f| %i[Asset Link].include?(typedef.fields[f].type) } links.all? { |f| _resolved_field?(f, depth) } end |
#to_h(stack = nil) ⇒ Object
Turns the current model into a hash representation as though it had been retrieved from the Contentful API.
This differs from ‘#raw` in that it recursively includes the `#to_h` of resolved links.
89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 |
# File 'lib/wcc/contentful/model_methods.rb', line 89 def to_h(stack = nil) raise WCC::Contentful::CircularReferenceError.new(stack, id) if stack&.include?(id) stack = [*stack, id] typedef = self.class.content_type_definition fields = typedef.fields.each_with_object({}) do |(name, field_def), h| if field_def.type == :Link || field_def.type == :Asset if _resolved_field?(name, 0) val = public_send(name) val = _try_map(val) { |v| v.to_h(stack) } else ids = field_def.array ? public_send("#{name}_ids") : public_send("#{name}_id") val = _try_map(ids) do |id| { 'sys' => { 'type' => 'Link', 'linkType' => field_def.type == :Asset ? 'Asset' : 'Entry', 'id' => id } } end end else val = public_send(name) val = _try_map(val) { |v| v.respond_to?(:to_h) ? v.to_h.stringify_keys! : v } end h[name] = val end { 'sys' => @raw['sys'].dup, 'fields' => fields } end |