simple_jsonapi_rails 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
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