fun_with_json_api 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/MIT-LICENSE +20 -0
- data/Rakefile +28 -0
- data/config/locales/fun_with_json_api.en.yml +13 -0
- data/lib/fun_with_json_api/attribute.rb +38 -0
- data/lib/fun_with_json_api/attributes/boolean_attribute.rb +24 -0
- data/lib/fun_with_json_api/attributes/date_attribute.rb +22 -0
- data/lib/fun_with_json_api/attributes/datetime_attribute.rb +20 -0
- data/lib/fun_with_json_api/attributes/decimal_attribute.rb +23 -0
- data/lib/fun_with_json_api/attributes/float_attribute.rb +20 -0
- data/lib/fun_with_json_api/attributes/integer_attribute.rb +20 -0
- data/lib/fun_with_json_api/attributes/relationship.rb +73 -0
- data/lib/fun_with_json_api/attributes/relationship_collection.rb +99 -0
- data/lib/fun_with_json_api/attributes/string_attribute.rb +9 -0
- data/lib/fun_with_json_api/controller_methods.rb +12 -0
- data/lib/fun_with_json_api/deserializer.rb +70 -0
- data/lib/fun_with_json_api/deserializer_class_methods.rb +83 -0
- data/lib/fun_with_json_api/deserializer_config_builder.rb +48 -0
- data/lib/fun_with_json_api/exception.rb +27 -0
- data/lib/fun_with_json_api/exception_payload.rb +29 -0
- data/lib/fun_with_json_api/exception_payload_serializer.rb +17 -0
- data/lib/fun_with_json_api/exception_serializer.rb +15 -0
- data/lib/fun_with_json_api/exceptions/invalid_attribute.rb +13 -0
- data/lib/fun_with_json_api/exceptions/invalid_document.rb +12 -0
- data/lib/fun_with_json_api/exceptions/invalid_relationship.rb +13 -0
- data/lib/fun_with_json_api/exceptions/missing_relationship.rb +15 -0
- data/lib/fun_with_json_api/pre_deserializer.rb +61 -0
- data/lib/fun_with_json_api/railtie.rb +11 -0
- data/lib/fun_with_json_api/version.rb +3 -0
- data/lib/fun_with_json_api.rb +24 -0
- data/lib/tasks/fun_with_json_api_tasks.rake +4 -0
- data/spec/dummy/README.rdoc +28 -0
- data/spec/dummy/Rakefile +6 -0
- data/spec/dummy/app/assets/javascripts/application.js +13 -0
- data/spec/dummy/app/assets/stylesheets/application.css +15 -0
- data/spec/dummy/app/controllers/application_controller.rb +5 -0
- data/spec/dummy/app/helpers/application_helper.rb +2 -0
- data/spec/dummy/app/views/layouts/application.html.erb +14 -0
- data/spec/dummy/bin/bundle +3 -0
- data/spec/dummy/bin/rails +4 -0
- data/spec/dummy/bin/rake +4 -0
- data/spec/dummy/bin/setup +29 -0
- data/spec/dummy/config/application.rb +25 -0
- data/spec/dummy/config/boot.rb +5 -0
- data/spec/dummy/config/database.yml +25 -0
- data/spec/dummy/config/environment.rb +5 -0
- data/spec/dummy/config/environments/development.rb +41 -0
- data/spec/dummy/config/environments/production.rb +80 -0
- data/spec/dummy/config/environments/test.rb +42 -0
- data/spec/dummy/config/initializers/assets.rb +11 -0
- data/spec/dummy/config/initializers/backtrace_silencers.rb +9 -0
- data/spec/dummy/config/initializers/cookies_serializer.rb +3 -0
- data/spec/dummy/config/initializers/filter_parameter_logging.rb +4 -0
- data/spec/dummy/config/initializers/inflections.rb +16 -0
- data/spec/dummy/config/initializers/mime_types.rb +4 -0
- data/spec/dummy/config/initializers/session_store.rb +3 -0
- data/spec/dummy/config/initializers/wrap_parameters.rb +14 -0
- data/spec/dummy/config/locales/en.yml +23 -0
- data/spec/dummy/config/routes.rb +56 -0
- data/spec/dummy/config/secrets.yml +22 -0
- data/spec/dummy/config.ru +4 -0
- data/spec/dummy/log/test.log +37839 -0
- data/spec/dummy/public/404.html +67 -0
- data/spec/dummy/public/422.html +67 -0
- data/spec/dummy/public/500.html +66 -0
- data/spec/dummy/public/favicon.ico +0 -0
- data/spec/example_spec.rb +64 -0
- data/spec/fixtures/active_record.rb +65 -0
- data/spec/fun_with_json_api/controller_methods_spec.rb +123 -0
- data/spec/fun_with_json_api/deserializer_class_methods_spec.rb +52 -0
- data/spec/fun_with_json_api/deserializer_spec.rb +450 -0
- data/spec/fun_with_json_api/exception_spec.rb +77 -0
- data/spec/fun_with_json_api/pre_deserializer_spec.rb +287 -0
- data/spec/fun_with_json_api_spec.rb +55 -0
- data/spec/spec_helper.rb +33 -0
- metadata +275 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 527661f615009228dc573ed949ccd8ea04349382
|
4
|
+
data.tar.gz: d93b9e012c63f7fab576f9c40c54af9bc3fd8c6e
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 59d7335c4ecb53d0b3b7800e6635ae52240d41750f626f443e567a7025b206245db1a362d13e6d5ee440b561c47e67b8acb7e0395ee511b9a039bf6f5177233f
|
7
|
+
data.tar.gz: 2daad3bbbb9ea0c93fc996bee1f0ded6dade569ef0223e60985a48b42c19aaa176ae4e4920146bb4855f0b344d19abe0508a9936ce06eccc4fa21106ef32455e
|
data/MIT-LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright 2016 Ben Morrall
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/Rakefile
ADDED
@@ -0,0 +1,28 @@
|
|
1
|
+
begin
|
2
|
+
require 'bundler/setup'
|
3
|
+
rescue LoadError
|
4
|
+
puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
|
5
|
+
end
|
6
|
+
|
7
|
+
require 'rdoc/task'
|
8
|
+
|
9
|
+
RDoc::Task.new(:rdoc) do |rdoc|
|
10
|
+
rdoc.rdoc_dir = 'rdoc'
|
11
|
+
rdoc.title = 'FunWithJsonApi'
|
12
|
+
rdoc.options << '--line-numbers'
|
13
|
+
rdoc.rdoc_files.include('README.rdoc')
|
14
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
15
|
+
end
|
16
|
+
|
17
|
+
Bundler::GemHelper.install_tasks
|
18
|
+
|
19
|
+
require 'rubocop/rake_task'
|
20
|
+
RuboCop::RakeTask.new
|
21
|
+
|
22
|
+
require 'rspec/core'
|
23
|
+
require 'rspec/core/rake_task'
|
24
|
+
|
25
|
+
desc 'Run all specs in spec directory (excluding plugin specs)'
|
26
|
+
RSpec::Core::RakeTask.new(:spec)
|
27
|
+
|
28
|
+
task default: [:spec, :rubocop]
|
@@ -0,0 +1,13 @@
|
|
1
|
+
en:
|
2
|
+
fun_with_json_api:
|
3
|
+
exceptions:
|
4
|
+
invalid_document: 'Request json_api document is invalid'
|
5
|
+
invalid_attribute: 'Request json_api document attribute is invalid'
|
6
|
+
invalid_relationship: 'Request json_api document relationship is invalid'
|
7
|
+
missing_relationship: 'Unable to find the requested relationship'
|
8
|
+
invalid_boolean_attribute: "Boolean value should only be true, false, or null"
|
9
|
+
invalid_date_attribute: "Date value should be in the format YYYY-MM-DD"
|
10
|
+
invalid_datetime_attribute: "Datetime value should be a ISO 8601 datetime"
|
11
|
+
invalid_decimal_attribute: "Decimal value must be a decimal number (i.e. 123.45)"
|
12
|
+
invalid_float_attribute: "Float value must be a floating point number (i.e. 123.45)"
|
13
|
+
invalid_integer_attribute: "Integer value must be a integer number (i.e. 123)"
|
@@ -0,0 +1,38 @@
|
|
1
|
+
module FunWithJsonApi
|
2
|
+
class Attribute
|
3
|
+
attr_reader :name
|
4
|
+
attr_reader :as
|
5
|
+
|
6
|
+
def self.create(name, options = {})
|
7
|
+
format = options.fetch(:format, 'string')
|
8
|
+
attribute_class_name = "#{format.to_s.classify}Attribute"
|
9
|
+
if FunWithJsonApi::Attributes.const_defined?(attribute_class_name)
|
10
|
+
FunWithJsonApi::Attributes.const_get(attribute_class_name)
|
11
|
+
else
|
12
|
+
raise ArgumentError, "Unknown attribute type: #{format}"
|
13
|
+
end.new(name, options)
|
14
|
+
end
|
15
|
+
|
16
|
+
def initialize(name, options = {})
|
17
|
+
raise ArgumentError, 'name cannot be blank!' unless name.present?
|
18
|
+
|
19
|
+
@name = name
|
20
|
+
@as = options.fetch(:as, name)
|
21
|
+
end
|
22
|
+
|
23
|
+
def call(value)
|
24
|
+
value
|
25
|
+
end
|
26
|
+
|
27
|
+
def sanitize_attribute_method
|
28
|
+
:"parse_#{param_value}"
|
29
|
+
end
|
30
|
+
|
31
|
+
def param_value
|
32
|
+
as.to_sym
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
# Load pre-defined Attributes
|
38
|
+
Dir["#{File.dirname(__FILE__)}/attributes/**/*.rb"].each { |f| require f }
|
@@ -0,0 +1,24 @@
|
|
1
|
+
module FunWithJsonApi
|
2
|
+
module Attributes
|
3
|
+
# Ensures a value is either Boolean.TRUE, Boolean.FALSE or nil
|
4
|
+
# Raises an argument error otherwise
|
5
|
+
class BooleanAttribute < Attribute
|
6
|
+
def call(value)
|
7
|
+
return nil if value.nil?
|
8
|
+
return value if value.is_a?(TrueClass) || value.is_a?(FalseClass)
|
9
|
+
|
10
|
+
raise build_invalid_attribute_error(value)
|
11
|
+
end
|
12
|
+
|
13
|
+
private
|
14
|
+
|
15
|
+
def build_invalid_attribute_error(value)
|
16
|
+
exception_message = I18n.t('fun_with_json_api.exceptions.invalid_boolean_attribute')
|
17
|
+
payload = ExceptionPayload.new
|
18
|
+
payload.detail = exception_message
|
19
|
+
payload.pointer = "/data/attributes/#{name}"
|
20
|
+
Exceptions::InvalidAttribute.new(exception_message + ": #{value.inspect}", payload)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
module FunWithJsonApi
|
2
|
+
module Attributes
|
3
|
+
class DateAttribute < Attribute
|
4
|
+
DATE_FORMAT = '%Y-%m-%d'.freeze
|
5
|
+
|
6
|
+
def call(value)
|
7
|
+
Date.strptime(value, DATE_FORMAT) if value
|
8
|
+
rescue ArgumentError => exception
|
9
|
+
raise build_invalid_attribute_error(exception, value)
|
10
|
+
end
|
11
|
+
|
12
|
+
private
|
13
|
+
|
14
|
+
def build_invalid_attribute_error(exception, value)
|
15
|
+
payload = ExceptionPayload.new
|
16
|
+
payload.detail = I18n.t('fun_with_json_api.exceptions.invalid_date_attribute')
|
17
|
+
payload.pointer = "/data/attributes/#{name}"
|
18
|
+
Exceptions::InvalidAttribute.new(exception.message + ": #{value.inspect}", payload)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
module FunWithJsonApi
|
2
|
+
module Attributes
|
3
|
+
class DatetimeAttribute < Attribute
|
4
|
+
def call(value)
|
5
|
+
DateTime.iso8601(value) if value
|
6
|
+
rescue ArgumentError => exception
|
7
|
+
raise build_invalid_attribute_error(exception, value)
|
8
|
+
end
|
9
|
+
|
10
|
+
private
|
11
|
+
|
12
|
+
def build_invalid_attribute_error(exception, value)
|
13
|
+
payload = ExceptionPayload.new
|
14
|
+
payload.detail = I18n.t('fun_with_json_api.exceptions.invalid_datetime_attribute')
|
15
|
+
payload.pointer = "/data/attributes/#{name}"
|
16
|
+
Exceptions::InvalidAttribute.new(exception.message + ": #{value.inspect}", payload)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
module FunWithJsonApi
|
2
|
+
module Attributes
|
3
|
+
class DecimalAttribute < Attribute
|
4
|
+
def call(value)
|
5
|
+
if value
|
6
|
+
unless value.to_s =~ /[0-9]+(\.[0-9]+)?/
|
7
|
+
raise build_invalid_attribute_error(value)
|
8
|
+
end
|
9
|
+
BigDecimal.new(value.to_s)
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
protected
|
14
|
+
|
15
|
+
def build_invalid_attribute_error(value)
|
16
|
+
payload = ExceptionPayload.new
|
17
|
+
payload.detail = I18n.t('fun_with_json_api.exceptions.invalid_decimal_attribute')
|
18
|
+
payload.pointer = "/data/attributes/#{name}"
|
19
|
+
Exceptions::InvalidAttribute.new("Unable to parse decimal: #{value.inspect}", payload)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
module FunWithJsonApi
|
2
|
+
module Attributes
|
3
|
+
class FloatAttribute < FunWithJsonApi::Attribute
|
4
|
+
def call(value)
|
5
|
+
Float(value.to_s) if value
|
6
|
+
rescue ArgumentError => exception
|
7
|
+
raise build_invalid_attribute_error(exception, value)
|
8
|
+
end
|
9
|
+
|
10
|
+
private
|
11
|
+
|
12
|
+
def build_invalid_attribute_error(exception, value)
|
13
|
+
payload = ExceptionPayload.new
|
14
|
+
payload.detail = I18n.t('fun_with_json_api.exceptions.invalid_float_attribute')
|
15
|
+
payload.pointer = "/data/attributes/#{name}"
|
16
|
+
Exceptions::InvalidAttribute.new(exception.message + ": #{value.inspect}", payload)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
module FunWithJsonApi
|
2
|
+
module Attributes
|
3
|
+
class IntegerAttribute < FunWithJsonApi::Attribute
|
4
|
+
def call(value)
|
5
|
+
Integer(value.to_s) if value
|
6
|
+
rescue ArgumentError => exception
|
7
|
+
raise build_invalid_attribute_error(exception)
|
8
|
+
end
|
9
|
+
|
10
|
+
private
|
11
|
+
|
12
|
+
def build_invalid_attribute_error(exception)
|
13
|
+
payload = ExceptionPayload.new
|
14
|
+
payload.detail = I18n.t('fun_with_json_api.exceptions.invalid_integer_attribute')
|
15
|
+
payload.pointer = "/data/attributes/#{name}"
|
16
|
+
Exceptions::InvalidAttribute.new(exception.message, payload)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,73 @@
|
|
1
|
+
module FunWithJsonApi
|
2
|
+
module Attributes
|
3
|
+
class Relationship < FunWithJsonApi::Attribute
|
4
|
+
# Creates a new Relationship with name
|
5
|
+
# @param name [String] name of the relationship
|
6
|
+
# @param deserializer_class_or_callable [Class] Class of Deserializer or
|
7
|
+
# a callable that returns one
|
8
|
+
# @param options[at] [String] alias value for the attribute
|
9
|
+
def self.create(name, deserializer_class_or_callable, options = {})
|
10
|
+
new(name, deserializer_class_or_callable, options)
|
11
|
+
end
|
12
|
+
|
13
|
+
delegate :id_param,
|
14
|
+
:type,
|
15
|
+
:resource_class,
|
16
|
+
to: :deserializer
|
17
|
+
|
18
|
+
def initialize(name, deserializer_class, options = {})
|
19
|
+
super(name, options)
|
20
|
+
@deserializer_class = deserializer_class
|
21
|
+
end
|
22
|
+
|
23
|
+
def deserializer
|
24
|
+
@deserializer ||= create_deserializer_from_deserializer_class
|
25
|
+
end
|
26
|
+
|
27
|
+
def call(id_value)
|
28
|
+
unless id_value.nil? || !id_value.is_a?(Array)
|
29
|
+
raise build_invalid_relationship_error(id_value)
|
30
|
+
end
|
31
|
+
|
32
|
+
resource_class.find_by!(id_param => id_value).try(:id) if id_value
|
33
|
+
rescue ActiveRecord::RecordNotFound => e
|
34
|
+
raise convert_record_not_found_error(e, id_value)
|
35
|
+
end
|
36
|
+
|
37
|
+
def param_value
|
38
|
+
:"#{as}_id"
|
39
|
+
end
|
40
|
+
|
41
|
+
private
|
42
|
+
|
43
|
+
# Creates a new Deserializer from the deserializer class
|
44
|
+
def create_deserializer_from_deserializer_class
|
45
|
+
if @deserializer_class.respond_to?(:call)
|
46
|
+
@deserializer_class.call
|
47
|
+
else
|
48
|
+
@deserializer_class
|
49
|
+
end.create(
|
50
|
+
attributes: [],
|
51
|
+
relationships: []
|
52
|
+
)
|
53
|
+
end
|
54
|
+
|
55
|
+
def build_invalid_relationship_error(id_value)
|
56
|
+
exception_message = "#{name} relationship should contain a single '#{type}' data hash"
|
57
|
+
payload = ExceptionPayload.new
|
58
|
+
payload.pointer = "/data/relationships/#{name}"
|
59
|
+
payload.detail = exception_message
|
60
|
+
Exceptions::InvalidRelationship.new(exception_message + ": #{id_value.inspect}", payload)
|
61
|
+
end
|
62
|
+
|
63
|
+
def convert_record_not_found_error(exception, id_value)
|
64
|
+
payload = ExceptionPayload.new
|
65
|
+
payload.pointer = "/data/relationships/#{name}/id"
|
66
|
+
payload.detail = "Unable to find '#{type}' with matching id: #{id_value.inspect}"
|
67
|
+
exception_message = "Couldn't find #{resource_class} where "\
|
68
|
+
"#{id_param} = #{id_value.inspect}: #{exception.message}"
|
69
|
+
Exceptions::MissingRelationship.new(exception_message, payload)
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
@@ -0,0 +1,99 @@
|
|
1
|
+
module FunWithJsonApi
|
2
|
+
module Attributes
|
3
|
+
class RelationshipCollection < FunWithJsonApi::Attribute
|
4
|
+
def self.create(name, deserializer_class_or_callable, options = {})
|
5
|
+
new(name, deserializer_class_or_callable, options)
|
6
|
+
end
|
7
|
+
|
8
|
+
delegate :id_param,
|
9
|
+
:type,
|
10
|
+
:resource_class,
|
11
|
+
to: :deserializer
|
12
|
+
|
13
|
+
def initialize(name, deserializer_class, options = {})
|
14
|
+
super(name, options.reverse_merge(as: name.to_s.singularize.to_sym))
|
15
|
+
@deserializer_class = deserializer_class
|
16
|
+
|
17
|
+
if as.to_s != as.to_s.singularize
|
18
|
+
raise ArgumentError, "Use a singular relationship as value: {as: :#{as.to_s.singularize}}"
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
def deserializer
|
23
|
+
@deserializer ||= create_deserializer_from_deserializer_class
|
24
|
+
end
|
25
|
+
|
26
|
+
# Expects an array of id values for a nested collection
|
27
|
+
def call(values)
|
28
|
+
unless values.nil? || values.is_a?(Array)
|
29
|
+
raise build_invalid_relationship_collection_error(values)
|
30
|
+
end
|
31
|
+
|
32
|
+
collection = resource_class.where(id_param => values)
|
33
|
+
|
34
|
+
# Ensure the collection size matches
|
35
|
+
expected_size = values.size
|
36
|
+
result_size = collection.size
|
37
|
+
if result_size != expected_size
|
38
|
+
raise build_missing_relationship_error_from_collection(collection, values)
|
39
|
+
end
|
40
|
+
|
41
|
+
# Call ActiceRecord#pluck if it is available
|
42
|
+
convert_collection_to_ids(collection)
|
43
|
+
end
|
44
|
+
|
45
|
+
# User the singular of `as` that is how AMS converts the value
|
46
|
+
def param_value
|
47
|
+
:"#{as}_ids"
|
48
|
+
end
|
49
|
+
|
50
|
+
private
|
51
|
+
|
52
|
+
def convert_collection_to_ids(collection)
|
53
|
+
if collection.respond_to? :pluck
|
54
|
+
# Well... pluck+arel doesn't work with SQLite, but select at least is safe
|
55
|
+
collection = collection.select(resource_class.arel_table[:id])
|
56
|
+
end
|
57
|
+
collection.map(&:id)
|
58
|
+
end
|
59
|
+
|
60
|
+
# Creates a new Deserializer from the deserializer class
|
61
|
+
def create_deserializer_from_deserializer_class
|
62
|
+
if @deserializer_class.respond_to?(:call)
|
63
|
+
@deserializer_class.call
|
64
|
+
else
|
65
|
+
@deserializer_class
|
66
|
+
end.create(
|
67
|
+
attributes: [],
|
68
|
+
relationships: []
|
69
|
+
)
|
70
|
+
end
|
71
|
+
|
72
|
+
def build_invalid_relationship_collection_error(values)
|
73
|
+
exception_message = "#{name} relationship should contain a array of '#{type}' data"
|
74
|
+
payload = ExceptionPayload.new
|
75
|
+
payload.pointer = "/data/relationships/#{name}"
|
76
|
+
payload.detail = exception_message
|
77
|
+
Exceptions::InvalidRelationship.new(exception_message + ": #{values.inspect}", payload)
|
78
|
+
end
|
79
|
+
|
80
|
+
def build_missing_relationship_error_from_collection(collection, values)
|
81
|
+
collection_values = collection.map { |resource| resource.public_send(id_param).to_s }
|
82
|
+
missing_values = values.reject { |value| collection_values.include?(value.to_s) }
|
83
|
+
payload = missing_values.map do |value|
|
84
|
+
build_missing_relationship_payload(value)
|
85
|
+
end
|
86
|
+
exception_message = "Couldn't find #{resource_class} items with "\
|
87
|
+
"#{id_param} in #{missing_values.inspect}"
|
88
|
+
Exceptions::MissingRelationship.new(exception_message, payload)
|
89
|
+
end
|
90
|
+
|
91
|
+
def build_missing_relationship_payload(value)
|
92
|
+
ExceptionPayload.new.tap do |payload|
|
93
|
+
payload.pointer = "/data/relationships/#{name}/id"
|
94
|
+
payload.detail = "Unable to find '#{type}' with matching id: #{value.inspect}"
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
require 'fun_with_json_api/exception_serializer'
|
2
|
+
|
3
|
+
module FunWithJsonApi
|
4
|
+
module ControllerMethods
|
5
|
+
def render_fun_with_json_api_exception(exception)
|
6
|
+
render json: exception,
|
7
|
+
serializer: FunWithJsonApi::ExceptionSerializer,
|
8
|
+
adapter: :json,
|
9
|
+
status: exception.http_status
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|