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.

Instance Method Summary collapse

Instance Method Details

#resolve(depth: 1, fields: nil, context: {}, **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.

Parameters:

  • depth (Fixnum) (defaults to: 1)

    how far to recursively resolve. Must be >= 1

  • fields (Array<String, Symbol>) (defaults to: nil)

    (optional) A subset of fields whose links should be resolved. Defaults to all fields.

  • context (Hash) (defaults to: {})

    passed to the resolved model’s ‘new` function to provide contextual information ex. current locale. See Model#find, Sys#context

  • options (Hash)

    The remaining optional parameters, defined below

Options Hash (**options):

  • circular_reference (Symbol)

    Determines how circular references are handled. ‘:raise` causes a CircularReferenceError to be raised, `:ignore` will cause the field to remain unresolved, and any other value (or nil) will cause the field to point to the previously resolved ruby object for that ID.

Raises:

  • (ArgumentError)


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
# File 'lib/wcc/contentful/model_methods.rb', line 25

def resolve(depth: 1, fields: nil, context: {}, **options)
  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) }

  raw_links =
    links.any? do |field_name|
      raw_value = raw.dig('fields', field_name, sys.locale)
      if raw_value&.is_a? Array
        raw_value.any? { |v| v&.dig('sys', 'type') == 'Link' }
      elsif raw_value
        raw_value.dig('sys', 'type') == 'Link'
      end
    end
  if raw_links
    # use include param to do resolution
    raw = self.class.store.find_by(content_type: self.class.content_type,
                                   filter: { 'sys.id' => id },
                                   options: { include: [depth, 10].min })
    unless raw
      raise WCC::Contentful::ResolveError, "Cannot find #{self.class.content_type} with ID #{id}"
    end

    @raw = raw.freeze
    links.each { |f| instance_variable_set('@' + f, raw.dig('fields', f, sys.locale)) }
  end

  links.each { |f| _resolve_field(f, depth, context, options) }
  self
end

#resolved?(depth: 1, fields: nil) ⇒ Boolean

Determines whether the object has been resolved up to the prescribed depth.

Returns:

  • (Boolean)

Raises:

  • (ArgumentError)


62
63
64
65
66
67
68
69
70
71
# File 'lib/wcc/contentful/model_methods.rb', line 62

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. It also sets the fields to the value for the entry’s ‘#sys.locale`, as though the entry had been retrieved from the API with `locale=WCC::Contentful::ModelMethods#sys#sys.locale` rather than `locale=*`.



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
113
114
115
116
117
# File 'lib/wcc/contentful/model_methods.rb', line 80

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' => { 'locale' => @sys.locale }.merge!(@raw['sys']),
    'fields' => fields
  }
end