jpie 0.4.5 → 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.
- checksums.yaml +4 -4
- data/.gitignore +21 -0
- data/.rspec +3 -0
- data/.rubocop.yml +35 -110
- data/.travis.yml +7 -0
- data/Gemfile +21 -0
- data/Gemfile.lock +312 -0
- data/README.md +2072 -140
- data/Rakefile +3 -14
- data/bin/console +15 -0
- data/bin/setup +8 -0
- data/jpie.gemspec +18 -35
- data/kiln/app/resources/user_message_resource.rb +2 -0
- data/lib/jpie.rb +3 -24
- data/lib/json_api/active_storage/deserialization.rb +106 -0
- data/lib/json_api/active_storage/detection.rb +74 -0
- data/lib/json_api/active_storage/serialization.rb +32 -0
- data/lib/json_api/configuration.rb +58 -0
- data/lib/json_api/controllers/base_controller.rb +26 -0
- data/lib/json_api/controllers/concerns/controller_helpers.rb +223 -0
- data/lib/json_api/controllers/concerns/resource_actions.rb +657 -0
- data/lib/json_api/controllers/relationships_controller.rb +504 -0
- data/lib/json_api/controllers/resources_controller.rb +6 -0
- data/lib/json_api/errors/parameter_not_allowed.rb +19 -0
- data/lib/json_api/railtie.rb +75 -0
- data/lib/json_api/resources/active_storage_blob_resource.rb +11 -0
- data/lib/json_api/resources/resource.rb +238 -0
- data/lib/json_api/resources/resource_loader.rb +35 -0
- data/lib/json_api/routing.rb +72 -0
- data/lib/json_api/serialization/deserializer.rb +362 -0
- data/lib/json_api/serialization/serializer.rb +320 -0
- data/lib/json_api/support/active_storage_support.rb +85 -0
- data/lib/json_api/support/collection_query.rb +406 -0
- data/lib/json_api/support/instrumentation.rb +42 -0
- data/lib/json_api/support/param_helpers.rb +51 -0
- data/lib/json_api/support/relationship_guard.rb +16 -0
- data/lib/json_api/support/relationship_helpers.rb +74 -0
- data/lib/json_api/support/resource_identifier.rb +87 -0
- data/lib/json_api/support/responders.rb +100 -0
- data/lib/json_api/support/response_helpers.rb +10 -0
- data/lib/json_api/support/sort_parsing.rb +21 -0
- data/lib/json_api/support/type_conversion.rb +21 -0
- data/lib/json_api/testing/test_helper.rb +76 -0
- data/lib/json_api/testing.rb +3 -0
- data/lib/{jpie → json_api}/version.rb +2 -2
- data/lib/json_api.rb +50 -0
- data/lib/rubocop/cop/custom/hash_value_omission.rb +53 -0
- metadata +50 -169
- data/.cursor/rules/dependencies.mdc +0 -19
- data/.cursor/rules/examples.mdc +0 -16
- data/.cursor/rules/git.mdc +0 -14
- data/.cursor/rules/project_structure.mdc +0 -30
- data/.cursor/rules/publish_gem.mdc +0 -73
- data/.cursor/rules/security.mdc +0 -14
- data/.cursor/rules/style.mdc +0 -15
- data/.cursor/rules/testing.mdc +0 -16
- data/.overcommit.yml +0 -35
- data/CHANGELOG.md +0 -164
- data/LICENSE.txt +0 -21
- data/PUBLISHING.md +0 -111
- data/examples/basic_example.md +0 -146
- data/examples/including_related_resources.md +0 -491
- data/examples/pagination.md +0 -303
- data/examples/relationships.md +0 -114
- data/examples/resource_attribute_configuration.md +0 -147
- data/examples/resource_meta_configuration.md +0 -244
- data/examples/rspec_testing.md +0 -130
- data/examples/single_table_inheritance.md +0 -160
- data/lib/jpie/configuration.rb +0 -12
- data/lib/jpie/controller/crud_actions.rb +0 -141
- data/lib/jpie/controller/error_handling/handler_setup.rb +0 -124
- data/lib/jpie/controller/error_handling/handlers.rb +0 -109
- data/lib/jpie/controller/error_handling.rb +0 -23
- data/lib/jpie/controller/json_api_validation.rb +0 -193
- data/lib/jpie/controller/parameter_parsing.rb +0 -78
- data/lib/jpie/controller/related_actions.rb +0 -45
- data/lib/jpie/controller/relationship_actions.rb +0 -291
- data/lib/jpie/controller/relationship_validation.rb +0 -117
- data/lib/jpie/controller/rendering.rb +0 -154
- data/lib/jpie/controller.rb +0 -45
- data/lib/jpie/deserializer.rb +0 -110
- data/lib/jpie/errors.rb +0 -117
- data/lib/jpie/generators/resource_generator.rb +0 -116
- data/lib/jpie/generators/templates/resource.rb.erb +0 -31
- data/lib/jpie/railtie.rb +0 -42
- data/lib/jpie/resource/attributable.rb +0 -112
- data/lib/jpie/resource/inferrable.rb +0 -43
- data/lib/jpie/resource/sortable.rb +0 -93
- data/lib/jpie/resource.rb +0 -147
- data/lib/jpie/routing.rb +0 -59
- data/lib/jpie/serializer.rb +0 -205
|
@@ -1,244 +0,0 @@
|
|
|
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
|
-
```
|
data/examples/rspec_testing.md
DELETED
|
@@ -1,130 +0,0 @@
|
|
|
1
|
-
# Testing JPie Resources with RSpec
|
|
2
|
-
|
|
3
|
-
This guide demonstrates how to use JPie's RSpec matchers and helpers to test your JSON:API resources.
|
|
4
|
-
|
|
5
|
-
## Setup
|
|
6
|
-
|
|
7
|
-
Add to your `spec/rails_helper.rb` or `spec/spec_helper.rb`:
|
|
8
|
-
|
|
9
|
-
```ruby
|
|
10
|
-
require 'jpie/rspec'
|
|
11
|
-
JPie::RSpec.configure!
|
|
12
|
-
```
|
|
13
|
-
|
|
14
|
-
## Example Usage
|
|
15
|
-
|
|
16
|
-
Given a basic resource setup:
|
|
17
|
-
|
|
18
|
-
```ruby
|
|
19
|
-
# app/models/book.rb
|
|
20
|
-
class Book < ApplicationRecord
|
|
21
|
-
belongs_to :author
|
|
22
|
-
has_many :reviews
|
|
23
|
-
|
|
24
|
-
def reading_time_minutes
|
|
25
|
-
(content.split.length / 200.0).ceil
|
|
26
|
-
end
|
|
27
|
-
end
|
|
28
|
-
|
|
29
|
-
# app/resources/book_resource.rb
|
|
30
|
-
class BookResource < JPie::Resource
|
|
31
|
-
type :books
|
|
32
|
-
|
|
33
|
-
attribute :title
|
|
34
|
-
meta_attribute :reading_time
|
|
35
|
-
relationship :author
|
|
36
|
-
relationship :reviews
|
|
37
|
-
|
|
38
|
-
def reading_time
|
|
39
|
-
{ minutes: object.reading_time_minutes }
|
|
40
|
-
end
|
|
41
|
-
end
|
|
42
|
-
```
|
|
43
|
-
|
|
44
|
-
Here's how to test it:
|
|
45
|
-
|
|
46
|
-
```ruby
|
|
47
|
-
# spec/resources/book_resource_spec.rb
|
|
48
|
-
RSpec.describe BookResource, type: :resource do
|
|
49
|
-
let(:author) { create(:author) }
|
|
50
|
-
let(:book) { create(:book, author: author) }
|
|
51
|
-
let(:resource) { described_class.new(model: book) }
|
|
52
|
-
|
|
53
|
-
# Test resource structure
|
|
54
|
-
it { is_expected.to have_type(:books) }
|
|
55
|
-
it { is_expected.to have_attribute(:title) }
|
|
56
|
-
it { is_expected.to have_meta_attribute(:reading_time) }
|
|
57
|
-
it { is_expected.to have_relationship(:author) }
|
|
58
|
-
it { is_expected.to have_relationship(:reviews) }
|
|
59
|
-
|
|
60
|
-
# Test meta values
|
|
61
|
-
it 'has correct reading time' do
|
|
62
|
-
expect(resource).to have_meta_value(:reading_time).including(
|
|
63
|
-
minutes: book.reading_time_minutes
|
|
64
|
-
)
|
|
65
|
-
end
|
|
66
|
-
|
|
67
|
-
# Test relationship linkage
|
|
68
|
-
it 'has correct author linkage' do
|
|
69
|
-
expect(resource).to have_relationship_linkage(:author).with_id(author.id.to_s)
|
|
70
|
-
end
|
|
71
|
-
end
|
|
72
|
-
|
|
73
|
-
# spec/requests/books_controller_spec.rb
|
|
74
|
-
RSpec.describe BooksController, type: :request do
|
|
75
|
-
let!(:books) { create_list(:book, 10) }
|
|
76
|
-
|
|
77
|
-
describe 'GET /books' do
|
|
78
|
-
it 'handles pagination and includes' do
|
|
79
|
-
get '/books', params: {
|
|
80
|
-
page: 1,
|
|
81
|
-
per_page: 5,
|
|
82
|
-
include: 'author,reviews'
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
# Test pagination
|
|
86
|
-
expect(response).to be_paginated
|
|
87
|
-
expect(response).to have_page_size(5)
|
|
88
|
-
expect(response).to have_pagination_links.including(:first, :last, :next)
|
|
89
|
-
|
|
90
|
-
# Test includes
|
|
91
|
-
expect(response).to include_related(:author)
|
|
92
|
-
expect(response).to include_related(:reviews)
|
|
93
|
-
end
|
|
94
|
-
end
|
|
95
|
-
end
|
|
96
|
-
```
|
|
97
|
-
|
|
98
|
-
## Helper Methods
|
|
99
|
-
|
|
100
|
-
```ruby
|
|
101
|
-
# Build without saving
|
|
102
|
-
book = build_jpie_resource(:books, { title: 'Test Book' })
|
|
103
|
-
|
|
104
|
-
# Create with relationships
|
|
105
|
-
author = create_jpie_resource(:authors, { name: 'Author' })
|
|
106
|
-
book = create_jpie_resource(:books, { title: 'Test Book' }, { author: author })
|
|
107
|
-
|
|
108
|
-
# Clean up
|
|
109
|
-
cleanup_jpie_resources([book, author])
|
|
110
|
-
```
|
|
111
|
-
|
|
112
|
-
## Best Practices
|
|
113
|
-
|
|
114
|
-
1. Always clean up your test resources using `cleanup_jpie_resources`
|
|
115
|
-
2. Test both the presence of attributes/relationships and their values
|
|
116
|
-
3. Group your tests logically by resource features (attributes, relationships, meta)
|
|
117
|
-
4. Test pagination with different page sizes and page numbers
|
|
118
|
-
5. Test relationship includes with various combinations
|
|
119
|
-
6. Test meta fields with both simple and complex values
|
|
120
|
-
7. Use factories (like FactoryBot) to create test data
|
|
121
|
-
8. Test edge cases and validations specific to your resource configuration
|
|
122
|
-
|
|
123
|
-
## Common Gotchas
|
|
124
|
-
|
|
125
|
-
- Remember that `have_attribute` and `have_relationship` check both the presence of the method and the attribute/relationship in the resource's configuration
|
|
126
|
-
- The cleanup helper will only destroy persisted resources
|
|
127
|
-
- When testing relationships, make sure to test both the relationship configuration and the actual related resources
|
|
128
|
-
- Meta field values should match exactly, including nested structures
|
|
129
|
-
- Pagination tests should verify both the metadata and the actual number of records returned
|
|
130
|
-
- When testing includes, verify both the presence of the included data and its structure
|
|
@@ -1,160 +0,0 @@
|
|
|
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
|
-
```
|
data/lib/jpie/configuration.rb
DELETED
|
@@ -1,141 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
module JPie
|
|
4
|
-
module Controller
|
|
5
|
-
module CrudActions
|
|
6
|
-
extend ActiveSupport::Concern
|
|
7
|
-
|
|
8
|
-
class_methods do
|
|
9
|
-
def jsonapi_resource(resource_class)
|
|
10
|
-
setup_jsonapi_resource(resource_class)
|
|
11
|
-
end
|
|
12
|
-
|
|
13
|
-
# More concise alias for modern Rails style
|
|
14
|
-
alias_method :resource, :jsonapi_resource
|
|
15
|
-
|
|
16
|
-
private
|
|
17
|
-
|
|
18
|
-
def setup_jsonapi_resource(resource_class)
|
|
19
|
-
define_method :resource_class do
|
|
20
|
-
resource_class
|
|
21
|
-
end
|
|
22
|
-
|
|
23
|
-
# Define automatic CRUD methods
|
|
24
|
-
define_automatic_crud_methods(resource_class)
|
|
25
|
-
end
|
|
26
|
-
|
|
27
|
-
def define_automatic_crud_methods(resource_class)
|
|
28
|
-
define_index_method(resource_class)
|
|
29
|
-
define_show_method(resource_class)
|
|
30
|
-
define_create_method(resource_class)
|
|
31
|
-
define_update_method(resource_class)
|
|
32
|
-
define_destroy_method(resource_class)
|
|
33
|
-
end
|
|
34
|
-
|
|
35
|
-
def define_index_method(resource_class)
|
|
36
|
-
define_method :index do
|
|
37
|
-
validate_include_params
|
|
38
|
-
validate_sort_params
|
|
39
|
-
resources = resource_class.scope(context)
|
|
40
|
-
sort_fields = parse_sort_params
|
|
41
|
-
resources = resource_class.sort(resources, sort_fields) if sort_fields.any?
|
|
42
|
-
|
|
43
|
-
pagination_params = parse_pagination_params
|
|
44
|
-
original_resources = resources
|
|
45
|
-
resources = apply_pagination(resources, pagination_params)
|
|
46
|
-
|
|
47
|
-
render_jsonapi(resources, pagination: pagination_params, original_scope: original_resources)
|
|
48
|
-
end
|
|
49
|
-
end
|
|
50
|
-
|
|
51
|
-
def define_show_method(resource_class)
|
|
52
|
-
define_method :show do
|
|
53
|
-
validate_include_params
|
|
54
|
-
resource = resource_class.scope(context).find(params[:id])
|
|
55
|
-
render_jsonapi(resource)
|
|
56
|
-
end
|
|
57
|
-
end
|
|
58
|
-
|
|
59
|
-
def define_create_method(resource_class)
|
|
60
|
-
define_method :create do
|
|
61
|
-
validate_json_api_request
|
|
62
|
-
attributes = deserialize_params
|
|
63
|
-
resource = resource_class.model.create!(attributes)
|
|
64
|
-
render_jsonapi(resource, status: :created)
|
|
65
|
-
end
|
|
66
|
-
end
|
|
67
|
-
|
|
68
|
-
def define_update_method(resource_class)
|
|
69
|
-
define_method :update do
|
|
70
|
-
validate_json_api_request
|
|
71
|
-
resource = resource_class.scope(context).find(params[:id])
|
|
72
|
-
attributes = deserialize_params
|
|
73
|
-
resource.update!(attributes)
|
|
74
|
-
render_jsonapi(resource)
|
|
75
|
-
end
|
|
76
|
-
end
|
|
77
|
-
|
|
78
|
-
def define_destroy_method(resource_class)
|
|
79
|
-
define_method :destroy do
|
|
80
|
-
resource = resource_class.scope(context).find(params[:id])
|
|
81
|
-
resource.destroy!
|
|
82
|
-
head :no_content
|
|
83
|
-
end
|
|
84
|
-
end
|
|
85
|
-
end
|
|
86
|
-
|
|
87
|
-
# These methods can still be called manually or used to override defaults
|
|
88
|
-
def index
|
|
89
|
-
validate_include_params
|
|
90
|
-
validate_sort_params
|
|
91
|
-
resources = resource_class.scope(context)
|
|
92
|
-
sort_fields = parse_sort_params
|
|
93
|
-
resources = resource_class.sort(resources, sort_fields) if sort_fields.any?
|
|
94
|
-
|
|
95
|
-
pagination_params = parse_pagination_params
|
|
96
|
-
original_resources = resources
|
|
97
|
-
resources = apply_pagination(resources, pagination_params)
|
|
98
|
-
|
|
99
|
-
render_jsonapi(resources, pagination: pagination_params, original_scope: original_resources)
|
|
100
|
-
end
|
|
101
|
-
|
|
102
|
-
def show
|
|
103
|
-
validate_include_params
|
|
104
|
-
resource = resource_class.scope(context).find(params[:id])
|
|
105
|
-
render_jsonapi(resource)
|
|
106
|
-
end
|
|
107
|
-
|
|
108
|
-
def create
|
|
109
|
-
validate_json_api_request
|
|
110
|
-
attributes = deserialize_params
|
|
111
|
-
resource = model_class.create!(attributes)
|
|
112
|
-
render_jsonapi(resource, status: :created)
|
|
113
|
-
end
|
|
114
|
-
|
|
115
|
-
def update
|
|
116
|
-
validate_json_api_request
|
|
117
|
-
resource = resource_class.scope(context).find(params[:id])
|
|
118
|
-
attributes = deserialize_params
|
|
119
|
-
resource.update!(attributes)
|
|
120
|
-
render_jsonapi(resource)
|
|
121
|
-
end
|
|
122
|
-
|
|
123
|
-
def destroy
|
|
124
|
-
resource = resource_class.scope(context).find(params[:id])
|
|
125
|
-
resource.destroy!
|
|
126
|
-
head :no_content
|
|
127
|
-
end
|
|
128
|
-
|
|
129
|
-
private
|
|
130
|
-
|
|
131
|
-
def apply_pagination(resources, pagination_params)
|
|
132
|
-
return resources unless pagination_params[:per_page]
|
|
133
|
-
|
|
134
|
-
page = pagination_params[:page] || 1
|
|
135
|
-
per_page = pagination_params[:per_page]
|
|
136
|
-
|
|
137
|
-
resources.limit(per_page).offset((page - 1) * per_page)
|
|
138
|
-
end
|
|
139
|
-
end
|
|
140
|
-
end
|
|
141
|
-
end
|