Class: Railsful::Deserializer

Inherits:
Object
  • Object
show all
Defined in:
lib/railsful/deserializer.rb

Overview

The deserializer class handles the “unwrapping” of incoming parameters. It translates jsonapi compliant params to those that Rails understands.

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(params) ⇒ Deserializer

Returns a new instance of Deserializer.



12
13
14
# File 'lib/railsful/deserializer.rb', line 12

def initialize(params)
  @params = params
end

Instance Attribute Details

#paramsObject (readonly)

Returns the value of attribute params.



10
11
12
# File 'lib/railsful/deserializer.rb', line 10

def params
  @params
end

Instance Method Details

#attributes(params) ⇒ Object

First level attributes from data object.

:reek:FeatureEnvy



33
34
35
36
37
38
39
40
41
42
43
44
45
46
# File 'lib/railsful/deserializer.rb', line 33

def attributes(params)
  data = params.fetch(:data, {})

  # Merge the resources attributes. Also merge the id since jsonapi does
  # not allow ids in the attribute body.
  attrs = data.fetch(:attributes, {}).merge(id: data[:id])

  # Get the already existing relationships
  data.fetch(:relationships, {}).each do |type, payload|
    attrs.merge!(relationship(type, payload))
  end

  attrs.compact
end

#belongs_to_relationship(type, data) ⇒ Object

rubocop:enable Naming/PredicateName



99
100
101
102
103
104
105
106
107
108
# File 'lib/railsful/deserializer.rb', line 99

def belongs_to_relationship(type, data)
  # Fetch a possible id from the data.
  relation_id = data[:id]

  # If no ID is provided skip it.
  return {} unless relation_id

  # Build the relationship hash.
  { :"#{type}_id" => relation_id }
end

#deserializeObject

Deserializes the given params.

:reek:FeatureEnvy



19
20
21
22
23
24
25
26
27
28
# File 'lib/railsful/deserializer.rb', line 19

def deserialize
  # Fetch attributes including resource id.
  deserialized = attributes(params)

  # Get the included elements.
  deserialized.deeper_merge!(included_hash(params))

  # Return the deserialized params.
  ActionController::Parameters.new(deserialized)
end

#has_many_relationship(type, data) ⇒ Object

rubocop:disable Naming/PredicateName



88
89
90
91
92
93
94
95
96
# File 'lib/railsful/deserializer.rb', line 88

def has_many_relationship(type, data)
  return {} unless data.is_a?(Array)

  ids = data.map { |relation| relation[:id] }.compact

  return {} if ids.empty?

  { :"#{type}_ids" => ids }
end

#included_hash(params) ⇒ Object

Fetches all included associations/relationships from the included hash.

:reek:UtilityFunction



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
# File 'lib/railsful/deserializer.rb', line 52

def included_hash(params)
  included_hash = {}

  params.fetch(:included, []).each do |inc|
    type = inc[:type].to_sym
    attrs = inc[:attributes]

    if params.dig(:data, :relationships, type, :data).is_a?(Array)
      # We pluralize the type since we are dealing with a
      # +has_many+ relationship.
      plural = ActiveSupport::Inflector.pluralize(type)

      included_hash["#{plural}_attributes"] ||= []
      included_hash["#{plural}_attributes"] << attrs
    else
      # When the data value is not an Array we are assuming that we
      # deal with a +has_one+ association. To be on the safe side we also
      # call singularize on the type.
      singular = ActiveSupport::Inflector.singularize(type)

      included_hash["#{singular}_attributes"] = attrs
    end
  end

  included_hash
end

#relationship(type, payload) ⇒ Object



79
80
81
82
83
84
85
# File 'lib/railsful/deserializer.rb', line 79

def relationship(type, payload)
  data = payload[:data]

  return has_many_relationship(type, data) if data.is_a?(Array)

  belongs_to_relationship(type, data)
end