jpie 0.3.1 → 0.4.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 +4 -4
- data/{.aiconfig → .cursorrules} +14 -2
- data/CHANGELOG.md +51 -0
- data/README.md +179 -844
- data/examples/basic_example.md +146 -0
- data/examples/including_related_resources.md +491 -0
- data/examples/resource_attribute_configuration.md +147 -0
- data/examples/resource_meta_configuration.md +244 -0
- data/examples/single_table_inheritance.md +160 -0
- data/lib/jpie/controller/crud_actions.rb +10 -0
- data/lib/jpie/controller/error_handling.rb +168 -17
- data/lib/jpie/controller/json_api_validation.rb +171 -0
- data/lib/jpie/controller.rb +2 -0
- data/lib/jpie/errors.rb +41 -0
- data/lib/jpie/generators/resource_generator.rb +86 -9
- data/lib/jpie/generators/templates/resource.rb.erb +20 -1
- data/lib/jpie/resource/attributable.rb +21 -2
- data/lib/jpie/resource.rb +26 -0
- data/lib/jpie/version.rb +1 -1
- metadata +9 -3
@@ -0,0 +1,147 @@
|
|
1
|
+
# Resource Attribute Configuration Example
|
2
|
+
|
3
|
+
This example demonstrates all the different ways to configure resource attributes in JPie, showcasing the various configuration patterns and customization techniques available for attributes.
|
4
|
+
|
5
|
+
## Setup
|
6
|
+
|
7
|
+
### 1. Model (`app/models/user.rb`)
|
8
|
+
```ruby
|
9
|
+
class User < ActiveRecord::Base
|
10
|
+
validates :first_name, presence: true
|
11
|
+
validates :last_name, presence: true
|
12
|
+
validates :email, presence: true, uniqueness: true
|
13
|
+
validates :username, presence: true, uniqueness: true
|
14
|
+
|
15
|
+
def active?
|
16
|
+
true # Simple boolean for demonstration
|
17
|
+
end
|
18
|
+
end
|
19
|
+
```
|
20
|
+
|
21
|
+
### 2. Resource with All Attribute Configuration Types (`app/resources/user_resource.rb`)
|
22
|
+
```ruby
|
23
|
+
class UserResource < JPie::Resource
|
24
|
+
# 1. Basic attributes - direct model attribute access
|
25
|
+
attributes :email, :first_name, :last_name
|
26
|
+
|
27
|
+
# 2. Attribute with custom attr mapping (maps to different model attribute)
|
28
|
+
attribute :display_name, attr: :username
|
29
|
+
|
30
|
+
# 3. Attribute with block override
|
31
|
+
attribute :status do
|
32
|
+
object.active? ? 'active' : 'inactive'
|
33
|
+
end
|
34
|
+
|
35
|
+
# 4. Attribute with custom method override
|
36
|
+
attribute :full_name
|
37
|
+
|
38
|
+
private
|
39
|
+
|
40
|
+
# Custom method for attribute override
|
41
|
+
def full_name
|
42
|
+
"#{object.first_name} #{object.last_name}".strip
|
43
|
+
end
|
44
|
+
end
|
45
|
+
```
|
46
|
+
|
47
|
+
### 3. Controller (`app/controllers/users_controller.rb`)
|
48
|
+
```ruby
|
49
|
+
class UsersController < ApplicationController
|
50
|
+
include JPie::Controller
|
51
|
+
end
|
52
|
+
```
|
53
|
+
|
54
|
+
## HTTP Examples
|
55
|
+
|
56
|
+
### Create User
|
57
|
+
```http
|
58
|
+
POST /users
|
59
|
+
Content-Type: application/vnd.api+json
|
60
|
+
|
61
|
+
{
|
62
|
+
"data": {
|
63
|
+
"type": "users",
|
64
|
+
"attributes": {
|
65
|
+
"email": "john.doe@example.com",
|
66
|
+
"first_name": "John",
|
67
|
+
"last_name": "Doe"
|
68
|
+
}
|
69
|
+
}
|
70
|
+
}
|
71
|
+
|
72
|
+
HTTP/1.1 201 Created
|
73
|
+
Content-Type: application/vnd.api+json
|
74
|
+
|
75
|
+
{
|
76
|
+
"data": {
|
77
|
+
"id": "1",
|
78
|
+
"type": "users",
|
79
|
+
"attributes": {
|
80
|
+
"email": "john.doe@example.com",
|
81
|
+
"first_name": "John",
|
82
|
+
"last_name": "Doe",
|
83
|
+
"display_name": "johndoe",
|
84
|
+
"status": "active",
|
85
|
+
"full_name": "John Doe"
|
86
|
+
}
|
87
|
+
}
|
88
|
+
}
|
89
|
+
```
|
90
|
+
|
91
|
+
### Update User
|
92
|
+
```http
|
93
|
+
PATCH /users/1
|
94
|
+
Content-Type: application/vnd.api+json
|
95
|
+
|
96
|
+
{
|
97
|
+
"data": {
|
98
|
+
"id": "1",
|
99
|
+
"type": "users",
|
100
|
+
"attributes": {
|
101
|
+
"first_name": "Jonathan"
|
102
|
+
}
|
103
|
+
}
|
104
|
+
}
|
105
|
+
|
106
|
+
HTTP/1.1 200 OK
|
107
|
+
Content-Type: application/vnd.api+json
|
108
|
+
|
109
|
+
{
|
110
|
+
"data": {
|
111
|
+
"id": "1",
|
112
|
+
"type": "users",
|
113
|
+
"attributes": {
|
114
|
+
"email": "john.doe@example.com",
|
115
|
+
"first_name": "Jonathan",
|
116
|
+
"last_name": "Doe",
|
117
|
+
"display_name": "johndoe",
|
118
|
+
"status": "active",
|
119
|
+
"full_name": "Jonathan Doe"
|
120
|
+
}
|
121
|
+
}
|
122
|
+
}
|
123
|
+
```
|
124
|
+
|
125
|
+
### Get User with All Attribute Configuration Types
|
126
|
+
```http
|
127
|
+
GET /users/1
|
128
|
+
Accept: application/vnd.api+json
|
129
|
+
|
130
|
+
HTTP/1.1 200 OK
|
131
|
+
Content-Type: application/vnd.api+json
|
132
|
+
|
133
|
+
{
|
134
|
+
"data": {
|
135
|
+
"id": "1",
|
136
|
+
"type": "users",
|
137
|
+
"attributes": {
|
138
|
+
"email": "john.doe@example.com",
|
139
|
+
"first_name": "John",
|
140
|
+
"last_name": "Doe",
|
141
|
+
"display_name": "johndoe",
|
142
|
+
"status": "active",
|
143
|
+
"full_name": "John Doe"
|
144
|
+
}
|
145
|
+
}
|
146
|
+
}
|
147
|
+
```
|
@@ -0,0 +1,244 @@
|
|
1
|
+
# Meta Field Configuration Example
|
2
|
+
|
3
|
+
This example demonstrates all the different ways to define and configure meta fields in JPie, focusing on the various configuration patterns and syntax options available.
|
4
|
+
|
5
|
+
## Setup
|
6
|
+
|
7
|
+
### 1. Article model
|
8
|
+
```ruby
|
9
|
+
class Article < ActiveRecord::Base
|
10
|
+
validates :title, presence: true
|
11
|
+
validates :content, presence: true
|
12
|
+
validates :status, inclusion: { in: %w[draft published archived] }
|
13
|
+
|
14
|
+
belongs_to :author, class_name: 'User'
|
15
|
+
|
16
|
+
def word_count
|
17
|
+
content.split.length
|
18
|
+
end
|
19
|
+
|
20
|
+
def reading_time_minutes
|
21
|
+
(word_count / 200.0).ceil
|
22
|
+
end
|
23
|
+
end
|
24
|
+
```
|
25
|
+
|
26
|
+
### 2. Resource with All Meta Field Configuration Types
|
27
|
+
```ruby
|
28
|
+
class ArticleResource < JPie::Resource
|
29
|
+
# 1. Basic meta attributes - direct model access and custom methods
|
30
|
+
meta_attributes :created_at, :updated_at
|
31
|
+
meta_attribute :reading_time
|
32
|
+
|
33
|
+
# 2. Meta attribute with attr mapping (maps to different model attribute)
|
34
|
+
meta_attribute :author_name, attr: :author_email
|
35
|
+
|
36
|
+
# 3. Meta attribute with block (legacy style)
|
37
|
+
meta_attribute :word_count do
|
38
|
+
object.word_count
|
39
|
+
end
|
40
|
+
|
41
|
+
# 4. Meta attribute with proc block (alternative legacy style)
|
42
|
+
meta_attribute :character_count, block: proc { object.content.length }
|
43
|
+
|
44
|
+
# 5. Short alias syntax (modern style)
|
45
|
+
meta :api_version
|
46
|
+
metas :request_id, :cache_key
|
47
|
+
|
48
|
+
# 6. Custom meta method for dynamic metadata
|
49
|
+
def meta
|
50
|
+
# Start with declared meta attributes
|
51
|
+
base_meta = super
|
52
|
+
|
53
|
+
# Add dynamic metadata
|
54
|
+
dynamic_meta = {
|
55
|
+
timestamp: Time.current.iso8601,
|
56
|
+
resource_version: '2.1'
|
57
|
+
}
|
58
|
+
|
59
|
+
# Conditional metadata based on context
|
60
|
+
if context[:include_debug]
|
61
|
+
dynamic_meta[:debug_info] = {
|
62
|
+
object_class: object.class.name,
|
63
|
+
context_keys: context.keys
|
64
|
+
}
|
65
|
+
end
|
66
|
+
|
67
|
+
# Merge and return
|
68
|
+
base_meta.merge(dynamic_meta)
|
69
|
+
end
|
70
|
+
|
71
|
+
private
|
72
|
+
|
73
|
+
# Custom method for reading_time meta attribute
|
74
|
+
def reading_time
|
75
|
+
{
|
76
|
+
minutes: object.reading_time_minutes,
|
77
|
+
formatted: "#{object.reading_time_minutes} min read"
|
78
|
+
}
|
79
|
+
end
|
80
|
+
|
81
|
+
# Meta attribute accessing context
|
82
|
+
def user_role
|
83
|
+
context[:current_user]&.role || 'anonymous'
|
84
|
+
end
|
85
|
+
|
86
|
+
# Meta attribute with conditional logic
|
87
|
+
def edit_permissions
|
88
|
+
current_user = context[:current_user]
|
89
|
+
return false unless current_user
|
90
|
+
|
91
|
+
current_user.admin? || current_user == object.author
|
92
|
+
end
|
93
|
+
|
94
|
+
# Meta attributes using short alias syntax
|
95
|
+
def api_version
|
96
|
+
'1.0'
|
97
|
+
end
|
98
|
+
|
99
|
+
def request_id
|
100
|
+
context[:request_id] || SecureRandom.uuid
|
101
|
+
end
|
102
|
+
|
103
|
+
def cache_key
|
104
|
+
"article:#{object.id}:#{object.updated_at.to_i}"
|
105
|
+
end
|
106
|
+
end
|
107
|
+
```
|
108
|
+
|
109
|
+
## HTTP Examples
|
110
|
+
|
111
|
+
### Create Article
|
112
|
+
```http
|
113
|
+
POST /articles
|
114
|
+
Content-Type: application/vnd.api+json
|
115
|
+
Authorization: Bearer user_token
|
116
|
+
|
117
|
+
{
|
118
|
+
"data": {
|
119
|
+
"type": "articles",
|
120
|
+
"attributes": {
|
121
|
+
"title": "Meta Field Configuration Guide",
|
122
|
+
"content": "This guide demonstrates all the different ways to configure meta fields in JPie...",
|
123
|
+
"status": "draft"
|
124
|
+
}
|
125
|
+
}
|
126
|
+
}
|
127
|
+
|
128
|
+
HTTP/1.1 201 Created
|
129
|
+
Content-Type: application/vnd.api+json
|
130
|
+
|
131
|
+
{
|
132
|
+
"data": {
|
133
|
+
"id": "1",
|
134
|
+
"type": "articles",
|
135
|
+
"attributes": {
|
136
|
+
"title": "Meta Field Configuration Guide",
|
137
|
+
"content": "This guide demonstrates all the different ways to configure meta fields in JPie...",
|
138
|
+
"status": "draft"
|
139
|
+
},
|
140
|
+
"meta": {
|
141
|
+
"created_at": "2024-01-15T10:30:00Z",
|
142
|
+
"updated_at": "2024-01-15T10:30:00Z",
|
143
|
+
"reading_time": {
|
144
|
+
"minutes": 3,
|
145
|
+
"formatted": "3 min read"
|
146
|
+
},
|
147
|
+
"author_name": "john@example.com",
|
148
|
+
"word_count": 450,
|
149
|
+
"character_count": 2700,
|
150
|
+
"api_version": "1.0",
|
151
|
+
"request_id": "req_abc123def456",
|
152
|
+
"cache_key": "article:1:1705492800",
|
153
|
+
"timestamp": "2024-03-15T16:45:30Z",
|
154
|
+
"resource_version": "2.1"
|
155
|
+
}
|
156
|
+
}
|
157
|
+
}
|
158
|
+
```
|
159
|
+
|
160
|
+
### Update Article
|
161
|
+
```http
|
162
|
+
PATCH /articles/1
|
163
|
+
Content-Type: application/vnd.api+json
|
164
|
+
Authorization: Bearer user_token
|
165
|
+
|
166
|
+
{
|
167
|
+
"data": {
|
168
|
+
"id": "1",
|
169
|
+
"type": "articles",
|
170
|
+
"attributes": {
|
171
|
+
"status": "published"
|
172
|
+
}
|
173
|
+
}
|
174
|
+
}
|
175
|
+
|
176
|
+
HTTP/1.1 200 OK
|
177
|
+
Content-Type: application/vnd.api+json
|
178
|
+
|
179
|
+
{
|
180
|
+
"data": {
|
181
|
+
"id": "1",
|
182
|
+
"type": "articles",
|
183
|
+
"attributes": {
|
184
|
+
"title": "Meta Field Configuration Guide",
|
185
|
+
"content": "This guide demonstrates all the different ways to configure meta fields in JPie...",
|
186
|
+
"status": "published"
|
187
|
+
},
|
188
|
+
"meta": {
|
189
|
+
"created_at": "2024-01-15T10:30:00Z",
|
190
|
+
"updated_at": "2024-01-16T14:20:00Z",
|
191
|
+
"reading_time": {
|
192
|
+
"minutes": 3,
|
193
|
+
"formatted": "3 min read"
|
194
|
+
},
|
195
|
+
"author_name": "john@example.com",
|
196
|
+
"word_count": 450,
|
197
|
+
"character_count": 2700,
|
198
|
+
"api_version": "1.0",
|
199
|
+
"request_id": "req_xyz789ghi012",
|
200
|
+
"cache_key": "article:1:1705492800",
|
201
|
+
"timestamp": "2024-03-16T14:20:00Z",
|
202
|
+
"resource_version": "2.1"
|
203
|
+
}
|
204
|
+
}
|
205
|
+
}
|
206
|
+
```
|
207
|
+
|
208
|
+
### Get Article with All Meta Field Configurations
|
209
|
+
```http
|
210
|
+
GET /articles/1
|
211
|
+
Accept: application/vnd.api+json
|
212
|
+
Authorization: Bearer user_token
|
213
|
+
|
214
|
+
HTTP/1.1 200 OK
|
215
|
+
Content-Type: application/vnd.api+json
|
216
|
+
|
217
|
+
{
|
218
|
+
"data": {
|
219
|
+
"id": "1",
|
220
|
+
"type": "articles",
|
221
|
+
"attributes": {
|
222
|
+
"title": "Meta Field Configuration Guide",
|
223
|
+
"content": "This guide demonstrates all the different ways to configure meta fields in JPie...",
|
224
|
+
"status": "published"
|
225
|
+
},
|
226
|
+
"meta": {
|
227
|
+
"created_at": "2024-01-15T10:30:00Z",
|
228
|
+
"updated_at": "2024-01-16T14:20:00Z",
|
229
|
+
"reading_time": {
|
230
|
+
"minutes": 3,
|
231
|
+
"formatted": "3 min read"
|
232
|
+
},
|
233
|
+
"author_name": "john@example.com",
|
234
|
+
"word_count": 450,
|
235
|
+
"character_count": 2700,
|
236
|
+
"api_version": "1.0",
|
237
|
+
"request_id": "req_abc123def456",
|
238
|
+
"cache_key": "article:1:1705492800",
|
239
|
+
"timestamp": "2024-03-16T14:20:00Z",
|
240
|
+
"resource_version": "2.1"
|
241
|
+
}
|
242
|
+
}
|
243
|
+
}
|
244
|
+
```
|
@@ -0,0 +1,160 @@
|
|
1
|
+
# Single Table Inheritance (STI) Example
|
2
|
+
|
3
|
+
This example demonstrates the minimal setup required to implement Single Table Inheritance with JPie resources and controllers.
|
4
|
+
|
5
|
+
## Setup
|
6
|
+
|
7
|
+
### 1. Base Model (`app/models/vehicle.rb`)
|
8
|
+
```ruby
|
9
|
+
class Vehicle < ApplicationRecord
|
10
|
+
validates :name, presence: true
|
11
|
+
validates :brand, presence: true
|
12
|
+
validates :year, presence: true
|
13
|
+
end
|
14
|
+
```
|
15
|
+
|
16
|
+
### 2. STI Models (`app/models/car.rb`, `app/models/truck.rb`)
|
17
|
+
```ruby
|
18
|
+
class Car < Vehicle
|
19
|
+
validates :engine_size, presence: true
|
20
|
+
end
|
21
|
+
|
22
|
+
class Truck < Vehicle
|
23
|
+
validates :cargo_capacity, presence: true
|
24
|
+
end
|
25
|
+
```
|
26
|
+
|
27
|
+
### 3. Base Resource (`app/resources/vehicle_resource.rb`)
|
28
|
+
```ruby
|
29
|
+
class VehicleResource < JPie::Resource
|
30
|
+
attributes :name, :brand, :year
|
31
|
+
end
|
32
|
+
```
|
33
|
+
|
34
|
+
### 4. STI Resources (`app/resources/car_resource.rb`, `app/resources/truck_resource.rb`)
|
35
|
+
```ruby
|
36
|
+
class CarResource < VehicleResource
|
37
|
+
attributes :engine_size
|
38
|
+
end
|
39
|
+
|
40
|
+
class TruckResource < VehicleResource
|
41
|
+
attributes :cargo_capacity
|
42
|
+
end
|
43
|
+
```
|
44
|
+
|
45
|
+
### 5. Controller (`app/controllers/vehicles_controller.rb`)
|
46
|
+
```ruby
|
47
|
+
class VehiclesController < ApplicationController
|
48
|
+
include JPie::Controller
|
49
|
+
end
|
50
|
+
```
|
51
|
+
|
52
|
+
### 6. Routes (`config/routes.rb`)
|
53
|
+
```ruby
|
54
|
+
Rails.application.routes.draw do
|
55
|
+
resources :vehicles
|
56
|
+
end
|
57
|
+
```
|
58
|
+
|
59
|
+
## HTTP Examples
|
60
|
+
|
61
|
+
### Create Car
|
62
|
+
```http
|
63
|
+
POST /vehicles
|
64
|
+
Content-Type: application/vnd.api+json
|
65
|
+
|
66
|
+
{
|
67
|
+
"data": {
|
68
|
+
"type": "cars",
|
69
|
+
"attributes": {
|
70
|
+
"name": "Civic",
|
71
|
+
"brand": "Honda",
|
72
|
+
"year": 2024,
|
73
|
+
"engine_size": 1500
|
74
|
+
}
|
75
|
+
}
|
76
|
+
}
|
77
|
+
|
78
|
+
HTTP/1.1 201 Created
|
79
|
+
Content-Type: application/vnd.api+json
|
80
|
+
|
81
|
+
{
|
82
|
+
"data": {
|
83
|
+
"id": "1",
|
84
|
+
"type": "cars",
|
85
|
+
"attributes": {
|
86
|
+
"name": "Civic",
|
87
|
+
"brand": "Honda",
|
88
|
+
"year": 2024,
|
89
|
+
"engine_size": 1500
|
90
|
+
}
|
91
|
+
}
|
92
|
+
}
|
93
|
+
```
|
94
|
+
|
95
|
+
### Update Car
|
96
|
+
```http
|
97
|
+
PATCH /vehicles/1
|
98
|
+
Content-Type: application/vnd.api+json
|
99
|
+
|
100
|
+
{
|
101
|
+
"data": {
|
102
|
+
"id": "1",
|
103
|
+
"type": "cars",
|
104
|
+
"attributes": {
|
105
|
+
"name": "Civic Hybrid",
|
106
|
+
"engine_size": 1800
|
107
|
+
}
|
108
|
+
}
|
109
|
+
}
|
110
|
+
|
111
|
+
HTTP/1.1 200 OK
|
112
|
+
Content-Type: application/vnd.api+json
|
113
|
+
|
114
|
+
{
|
115
|
+
"data": {
|
116
|
+
"id": "1",
|
117
|
+
"type": "cars",
|
118
|
+
"attributes": {
|
119
|
+
"name": "Civic Hybrid",
|
120
|
+
"brand": "Honda",
|
121
|
+
"year": 2024,
|
122
|
+
"engine_size": 1800
|
123
|
+
}
|
124
|
+
}
|
125
|
+
}
|
126
|
+
```
|
127
|
+
|
128
|
+
### Get Mixed Vehicles
|
129
|
+
```http
|
130
|
+
GET /vehicles
|
131
|
+
Accept: application/vnd.api+json
|
132
|
+
|
133
|
+
HTTP/1.1 200 OK
|
134
|
+
Content-Type: application/vnd.api+json
|
135
|
+
|
136
|
+
{
|
137
|
+
"data": [
|
138
|
+
{
|
139
|
+
"id": "1",
|
140
|
+
"type": "cars",
|
141
|
+
"attributes": {
|
142
|
+
"name": "Civic",
|
143
|
+
"brand": "Honda",
|
144
|
+
"year": 2024,
|
145
|
+
"engine_size": 1500
|
146
|
+
}
|
147
|
+
},
|
148
|
+
{
|
149
|
+
"id": "2",
|
150
|
+
"type": "trucks",
|
151
|
+
"attributes": {
|
152
|
+
"name": "F-150",
|
153
|
+
"brand": "Ford",
|
154
|
+
"year": 2024,
|
155
|
+
"cargo_capacity": 1000
|
156
|
+
}
|
157
|
+
}
|
158
|
+
]
|
159
|
+
}
|
160
|
+
```
|
@@ -34,6 +34,8 @@ module JPie
|
|
34
34
|
|
35
35
|
def define_index_method(resource_class)
|
36
36
|
define_method :index do
|
37
|
+
validate_include_params
|
38
|
+
validate_sort_params
|
37
39
|
resources = resource_class.scope(context)
|
38
40
|
sort_fields = parse_sort_params
|
39
41
|
resources = resource_class.sort(resources, sort_fields) if sort_fields.any?
|
@@ -43,6 +45,7 @@ module JPie
|
|
43
45
|
|
44
46
|
def define_show_method(resource_class)
|
45
47
|
define_method :show do
|
48
|
+
validate_include_params
|
46
49
|
resource = resource_class.scope(context).find(params[:id])
|
47
50
|
render_jsonapi(resource)
|
48
51
|
end
|
@@ -50,6 +53,7 @@ module JPie
|
|
50
53
|
|
51
54
|
def define_create_method(resource_class)
|
52
55
|
define_method :create do
|
56
|
+
validate_json_api_request
|
53
57
|
attributes = deserialize_params
|
54
58
|
resource = resource_class.model.create!(attributes)
|
55
59
|
render_jsonapi(resource, status: :created)
|
@@ -58,6 +62,7 @@ module JPie
|
|
58
62
|
|
59
63
|
def define_update_method(resource_class)
|
60
64
|
define_method :update do
|
65
|
+
validate_json_api_request
|
61
66
|
resource = resource_class.scope(context).find(params[:id])
|
62
67
|
attributes = deserialize_params
|
63
68
|
resource.update!(attributes)
|
@@ -76,6 +81,8 @@ module JPie
|
|
76
81
|
|
77
82
|
# These methods can still be called manually or used to override defaults
|
78
83
|
def index
|
84
|
+
validate_include_params
|
85
|
+
validate_sort_params
|
79
86
|
resources = resource_class.scope(context)
|
80
87
|
sort_fields = parse_sort_params
|
81
88
|
resources = resource_class.sort(resources, sort_fields) if sort_fields.any?
|
@@ -83,17 +90,20 @@ module JPie
|
|
83
90
|
end
|
84
91
|
|
85
92
|
def show
|
93
|
+
validate_include_params
|
86
94
|
resource = resource_class.scope(context).find(params[:id])
|
87
95
|
render_jsonapi(resource)
|
88
96
|
end
|
89
97
|
|
90
98
|
def create
|
99
|
+
validate_json_api_request
|
91
100
|
attributes = deserialize_params
|
92
101
|
resource = model_class.create!(attributes)
|
93
102
|
render_jsonapi(resource, status: :created)
|
94
103
|
end
|
95
104
|
|
96
105
|
def update
|
106
|
+
validate_json_api_request
|
97
107
|
resource = resource_class.scope(context).find(params[:id])
|
98
108
|
attributes = deserialize_params
|
99
109
|
resource.update!(attributes)
|