jsonapi.rb 1.5.7 → 2.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/README.md +28 -4
- data/lib/jsonapi/active_model_error_serializer.rb +0 -3
- data/lib/jsonapi/error_serializer.rb +8 -3
- data/lib/jsonapi/filtering.rb +7 -2
- data/lib/jsonapi/pagination.rb +25 -5
- data/lib/jsonapi/rails.rb +38 -13
- data/lib/jsonapi/version.rb +1 -1
- data/spec/deserialization_spec.rb +87 -0
- data/spec/dummy.rb +162 -0
- data/spec/errors_spec.rb +168 -0
- data/spec/fetching_spec.rb +65 -0
- data/spec/filtering_spec.rb +101 -0
- data/spec/pagination_spec.rb +246 -0
- data/spec/spec_helper.rb +87 -0
- metadata +37 -27
- data/.github/ISSUE_TEMPLATE.md +0 -16
- data/.github/PULL_REQUEST_TEMPLATE.md +0 -17
- data/.github/workflows/ci.yml +0 -36
- data/.gitignore +0 -3
- data/.rspec +0 -3
- data/.rubocop.yml +0 -36
- data/.yardstick.yml +0 -29
- data/Gemfile +0 -6
- data/Rakefile +0 -30
- data/jsonapi.rb.gemspec +0 -40
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 2192bbffc57d4ecbe419a90e25728951db4464c5f299e8866afefe72fa393cad
|
4
|
+
data.tar.gz: f7f83b43169207e7cf6d06e6e99cc8c8f705de09c4c83ff9dba5238540577a9e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 577c2b0d1801ef2191c25925e407449ff12ba95d7fc5c8433fcbb2b20e532a1b7a51a884f147c5042c38ec27ca9eed6567bfd746aad4ad8895b7a3f90e9043b1
|
7
|
+
data.tar.gz: f6ca1bc49fd89c1ea942f3c047234d76c4fa1d7604bd06aa5d67c43dad93603cb19e6c542ec13837d1db5e3fbe923ec4799fd865c96c08822dcab7cb160d7f7e
|
data/README.md
CHANGED
@@ -31,7 +31,7 @@ Main goals:
|
|
31
31
|
|
32
32
|
The available features include:
|
33
33
|
|
34
|
-
* object serialization (powered by
|
34
|
+
* object serialization (powered by JSON:API Serializer, was `fast_jsonapi`)
|
35
35
|
* [error handling](https://jsonapi.org/format/#errors) (parameters,
|
36
36
|
validation, generic errors)
|
37
37
|
* fetching of the data (support for
|
@@ -39,16 +39,26 @@ The available features include:
|
|
39
39
|
[sparse fields](https://jsonapi.org/format/#fetching-sparse-fieldsets))
|
40
40
|
* [filtering](https://jsonapi.org/format/#fetching-filtering) and
|
41
41
|
[sorting](https://jsonapi.org/format/#fetching-sorting) of the data
|
42
|
-
(powered by Ransack)
|
42
|
+
(powered by Ransack, soft-dependency)
|
43
43
|
* [pagination](https://jsonapi.org/format/#fetching-pagination) support
|
44
44
|
|
45
45
|
## But how?
|
46
46
|
|
47
|
-
Mainly by leveraging [
|
47
|
+
Mainly by leveraging [JSON:API Serializer](https://github.com/jsonapi-serializer/jsonapi-serializer)
|
48
48
|
and [Ransack](https://github.com/activerecord-hackery/ransack).
|
49
49
|
|
50
50
|
Thanks to everyone who worked on these amazing projects!
|
51
51
|
|
52
|
+
## Sponsors
|
53
|
+
|
54
|
+
I'm grateful for the following companies for supporting this project!
|
55
|
+
|
56
|
+
<p align="center">
|
57
|
+
<a href="https://www.luneteyewear.com"><img src="https://user-images.githubusercontent.com/112147/136836142-2bfba96e-447f-4eb6-b137-2445aee81b37.png"/></a>
|
58
|
+
<a href="https://www.startuplandia.io"><img src="https://user-images.githubusercontent.com/112147/136836147-93f8ab17-2465-4477-a7ab-e38255483c66.png"/></a>
|
59
|
+
</p>
|
60
|
+
|
61
|
+
|
52
62
|
## Installation
|
53
63
|
|
54
64
|
Add this line to your application's Gemfile:
|
@@ -100,7 +110,7 @@ The naming scheme follows the `ModuleName::ClassNameSerializer` for an instance
|
|
100
110
|
of the `ModuleName::ClassName`.
|
101
111
|
|
102
112
|
Please follow the
|
103
|
-
[
|
113
|
+
[JSON:API Serializer guide](https://github.com/jsonapi-serializer/jsonapi-serializer#serializer-definition)
|
104
114
|
on how to define a serializer.
|
105
115
|
|
106
116
|
To provide a different naming scheme implement the `jsonapi_serializer_class`
|
@@ -231,6 +241,8 @@ to filter and sort over a collection of records.
|
|
231
241
|
The support is pretty extended and covers also relationships and composite
|
232
242
|
matchers.
|
233
243
|
|
244
|
+
Please add `ransack` to your `Gemfile` in order to benefit from this functionality!
|
245
|
+
|
234
246
|
Here's an example:
|
235
247
|
|
236
248
|
```ruby
|
@@ -290,6 +302,7 @@ class MyController < ActionController::Base
|
|
290
302
|
render jsonapi: paginated
|
291
303
|
end
|
292
304
|
end
|
305
|
+
|
293
306
|
end
|
294
307
|
```
|
295
308
|
|
@@ -306,6 +319,17 @@ use the `jsonapi_pagination_meta` method:
|
|
306
319
|
end
|
307
320
|
|
308
321
|
```
|
322
|
+
|
323
|
+
If you want to change the default number of items per page or define a custom logic to handle page size, use the
|
324
|
+
`jsonapi_page_size` method:
|
325
|
+
|
326
|
+
```ruby
|
327
|
+
def jsonapi_page_size(pagination_params)
|
328
|
+
per_page = pagination_params[:size].to_f.to_i
|
329
|
+
per_page = 30 if per_page > 30 || per_page < 1
|
330
|
+
per_page
|
331
|
+
end
|
332
|
+
```
|
309
333
|
### Deserialization
|
310
334
|
|
311
335
|
`JSONAPI::Deserialization` provides a helper to transform a `JSONAPI` document
|
@@ -1,11 +1,10 @@
|
|
1
|
-
require '
|
1
|
+
require 'jsonapi/serializer'
|
2
2
|
|
3
3
|
module JSONAPI
|
4
4
|
# A simple error serializer
|
5
5
|
class ErrorSerializer
|
6
|
-
include
|
6
|
+
include JSONAPI::Serializer
|
7
7
|
|
8
|
-
set_id :object_id
|
9
8
|
set_type :error
|
10
9
|
|
11
10
|
# Object/Hash attribute helpers.
|
@@ -15,6 +14,12 @@ module JSONAPI
|
|
15
14
|
end
|
16
15
|
end
|
17
16
|
|
17
|
+
# Overwrite the ID extraction method, to skip validations
|
18
|
+
#
|
19
|
+
# @return [NilClass]
|
20
|
+
def self.id_from_record(_record, _params)
|
21
|
+
end
|
22
|
+
|
18
23
|
# Remap the root key to `errors`
|
19
24
|
#
|
20
25
|
# @return [Hash]
|
data/lib/jsonapi/filtering.rb
CHANGED
@@ -1,5 +1,10 @@
|
|
1
|
-
|
2
|
-
|
1
|
+
begin
|
2
|
+
require 'active_record'
|
3
|
+
require 'ransack'
|
4
|
+
require_relative 'patches'
|
5
|
+
rescue LoadError
|
6
|
+
warn('Install `ransack` gem before using `JSONAPI::Filtering`!')
|
7
|
+
end
|
3
8
|
|
4
9
|
# Filtering and sorting support
|
5
10
|
module JSONAPI
|
data/lib/jsonapi/pagination.rb
CHANGED
@@ -43,6 +43,8 @@ module JSONAPI
|
|
43
43
|
original_url = request.base_url + request.path + '?'
|
44
44
|
|
45
45
|
pagination.each do |page_name, number|
|
46
|
+
next if page_name == :records
|
47
|
+
|
46
48
|
original_params[:page][:number] = number
|
47
49
|
links[page_name] = original_url + CGI.unescape(
|
48
50
|
original_params.to_query
|
@@ -63,7 +65,7 @@ module JSONAPI
|
|
63
65
|
numbers = { current: page }
|
64
66
|
|
65
67
|
if resources.respond_to?(:unscope)
|
66
|
-
total = resources.unscope(:limit, :offset, :order).
|
68
|
+
total = resources.unscope(:limit, :offset, :order).size
|
67
69
|
else
|
68
70
|
# Try to fetch the cached size first
|
69
71
|
total = resources.instance_variable_get(:@original_size)
|
@@ -82,6 +84,10 @@ module JSONAPI
|
|
82
84
|
numbers[:last] = last_page
|
83
85
|
end
|
84
86
|
|
87
|
+
if total.present?
|
88
|
+
numbers[:records] = total
|
89
|
+
end
|
90
|
+
|
85
91
|
numbers
|
86
92
|
end
|
87
93
|
|
@@ -89,16 +95,30 @@ module JSONAPI
|
|
89
95
|
#
|
90
96
|
# @return [Array] with the offset, limit and the current page number
|
91
97
|
def jsonapi_pagination_params
|
92
|
-
def_per_page = self.class.const_get(:JSONAPI_PAGE_SIZE).to_i
|
93
|
-
|
94
98
|
pagination = params[:page].try(:slice, :number, :size) || {}
|
95
|
-
per_page = pagination
|
96
|
-
per_page = def_per_page if per_page > def_per_page || per_page < 1
|
99
|
+
per_page = jsonapi_page_size(pagination)
|
97
100
|
num = [1, pagination[:number].to_f.to_i].max
|
98
101
|
|
99
102
|
[(num - 1) * per_page, per_page, num]
|
100
103
|
end
|
101
104
|
|
105
|
+
# Retrieves the default page size
|
106
|
+
#
|
107
|
+
# @param per_page_param [Hash] opts the paginations params
|
108
|
+
# @option opts [String] :number the page number requested
|
109
|
+
# @option opts [String] :size the page size requested
|
110
|
+
#
|
111
|
+
# @return [Integer]
|
112
|
+
def jsonapi_page_size(pagination_params)
|
113
|
+
per_page = pagination_params[:size].to_f.to_i
|
114
|
+
|
115
|
+
return self.class
|
116
|
+
.const_get(:JSONAPI_PAGE_SIZE)
|
117
|
+
.to_i if per_page < 1
|
118
|
+
|
119
|
+
per_page
|
120
|
+
end
|
121
|
+
|
102
122
|
# Fallback to Rack's parsed query string when Rails is not available
|
103
123
|
#
|
104
124
|
# @return [Hash]
|
data/lib/jsonapi/rails.rb
CHANGED
@@ -42,11 +42,12 @@ module JSONAPI
|
|
42
42
|
many = JSONAPI::Rails.is_collection?(resource, options[:is_collection])
|
43
43
|
resource = [resource] unless many
|
44
44
|
|
45
|
-
return JSONAPI::
|
46
|
-
.
|
45
|
+
return JSONAPI::Rails.serializer_to_json(
|
46
|
+
JSONAPI::ErrorSerializer.new(resource, options)
|
47
|
+
) unless resource.is_a?(ActiveModel::Errors)
|
47
48
|
|
48
49
|
errors = []
|
49
|
-
model = resource.instance_variable_get(
|
50
|
+
model = resource.instance_variable_get(:@base)
|
50
51
|
|
51
52
|
if respond_to?(:jsonapi_serializer_class, true)
|
52
53
|
model_serializer = jsonapi_serializer_class(model, false)
|
@@ -54,8 +55,18 @@ module JSONAPI
|
|
54
55
|
model_serializer = JSONAPI::Rails.serializer_class(model, false)
|
55
56
|
end
|
56
57
|
|
57
|
-
details =
|
58
|
-
|
58
|
+
details = {}
|
59
|
+
if ::Rails.gem_version >= Gem::Version.new('6.1')
|
60
|
+
resource.each do |error|
|
61
|
+
attr = error.attribute
|
62
|
+
details[attr] ||= []
|
63
|
+
details[attr] << error.detail.merge(message: error.message)
|
64
|
+
end
|
65
|
+
elsif resource.respond_to?(:details)
|
66
|
+
details = resource.details
|
67
|
+
else
|
68
|
+
details = resource.messages
|
69
|
+
end
|
59
70
|
|
60
71
|
details.each do |error_key, error_hashes|
|
61
72
|
error_hashes.each do |error_hash|
|
@@ -66,9 +77,11 @@ module JSONAPI
|
|
66
77
|
end
|
67
78
|
end
|
68
79
|
|
69
|
-
JSONAPI::
|
70
|
-
|
71
|
-
|
80
|
+
JSONAPI::Rails.serializer_to_json(
|
81
|
+
JSONAPI::ActiveModelErrorSerializer.new(
|
82
|
+
errors, params: { model: model, model_serializer: model_serializer }
|
83
|
+
)
|
84
|
+
)
|
72
85
|
end
|
73
86
|
end
|
74
87
|
|
@@ -100,21 +113,21 @@ module JSONAPI
|
|
100
113
|
serializer_class = JSONAPI::Rails.serializer_class(resource, many)
|
101
114
|
end
|
102
115
|
|
103
|
-
|
116
|
+
JSONAPI::Rails.serializer_to_json(
|
117
|
+
serializer_class.new(resource, options)
|
118
|
+
)
|
104
119
|
end
|
105
120
|
end
|
106
121
|
|
107
122
|
# Checks if an object is a collection
|
108
123
|
#
|
109
|
-
#
|
124
|
+
# Basically forwards it to a [JSONAPI::Serializer] as there's no public API
|
110
125
|
#
|
111
126
|
# @param resource [Object] to check
|
112
127
|
# @param force_is_collection [NilClass] flag to overwrite
|
113
128
|
# @return [TrueClass] upon success
|
114
129
|
def self.is_collection?(resource, force_is_collection = nil)
|
115
|
-
|
116
|
-
|
117
|
-
resource.respond_to?(:size) && !resource.respond_to?(:each_pair)
|
130
|
+
JSONAPI::ErrorSerializer.is_collection?(resource, force_is_collection)
|
118
131
|
end
|
119
132
|
|
120
133
|
# Resolves resource serializer class
|
@@ -126,5 +139,17 @@ module JSONAPI
|
|
126
139
|
|
127
140
|
"#{klass.name}Serializer".constantize
|
128
141
|
end
|
142
|
+
|
143
|
+
# Lazily returns the serializer JSON
|
144
|
+
#
|
145
|
+
# @param serializer [Object] to evaluate
|
146
|
+
# @return [String]
|
147
|
+
def self.serializer_to_json(serializer)
|
148
|
+
if serializer.respond_to?(:serialized_json)
|
149
|
+
serializer.serialized_json
|
150
|
+
else
|
151
|
+
serializer.serializable_hash.to_json
|
152
|
+
end
|
153
|
+
end
|
129
154
|
end
|
130
155
|
end
|
data/lib/jsonapi/version.rb
CHANGED
@@ -0,0 +1,87 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
RSpec.describe JSONAPI::Deserialization do
|
4
|
+
let(:jsonapi_deserialize) { UsersController.new.method(:jsonapi_deserialize) }
|
5
|
+
let(:document) do
|
6
|
+
{
|
7
|
+
data: {
|
8
|
+
id: 1,
|
9
|
+
type: 'note',
|
10
|
+
attributes: {
|
11
|
+
title: 'Title 1',
|
12
|
+
date: '2015-12-20'
|
13
|
+
},
|
14
|
+
relationships: {
|
15
|
+
author: {
|
16
|
+
data: {
|
17
|
+
type: 'user',
|
18
|
+
id: 2
|
19
|
+
}
|
20
|
+
},
|
21
|
+
second_author: {
|
22
|
+
data: nil
|
23
|
+
},
|
24
|
+
notes: {
|
25
|
+
data: [
|
26
|
+
{
|
27
|
+
type: 'note',
|
28
|
+
id: 3
|
29
|
+
},
|
30
|
+
{
|
31
|
+
type: 'note',
|
32
|
+
id: 4
|
33
|
+
}
|
34
|
+
]
|
35
|
+
}
|
36
|
+
}
|
37
|
+
}
|
38
|
+
}
|
39
|
+
end
|
40
|
+
|
41
|
+
describe '#jsonapi_deserialize' do
|
42
|
+
it do
|
43
|
+
expect(jsonapi_deserialize.call(document)).to eq(
|
44
|
+
'id' => 1,
|
45
|
+
'date' => '2015-12-20',
|
46
|
+
'title' => 'Title 1',
|
47
|
+
'author_id' => 2,
|
48
|
+
'second_author_id' => nil,
|
49
|
+
'note_ids' => [3, 4]
|
50
|
+
)
|
51
|
+
end
|
52
|
+
|
53
|
+
context 'with `only`' do
|
54
|
+
it do
|
55
|
+
expect(jsonapi_deserialize.call(document, only: :notes)).to eq(
|
56
|
+
'note_ids' => [3, 4]
|
57
|
+
)
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
context 'with `except`' do
|
62
|
+
it do
|
63
|
+
expect(
|
64
|
+
jsonapi_deserialize.call(document, except: [:date, :title])
|
65
|
+
).to eq(
|
66
|
+
'id' => 1,
|
67
|
+
'author_id' => 2,
|
68
|
+
'second_author_id' => nil,
|
69
|
+
'note_ids' => [3, 4]
|
70
|
+
)
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
context 'with `polymorphic`' do
|
75
|
+
it do
|
76
|
+
expect(
|
77
|
+
jsonapi_deserialize.call(
|
78
|
+
document, only: :author, polymorphic: :author
|
79
|
+
)
|
80
|
+
).to eq(
|
81
|
+
'author_id' => 2,
|
82
|
+
'author_type' => User.name
|
83
|
+
)
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
data/spec/dummy.rb
ADDED
@@ -0,0 +1,162 @@
|
|
1
|
+
require 'securerandom'
|
2
|
+
require 'rails/all'
|
3
|
+
require 'ransack'
|
4
|
+
require 'jsonapi'
|
5
|
+
|
6
|
+
Rails.logger = Logger.new(STDOUT)
|
7
|
+
Rails.logger.level = ENV['LOG_LEVEL'] || Logger::WARN
|
8
|
+
|
9
|
+
JSONAPI::Rails.install!
|
10
|
+
|
11
|
+
ActiveRecord::Base.logger = Rails.logger
|
12
|
+
ActiveRecord::Base.establish_connection(
|
13
|
+
ENV['DATABASE_URL'] || 'sqlite3::memory:'
|
14
|
+
)
|
15
|
+
|
16
|
+
ActiveRecord::Schema.define do
|
17
|
+
create_table :users, force: true do |t|
|
18
|
+
t.string :first_name
|
19
|
+
t.string :last_name
|
20
|
+
t.timestamps
|
21
|
+
end
|
22
|
+
|
23
|
+
create_table :notes, force: true do |t|
|
24
|
+
t.string :title
|
25
|
+
t.integer :user_id
|
26
|
+
t.integer :quantity
|
27
|
+
t.timestamps
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
class User < ActiveRecord::Base
|
32
|
+
has_many :notes
|
33
|
+
end
|
34
|
+
|
35
|
+
class Note < ActiveRecord::Base
|
36
|
+
validates_format_of :title, without: /BAD_TITLE/
|
37
|
+
validates_numericality_of :quantity, less_than: 100, if: :quantity?
|
38
|
+
belongs_to :user, required: true
|
39
|
+
end
|
40
|
+
|
41
|
+
class CustomNoteSerializer
|
42
|
+
include JSONAPI::Serializer
|
43
|
+
|
44
|
+
set_type :note
|
45
|
+
belongs_to :user
|
46
|
+
attributes(:title, :quantity, :created_at, :updated_at)
|
47
|
+
end
|
48
|
+
|
49
|
+
class UserSerializer
|
50
|
+
include JSONAPI::Serializer
|
51
|
+
|
52
|
+
has_many :notes, serializer: CustomNoteSerializer
|
53
|
+
attributes(:last_name, :created_at, :updated_at)
|
54
|
+
|
55
|
+
attribute :first_name do |object, params|
|
56
|
+
if params[:first_name_upcase]
|
57
|
+
object.first_name.upcase
|
58
|
+
else
|
59
|
+
object.first_name
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
class Dummy < Rails::Application
|
65
|
+
secrets.secret_key_base = '_'
|
66
|
+
config.hosts << 'www.example.com' if config.respond_to?(:hosts)
|
67
|
+
|
68
|
+
routes.draw do
|
69
|
+
scope defaults: { format: :jsonapi } do
|
70
|
+
resources :users, only: [:index]
|
71
|
+
resources :notes, only: [:update]
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
class UsersController < ActionController::Base
|
77
|
+
include JSONAPI::Fetching
|
78
|
+
include JSONAPI::Filtering
|
79
|
+
include JSONAPI::Pagination
|
80
|
+
include JSONAPI::Deserialization
|
81
|
+
|
82
|
+
def index
|
83
|
+
allowed_fields = [
|
84
|
+
:first_name, :last_name, :created_at,
|
85
|
+
:notes_created_at, :notes_quantity
|
86
|
+
]
|
87
|
+
options = { sort_with_expressions: true }
|
88
|
+
|
89
|
+
jsonapi_filter(User.all, allowed_fields, options) do |filtered|
|
90
|
+
result = filtered.result
|
91
|
+
|
92
|
+
if params[:sort].to_s.include?('notes_quantity')
|
93
|
+
render jsonapi: result.group('id').to_a
|
94
|
+
return
|
95
|
+
end
|
96
|
+
|
97
|
+
result = result.to_a if params[:as_list]
|
98
|
+
|
99
|
+
jsonapi_paginate(result) do |paginated|
|
100
|
+
render jsonapi: paginated
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
private
|
106
|
+
def jsonapi_meta(resources)
|
107
|
+
{
|
108
|
+
many: true,
|
109
|
+
pagination: jsonapi_pagination_meta(resources)
|
110
|
+
}
|
111
|
+
end
|
112
|
+
|
113
|
+
def jsonapi_serializer_params
|
114
|
+
{
|
115
|
+
first_name_upcase: params[:upcase]
|
116
|
+
}
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
120
|
+
class NotesController < ActionController::Base
|
121
|
+
include JSONAPI::Errors
|
122
|
+
include JSONAPI::Deserialization
|
123
|
+
|
124
|
+
def update
|
125
|
+
raise_error! if params[:id] == 'tada'
|
126
|
+
|
127
|
+
note = Note.find(params[:id])
|
128
|
+
|
129
|
+
if note.update(note_params)
|
130
|
+
render jsonapi: note
|
131
|
+
else
|
132
|
+
note.errors.add(:title, message: 'has typos') if note.errors.key?(:title)
|
133
|
+
|
134
|
+
render jsonapi_errors: note.errors, status: :unprocessable_entity
|
135
|
+
end
|
136
|
+
end
|
137
|
+
|
138
|
+
private
|
139
|
+
def render_jsonapi_internal_server_error(exception)
|
140
|
+
Rails.logger.error(exception)
|
141
|
+
super(exception)
|
142
|
+
end
|
143
|
+
|
144
|
+
def jsonapi_serializer_class(resource, is_collection)
|
145
|
+
JSONAPI::Rails.serializer_class(resource, is_collection)
|
146
|
+
rescue NameError
|
147
|
+
klass = resource.class
|
148
|
+
klass = resource.first.class if is_collection
|
149
|
+
"Custom#{klass.name}Serializer".constantize
|
150
|
+
end
|
151
|
+
|
152
|
+
def note_params
|
153
|
+
# Will trigger required attribute error handling
|
154
|
+
params.require(:data).require(:attributes).require(:title)
|
155
|
+
|
156
|
+
jsonapi_deserialize(params)
|
157
|
+
end
|
158
|
+
|
159
|
+
def jsonapi_meta(resources)
|
160
|
+
{ single: true }
|
161
|
+
end
|
162
|
+
end
|