Module: JSONAPI::Rails

Defined in:
lib/jsonapi/rails.rb

Constant Summary collapse

JSONAPI_METHODS_MAPPING =
{
  meta: :jsonapi_meta,
  links: :jsonapi_pagination,
  fields: :jsonapi_fields,
  include: :jsonapi_include,
  params: :jsonapi_serializer_params
}

Class Method Summary collapse

Class Method Details

.add_errors_renderer!NilClass

Adds the error renderer

Returns:

  • (NilClass)


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
# File 'lib/jsonapi/rails.rb', line 38

def self.add_errors_renderer!
  ActionController::Renderers.add(:jsonapi_errors) do |resource, options|
    self.content_type = Mime[:jsonapi] if self.media_type.nil?

    many = JSONAPI::Rails.is_collection?(resource, options[:is_collection])
    resource = [resource] unless many

    return JSONAPI::Rails.serializer_to_json(
      JSONAPI::ErrorSerializer.new(resource, options)
    ) unless resource.is_a?(ActiveModel::Errors)

    errors = []
    model = resource.instance_variable_get(:@base)

    if respond_to?(:jsonapi_serializer_class, true)
      model_serializer = jsonapi_serializer_class(model, false)
    else
      model_serializer = JSONAPI::Rails.serializer_class(model, false)
    end

    details = {}
    if ::Rails.gem_version >= Gem::Version.new('6.1')
      resource.each do |error|
        attr = error.attribute
        details[attr] ||= []
        details[attr] << error.detail.merge(message: error.message)
      end
    elsif resource.respond_to?(:details)
      details = resource.details
    else
      details = resource.messages
    end

    details.each do |error_key, error_hashes|
      error_hashes.each do |error_hash|
        # Rails 4 provides just the message.
        error_hash = { message: error_hash } unless error_hash.is_a?(Hash)

        errors << [ error_key, error_hash ]
      end
    end

    JSONAPI::Rails.serializer_to_json(
      JSONAPI::ActiveModelErrorSerializer.new(
        errors, params: { model: model, model_serializer: model_serializer }
      )
    )
  end
end

.add_renderer!NilClass

Adds the default renderer

Returns:

  • (NilClass)


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
# File 'lib/jsonapi/rails.rb', line 91

def self.add_renderer!
  ActionController::Renderers.add(:jsonapi) do |resource, options|
    self.content_type = Mime[:jsonapi] if self.media_type.nil?

    JSONAPI_METHODS_MAPPING.to_a[0..1].each do |opt, method_name|
      next unless respond_to?(method_name, true)
      options[opt] ||= send(method_name, resource)
    end

    # If it's an empty collection, return it directly.
    many = JSONAPI::Rails.is_collection?(resource, options[:is_collection])
    if many && !resource.any?
      return options.slice(:meta, :links).compact.merge(data: []).to_json
    end

    JSONAPI_METHODS_MAPPING.to_a[2..-1].each do |opt, method_name|
      options[opt] ||= send(method_name) if respond_to?(method_name, true)
    end

    if respond_to?(:jsonapi_serializer_class, true)
      serializer_class = jsonapi_serializer_class(resource, many)
    else
      serializer_class = JSONAPI::Rails.serializer_class(resource, many)
    end

    JSONAPI::Rails.serializer_to_json(
      serializer_class.new(resource, options)
    )
  end
end

.install!NilClass

Updates the mime types and registers the renderers

Returns:

  • (NilClass)


18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
# File 'lib/jsonapi/rails.rb', line 18

def self.install!
  return unless defined?(::Rails)

  Mime::Type.register JSONAPI::MEDIA_TYPE, :jsonapi

  # Map the JSON parser to the JSONAPI mime type requests.
  if ::Rails::VERSION::MAJOR >= 5
    parser = ActionDispatch::Request.parameter_parsers[:json]
    ActionDispatch::Request.parameter_parsers[:jsonapi] = parser
  else
    ActionDispatch::ParamsParser::DEFAULT_PARSERS[Mime[:jsonapi]] = :json
  end

  self.add_renderer!
  self.add_errors_renderer!
end

.is_collection?(resource, force_is_collection = nil) ⇒ TrueClass

Checks if an object is a collection

Basically forwards it to a [JSONAPI::Serializer] as there’s no public API

Parameters:

  • resource (Object)

    to check

  • force_is_collection (NilClass) (defaults to: nil)

    flag to overwrite

Returns:

  • (TrueClass)

    upon success



129
130
131
# File 'lib/jsonapi/rails.rb', line 129

def self.is_collection?(resource, force_is_collection = nil)
  JSONAPI::ErrorSerializer.is_collection?(resource, force_is_collection)
end

.serializer_class(resource, is_collection) ⇒ Class

Resolves resource serializer class

Returns:

  • (Class)


136
137
138
139
140
141
# File 'lib/jsonapi/rails.rb', line 136

def self.serializer_class(resource, is_collection)
  klass = resource.class
  klass = resource.first.class if is_collection

  "#{klass.name}Serializer".constantize
end

.serializer_to_json(serializer) ⇒ String

Lazily returns the serializer JSON

Parameters:

  • serializer (Object)

    to evaluate

Returns:

  • (String)


147
148
149
150
151
152
153
# File 'lib/jsonapi/rails.rb', line 147

def self.serializer_to_json(serializer)
  if serializer.respond_to?(:serialized_json)
    serializer.serialized_json
  else
    serializer.serializable_hash.to_json
  end
end