simple_jsonapi_rails 1.0.0

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.
Files changed (53) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +10 -0
  3. data/.rubocop.yml +132 -0
  4. data/CHANGELOG.md +2 -0
  5. data/Gemfile +5 -0
  6. data/Jenkinsfile +92 -0
  7. data/LICENSE.txt +22 -0
  8. data/README.md +245 -0
  9. data/Rakefile +10 -0
  10. data/lib/simple_jsonapi/errors/active_model_error.rb +21 -0
  11. data/lib/simple_jsonapi/errors/active_model_error_serializer.rb +15 -0
  12. data/lib/simple_jsonapi/errors/active_record/record_not_found_serializer.rb +15 -0
  13. data/lib/simple_jsonapi/rails/action_controller/jsonapi_helper.rb +122 -0
  14. data/lib/simple_jsonapi/rails/action_controller/request_validator.rb +40 -0
  15. data/lib/simple_jsonapi/rails/action_controller.rb +44 -0
  16. data/lib/simple_jsonapi/rails/extensions/routing.rb +57 -0
  17. data/lib/simple_jsonapi/rails/extensions.rb +13 -0
  18. data/lib/simple_jsonapi/rails/railtie.rb +34 -0
  19. data/lib/simple_jsonapi/rails/test_helpers.rb +20 -0
  20. data/lib/simple_jsonapi/rails/version.rb +5 -0
  21. data/lib/simple_jsonapi/rails.rb +13 -0
  22. data/lib/simple_jsonapi_rails.rb +4 -0
  23. data/simple_jsonapi_rails.gemspec +33 -0
  24. data/test/action_controller_test.rb +299 -0
  25. data/test/dummy/.gitignore +23 -0
  26. data/test/dummy/Rakefile +6 -0
  27. data/test/dummy/app/controllers/api_controller.rb +3 -0
  28. data/test/dummy/app/controllers/orders/relationships/items_controller.rb +10 -0
  29. data/test/dummy/app/controllers/orders_controller.rb +38 -0
  30. data/test/dummy/app/models/order.rb +4 -0
  31. data/test/dummy/app/serializers/order_serializer.rb +6 -0
  32. data/test/dummy/config/application.rb +13 -0
  33. data/test/dummy/config/boot.rb +3 -0
  34. data/test/dummy/config/database.yml +7 -0
  35. data/test/dummy/config/environment.rb +5 -0
  36. data/test/dummy/config/environments/development.rb +44 -0
  37. data/test/dummy/config/environments/test.rb +44 -0
  38. data/test/dummy/config/initializers/.keep +0 -0
  39. data/test/dummy/config/locales/en.yml +2 -0
  40. data/test/dummy/config/puma.rb +56 -0
  41. data/test/dummy/config/routes.rb +5 -0
  42. data/test/dummy/config/secrets.yml +24 -0
  43. data/test/dummy/config/spring.rb +6 -0
  44. data/test/dummy/config.ru +5 -0
  45. data/test/dummy/db/migrate/20170719143227_create_orders.rb +10 -0
  46. data/test/dummy/db/seeds.rb +7 -0
  47. data/test/dummy/log/.keep +0 -0
  48. data/test/dummy/tmp/.keep +0 -0
  49. data/test/errors/active_model_error_serializer_test.rb +47 -0
  50. data/test/errors/active_model_error_test.rb +46 -0
  51. data/test/errors/active_record/record_not_found_serializer_test.rb +33 -0
  52. data/test/test_helper.rb +35 -0
  53. metadata +284 -0
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: eb87c3e8f49a4ea784c1aafacf83f82dd69f35ee
4
+ data.tar.gz: 32c513cf1c662eebf42af0a1bc05b3feca0f8ad5
5
+ SHA512:
6
+ metadata.gz: c1f9d71e8dc53a740a449b48e978a4eff6e14a78cb3a8fa23fd235f0109e9250bb2789045b80daf45bde389c09b26ab3d9320832b9a60f72ba3144ed2b05e121
7
+ data.tar.gz: eaa046434edc39bd0ee5237dd48845a15acf178da2d76b40c9c7545ca0915ba749c811dbb28df3b3902f37a3fad01fc6faeede4228b5972931a4f61eafdfc7c6
data/.gitignore ADDED
@@ -0,0 +1,10 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /_yardoc/
4
+ /Gemfile.lock
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
10
+ *.gem
data/.rubocop.yml ADDED
@@ -0,0 +1,132 @@
1
+ AllCops:
2
+ Exclude:
3
+ - '*.gemspec'
4
+ - 'Gemfile*'
5
+ - 'test/dummy/**/*'
6
+ TargetRubyVersion: "2.3"
7
+
8
+ # Do not modify any of these rules without running your changes past the `@techleads` Slack group.
9
+
10
+ # In order to make CodeClimate run in less than 30 minutes (the time-out), we're temporarily turning off
11
+ # some of the low-risk, high-frequency cops. This should be a temporary solution. We should either
12
+ # fix all of these issues across the codebase, or tune the cops to only pull up these issues when they
13
+ # matter (e.g. setting the max line length to 120 instead of 80)
14
+
15
+ Style/StringLiterals:
16
+ Enabled: false # this cop slows rubocop down too much so CodeClimate times out
17
+ EnforcedStyle: double_quotes
18
+
19
+ Style/NumericLiterals:
20
+ Enabled: false # this cop slows rubocop down too much so CodeClimate times out
21
+
22
+ # Permanent rules below
23
+
24
+ Layout/AlignParameters:
25
+ Enabled: false # we haven't reached consensus yet on what this rule should be
26
+
27
+ Layout/CaseIndentation:
28
+ EnforcedStyle: end
29
+ IndentOneStep: false
30
+
31
+ # Layout/ElseAlignment:
32
+ # Enabled: false # we haven't reached consensus yet on what this rule should be
33
+
34
+ # Layout/MultilineMethodCallIndentation:
35
+ # Enabled: false # we haven't reached consensus yet on what this rule should be
36
+
37
+ Layout/MultilineOperationIndentation:
38
+ Enabled: true
39
+ EnforcedStyle: indented
40
+
41
+ Lint/AmbiguousRegexpLiteral:
42
+ Enabled: false # we disagree with this rule
43
+
44
+ # Lint/EndAlignment:
45
+ # EnforcedStyleAlignWith: start_of_line
46
+
47
+ Metrics/AbcSize:
48
+ # There are ~500 methods > 20 as of 3/7/18, vs. ~900 methods > 15 (which is the default)
49
+ Max: 20
50
+
51
+ Metrics/BlockLength:
52
+ Max: 25
53
+ ExcludedMethods: ["class_methods", "describe", "included"]
54
+
55
+ Metrics/ClassLength:
56
+ # nearly all classes over 200 lines are old and crufty and should be split up
57
+ Max: 200
58
+
59
+ Metrics/CyclomaticComplexity:
60
+ # There are ~100 methods > 8 as of 3/7/18, vs. 220 > 6 (which is the default)
61
+ Max: 8
62
+
63
+ Metrics/LineLength:
64
+ # There are 23k lines > 80 chars, 5k > 120, 2k > 140 chars as of 12/21/17
65
+ Max: 120
66
+
67
+ Metrics/MethodLength:
68
+ # There are ~100 methods > 35 lines as of 12/21/17
69
+ Max: 35
70
+
71
+ Metrics/ModuleLength:
72
+ # nearly all modules over 200 lines are old and crufty and should be split up
73
+ Max: 200
74
+
75
+ Metrics/PerceivedComplexity:
76
+ # There are ~100 methods > 8 as of 3/7/18, vs. ~150 methods > 7 (which is the default)
77
+ Max: 8
78
+
79
+ Naming/VariableNumber:
80
+ EnforcedStyle: snake_case # `condition_info_1` is easier to read than `condition_info1`
81
+
82
+ Performance/Casecmp:
83
+ Enabled: false # we generally prefer the readability of downcase over the performance of casecmp
84
+
85
+ Style/Alias:
86
+ EnforcedStyle: prefer_alias_method
87
+
88
+ Style/BracesAroundHashParameters:
89
+ Enabled: false # using braces can be a good choice, e.g., `assert_equal expected_json, { "foo" => "bar" }`
90
+
91
+ Style/ClassAndModuleChildren:
92
+ EnforcedStyle: compact
93
+ Exclude: ["share/**/*"]
94
+
95
+ Style/CollectionMethods:
96
+ Enabled: true
97
+ PreferredMethods:
98
+ collect: map
99
+ collect!: map!
100
+ inject: reduce
101
+ detect: find
102
+ find_all: select
103
+
104
+ Style/Documentation:
105
+ Enabled: false # don't require class and method doc comments
106
+
107
+ Style/EmptyMethod:
108
+ EnforcedStyle: expanded
109
+
110
+ Style/FrozenStringLiteralComment:
111
+ EnforcedStyle: never
112
+
113
+ Style/GuardClause:
114
+ Enabled: false # sometimes guard clauses are appropriate and sometimes they aren't
115
+
116
+ Style/IfUnlessModifier:
117
+ Enabled: false # sometimes its clearer to use traditional if/end conditionals, even if they would fit on one line
118
+
119
+ Style/NumericPredicate:
120
+ Enabled: false # we disagree with this rule
121
+
122
+ Style/SymbolArray:
123
+ Enabled: false # undecided
124
+
125
+ Style/TrailingCommaInArguments:
126
+ EnforcedStyleForMultiline: consistent_comma
127
+
128
+ Style/TrailingCommaInLiteral:
129
+ EnforcedStyleForMultiline: consistent_comma
130
+
131
+ Style/WordArray:
132
+ Enabled: false # sometimes %w makes sense and sometimes it doesn't
data/CHANGELOG.md ADDED
@@ -0,0 +1,2 @@
1
+ ## Version 1.0.0 - April 19, 2018
2
+ * Initial public release
data/Gemfile ADDED
@@ -0,0 +1,5 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gemspec
4
+
5
+ gem 'rake'
data/Jenkinsfile ADDED
@@ -0,0 +1,92 @@
1
+ pipeline {
2
+ agent none
3
+ options {
4
+ timeout(time: 1, unit: 'HOURS')
5
+ skipDefaultCheckout()
6
+ }
7
+
8
+ stages {
9
+ stage("Build Ruby") {
10
+ agent {
11
+ node {
12
+ label 'docker'
13
+ }
14
+ }
15
+
16
+ steps {
17
+ script {
18
+ with_ruby_build() {
19
+ script {
20
+ uid = sh(returnStdout: true, script: 'stat -c %g .').trim()
21
+ gid = sh(returnStdout: true, script: 'stat -c %u .').trim()
22
+ }
23
+
24
+ sh "chown -R ${uid}:${gid} vendor/bundle/"
25
+ sh "rm -rf vendor/bundle/ruby/2.3.0/cache"
26
+ stash name: 'ruby-bundle', includes: 'vendor/bundle/'
27
+ }
28
+ }
29
+ }
30
+ }
31
+
32
+ stage("Test") {
33
+ steps {
34
+ script {
35
+ node('docker') {
36
+ checkout([
37
+ $class: 'GitSCM',
38
+ branches: scm.branches,
39
+ doGenerateSubmoduleConfigurations: scm.doGenerateSubmoduleConfigurations,
40
+ extensions: scm.extensions + [[$class: 'CloneOption', noTags: true, reference: '', shallow: true]],
41
+ userRemoteConfigs: scm.userRemoteConfigs
42
+ ])
43
+ try {
44
+ docker.image('ruby:2.3.3').inside() {
45
+ sh 'rm -rf vendor/bundle'
46
+ unstash 'ruby-bundle'
47
+ sh 'bundle install --path=vendor/bundle'
48
+
49
+ withEnv([
50
+ 'DISABLE_SPRING=1',
51
+ 'TZ=America/New_York'
52
+ ]) {
53
+ sh 'bundle exec rake test'
54
+ }
55
+ }
56
+ }
57
+ finally {
58
+ junit 'test/reports/'
59
+ cleanWs()
60
+ }
61
+ }
62
+ }
63
+ }
64
+ }
65
+ }
66
+
67
+ post {
68
+ failure {
69
+ script {
70
+ if (env.BRANCH_NAME == 'master' || env.BRANCH_NAME == 'current') {
71
+ slackSend (channel: '#plm_website', color: '#FF0000', message: "FAILED ${env.JOB_NAME} [${env.BUILD_NUMBER}] (${env.RUN_DISPLAY_URL})")
72
+ }
73
+ }
74
+ }
75
+ }
76
+ }
77
+
78
+ def with_ruby_build(closure) {
79
+ docker.image('ruby:2.3.3').inside() {
80
+ checkout([
81
+ $class: 'GitSCM',
82
+ branches: scm.branches,
83
+ doGenerateSubmoduleConfigurations: scm.doGenerateSubmoduleConfigurations,
84
+ extensions: scm.extensions + [[$class: 'CloneOption', noTags: true, reference: '', shallow: true]],
85
+ userRemoteConfigs: scm.userRemoteConfigs
86
+ ])
87
+ sh 'rm -rf vendor/bundle'
88
+ sh 'bundle install --path=vendor/bundle'
89
+ closure()
90
+ cleanWs()
91
+ }
92
+ }
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2016-2018 PatientsLikeMe
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,245 @@
1
+ # SimpleJsonapi/Rails
2
+
3
+ A library for integrating SimpleJsonapi into a Rails application.
4
+
5
+ ## Installation
6
+
7
+ Add **simple\_jsonapi\_rails** to your Gemfile and include **SimpleJsonapi::Rails::ActionController** in your API controllers:
8
+
9
+ ```ruby
10
+ # Gemfile
11
+ gem 'simple_jsonapi_rails'
12
+
13
+ # app/controllers/api_controller.rb
14
+ class ApiController < ApplicationController
15
+ include SimpleJsonapi::Rails::ActionController
16
+ end
17
+ ```
18
+
19
+ ## Controllers, parsing, and rendering
20
+
21
+ ### Index actions
22
+
23
+ Render a collection of resources with **`render jsonapi_resources:`**.
24
+
25
+ ```ruby
26
+ class OrdersController < ApiController
27
+ def index
28
+ orders = Order.all # search, sort, paginate, etc.
29
+ render jsonapi_resources: orders
30
+ end
31
+ end
32
+ ```
33
+
34
+ Any additional parameters will be passed through to the serializer.
35
+
36
+ ```ruby
37
+ class OrdersController < ApiController
38
+ def index
39
+ orders = Order.all
40
+ render jsonapi_resources: orders,
41
+ serializer: OrderSerializer,
42
+ fields: jsonapi.fields_params,
43
+ include: jsonapi.include_params,
44
+ sort_related: jsonapi.sort_related_params,
45
+ links: { self: "https://example.com/orders" },
46
+ meta: { generated_at: Time.current },
47
+ extras: { current_user: @current_user }
48
+ end
49
+ end
50
+ ```
51
+
52
+ ### Show actions
53
+
54
+ Render a single resource with **`render jsonapi_resource:`**. Any additional parameters will be passed through to the serializer.
55
+
56
+ ```ruby
57
+ class OrdersController < ApiController
58
+ def show
59
+ order = Order.find(params[:id])
60
+ render jsonapi_resource: order,
61
+ serializer: OrderSerializer,
62
+ ...
63
+ end
64
+ end
65
+ ```
66
+
67
+ ### Create and update actions
68
+
69
+ Incoming JSON:API documents can be parsed into a more Rails-friendly structure by calling **`jsonapi_deserialize`** in the controller class.
70
+
71
+ `jsonapi_deserialize` converts this incoming document ...
72
+
73
+ ```json
74
+ {
75
+ "data": {
76
+ "type": "orders",
77
+ "id": "1",
78
+ "attributes": {
79
+ "customer_name": "Jose",
80
+ "date": "2017-10-01",
81
+ },
82
+ "relationships": {
83
+ "customer": {
84
+ "data": { "type": "customers", "id": "11" }
85
+ },
86
+ "products": {
87
+ "data": [
88
+ { "type": "products", "id": "21" },
89
+ { "type": "widgets", "id": "22" },
90
+ ]
91
+ },
92
+ },
93
+ }
94
+ }
95
+ ```
96
+
97
+ ... to this hash ...
98
+
99
+ ```ruby
100
+ {
101
+ type: "orders",
102
+ id: "1",
103
+ customer_name: "Jose",
104
+ date: "2017-10-01",
105
+ customer_type: "customers",
106
+ customer_id: "11",
107
+ product_types: ["products", "widgets"],
108
+ product_ids: ["21", "22"],
109
+ }
110
+ ```
111
+
112
+ ... which can then be saved with typical Rails actions.
113
+
114
+ ```ruby
115
+ class OrdersController < ApiController
116
+ jsonapi_deserialize :order, only: [:create, :update]
117
+
118
+ def create
119
+ order = Order.create!(order_params)
120
+ render jsonapi_resource: order, status: :created
121
+ end
122
+
123
+ def update
124
+ order = Order.find(params[:id]).update!(order_params)
125
+ render jsonapi_resource: order, status: :ok
126
+ end
127
+
128
+ private
129
+ def order_params
130
+ params.require(:order).permit(:customer_name, :date)
131
+ end
132
+ end
133
+ ```
134
+
135
+ Note the use of bang methods (`#create!` and `#update!`). While not necessary, `ActiveRecord::RecordNotFound`, `::RecordInvalid`, and `::RecordNotSaved` exceptions will be rescued and rendered automatically.
136
+
137
+ You can also render errors explicitly with **`render jsonapi_errors:`**.
138
+
139
+ ```ruby
140
+ class OrdersController < ApiController
141
+ jsonapi_deserialize :order, only: [:create, :update]
142
+
143
+ def create
144
+ order = Order.new(order_params)
145
+ if order.save
146
+ render jsonapi_resource: order, status: :created
147
+ else
148
+ error = SimpleJsonapi::Errors::WrappedError.new(...)
149
+ render jsonapi_errors: error, status: :unprocessable_entity
150
+ end
151
+ end
152
+ end
153
+ ```
154
+
155
+ ## Error handling
156
+
157
+ In addition to restructuring the incoming JSON, `jsonapi_deserialize` also stores a collection of pointers that can be used to render errors.
158
+
159
+ Calling **`jsonapi.pointers`** in a controller action returns the following structure.
160
+
161
+ ```ruby
162
+ # OrdersController#create
163
+ jsonapi.pointers
164
+ => {
165
+ type: "/data/type",
166
+ id: "/data/id",
167
+ customer_name: "/data/attributes/customer_name",
168
+ date: "/data/attributes/date",
169
+ customer_type: "/data/relationships/customer",
170
+ customer_id: "/data/relationships/customer",
171
+ product_types: "/data/relationships/products",
172
+ product_ids: "/data/relationships/products",
173
+ }
174
+ ```
175
+
176
+ SimpleJsonapi/Rails also provides helpers for rendering several Rails-specific errors.
177
+
178
+ **`SimpleJsonapi::Errors::ActiveModelError`** converts an `ActiveModel::Errors` object to an array of serializable errors. This is done automatically in response to `AR::RecordInvalid` or `AR::RecordNotSaved`.
179
+
180
+ ```ruby
181
+ SimpleJsonapi::Errors::ActiveModelError.from_errors(order.errors, jsonapi.pointers)
182
+ => [
183
+ <SimpleJsonapi::Errors::ActiveModelError
184
+ status: "422",
185
+ code: "unprocessable_entity",
186
+ title: "Invalid customer_name",
187
+ detail: "Customer name must be present",
188
+ source: { pointer: "/data/attributes/customer_name" }
189
+ >, ...
190
+ ]
191
+ ```
192
+
193
+ A serializer is provided for `ActiveRecord::RecordNotFound` errors, so they can be rendered directly.
194
+
195
+ ```ruby
196
+ error = ActiveRecord::RecordNotFound.new(...)
197
+ render jsonapi_errors: error, status: :not_found
198
+ ```
199
+
200
+ ## Request Validation
201
+
202
+ SimpleJsonapi/Rails performs some basic request validations via two `before_action`s,
203
+ `validate_jsonapi_request_headers`, and `validate_jsonapi_request_body`.
204
+
205
+ The `Content-Type` header must be set to `application/vnd+api.json` if there is a response body present. If it is not a
206
+ head response will be returned with status 415 Unsupported Media Type.
207
+
208
+ The `Accept` header, if it present, must also be set to `application/vnd+api.json`. If it is not a head response will be
209
+ returned with status 406 Not Acceptable.
210
+
211
+ ## Routing
212
+ Rails' route mapper works well for most jsonapi resource routes. However, simple_jsonapi_rails does supply helpers method
213
+ for defining relationship routes, which can be trickier:
214
+
215
+ ```ruby
216
+ # config/routes.rb
217
+ resources :orders do
218
+ jsonapi_to_many_relationship(:orders, :items)
219
+ jsonapi_to_one_relationship(:orders, :customer)
220
+ end
221
+ ```
222
+
223
+ This code generates the following paths and routes/controller action mappings.
224
+ ```
225
+ orders_relationships_items POST /orders/:order_id/relationships/items(.:format) orders/relationships/items#add
226
+ orders_relationships_items DELETE /orders/:order_id/relationships/items(.:format) orders/relationships/items#remove
227
+ orders_relationships_items PATCH /orders/:order_id/relationships/items(.:format) orders/relationships/items#replace
228
+
229
+ orders_relationships_customer PATCH /orders/:order_id/customer(.:format) orders/relationships/customer#replace
230
+
231
+ ```
232
+
233
+ ## Running tests
234
+
235
+ 1. Change to the gem's directory
236
+ 2. Run `bundle install`
237
+ 3. Run `bundle exec rake test`
238
+
239
+ ## Release Process
240
+ Once pull request is merged to master, on latest master:
241
+ 1. Update CHANGELOG.md. Version: [ major (breaking change: non-backwards
242
+ compatible release) | minor (new features) | patch (bugfixes) ]
243
+ 2. Update version in lib/global_enforcer/version.rb
244
+ 3. Release by running `bundle exec rake release`
245
+
data/Rakefile ADDED
@@ -0,0 +1,10 @@
1
+ require 'bundler/gem_tasks'
2
+ require 'rake/testtask'
3
+
4
+ Rake::TestTask.new(:test) do |t|
5
+ t.libs << 'test'
6
+ t.libs << 'lib'
7
+ t.test_files = FileList['test/**/*_test.rb']
8
+ end
9
+
10
+ task default: :test
@@ -0,0 +1,21 @@
1
+ module SimpleJsonapi
2
+ module Errors
3
+ class ActiveModelError
4
+ def self.from_errors(errors, pointer_mapping = {})
5
+ errors.keys.flat_map do |attribute|
6
+ errors.full_messages_for(attribute).map do |message|
7
+ new(attribute, message, pointer_mapping[attribute])
8
+ end
9
+ end
10
+ end
11
+
12
+ attr_reader :attribute, :message, :pointer
13
+
14
+ def initialize(attribute, message, pointer)
15
+ @attribute = attribute.to_s
16
+ @message = message.to_s
17
+ @pointer = pointer.to_s
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,15 @@
1
+ module SimpleJsonapi
2
+ module Errors
3
+ class ActiveModelErrorSerializer < ErrorSerializer
4
+ status "422"
5
+ code "unprocessable_entity"
6
+
7
+ title { |err| "Invalid #{err.attribute.presence || 'record'}" }
8
+ detail { |err| err.message }
9
+
10
+ source do
11
+ pointer(if: ->(err) { err.pointer.present? }) { |err| err.pointer }
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,15 @@
1
+ module SimpleJsonapi
2
+ module Errors
3
+ module ActiveRecord
4
+ class RecordNotFoundSerializer < SimpleJsonapi::ErrorSerializer
5
+ status "404"
6
+ code "not_found"
7
+ title "Not found"
8
+ detail { |ex| ex.message }
9
+ source do
10
+ parameter { |ex| ex.primary_key }
11
+ end
12
+ end
13
+ end
14
+ end
15
+ end