jpie 0.4.5 → 1.0.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.
Files changed (141) hide show
  1. checksums.yaml +4 -4
  2. data/.cursor/rules/release.mdc +62 -0
  3. data/.gitignore +26 -0
  4. data/.rspec +3 -0
  5. data/.rubocop.yml +76 -107
  6. data/.travis.yml +7 -0
  7. data/Gemfile +23 -0
  8. data/Gemfile.lock +321 -0
  9. data/README.md +1508 -136
  10. data/Rakefile +3 -14
  11. data/bin/console +15 -0
  12. data/bin/setup +8 -0
  13. data/jpie.gemspec +21 -38
  14. data/kiln/app/resources/user_message_resource.rb +4 -0
  15. data/lib/jpie.rb +3 -25
  16. data/lib/json_api/active_storage/deserialization.rb +116 -0
  17. data/lib/json_api/active_storage/detection.rb +69 -0
  18. data/lib/json_api/active_storage/serialization.rb +34 -0
  19. data/lib/json_api/configuration.rb +57 -0
  20. data/lib/json_api/controllers/base_controller.rb +26 -0
  21. data/lib/json_api/controllers/concerns/controller_helpers/authorization.rb +30 -0
  22. data/lib/json_api/controllers/concerns/controller_helpers/document_meta.rb +20 -0
  23. data/lib/json_api/controllers/concerns/controller_helpers/error_rendering.rb +64 -0
  24. data/lib/json_api/controllers/concerns/controller_helpers/parsing.rb +127 -0
  25. data/lib/json_api/controllers/concerns/controller_helpers/resource_setup.rb +38 -0
  26. data/lib/json_api/controllers/concerns/controller_helpers.rb +19 -0
  27. data/lib/json_api/controllers/concerns/relationships/active_storage_removal.rb +65 -0
  28. data/lib/json_api/controllers/concerns/relationships/events.rb +44 -0
  29. data/lib/json_api/controllers/concerns/relationships/removal.rb +92 -0
  30. data/lib/json_api/controllers/concerns/relationships/response_helpers.rb +55 -0
  31. data/lib/json_api/controllers/concerns/relationships/serialization.rb +72 -0
  32. data/lib/json_api/controllers/concerns/relationships/sorting.rb +114 -0
  33. data/lib/json_api/controllers/concerns/relationships/updating.rb +73 -0
  34. data/lib/json_api/controllers/concerns/relationships_controller/active_storage_removal.rb +67 -0
  35. data/lib/json_api/controllers/concerns/relationships_controller/events.rb +44 -0
  36. data/lib/json_api/controllers/concerns/relationships_controller/removal.rb +92 -0
  37. data/lib/json_api/controllers/concerns/relationships_controller/response_helpers.rb +55 -0
  38. data/lib/json_api/controllers/concerns/relationships_controller/serialization.rb +72 -0
  39. data/lib/json_api/controllers/concerns/relationships_controller/sorting.rb +114 -0
  40. data/lib/json_api/controllers/concerns/relationships_controller/updating.rb +73 -0
  41. data/lib/json_api/controllers/concerns/resource_actions/crud_helpers.rb +93 -0
  42. data/lib/json_api/controllers/concerns/resource_actions/field_validation.rb +114 -0
  43. data/lib/json_api/controllers/concerns/resource_actions/filter_validation.rb +91 -0
  44. data/lib/json_api/controllers/concerns/resource_actions/pagination.rb +51 -0
  45. data/lib/json_api/controllers/concerns/resource_actions/preloading.rb +64 -0
  46. data/lib/json_api/controllers/concerns/resource_actions/resource_loading.rb +71 -0
  47. data/lib/json_api/controllers/concerns/resource_actions/serialization.rb +63 -0
  48. data/lib/json_api/controllers/concerns/resource_actions/type_validation.rb +75 -0
  49. data/lib/json_api/controllers/concerns/resource_actions.rb +106 -0
  50. data/lib/json_api/controllers/relationships_controller.rb +108 -0
  51. data/lib/json_api/controllers/resources_controller.rb +6 -0
  52. data/lib/json_api/errors/parameter_not_allowed.rb +19 -0
  53. data/lib/json_api/railtie.rb +112 -0
  54. data/lib/json_api/resources/active_storage_blob_resource.rb +19 -0
  55. data/lib/json_api/resources/concerns/attributes_dsl.rb +69 -0
  56. data/lib/json_api/resources/concerns/filters_dsl.rb +32 -0
  57. data/lib/json_api/resources/concerns/meta_dsl.rb +23 -0
  58. data/lib/json_api/resources/concerns/model_class_helpers.rb +37 -0
  59. data/lib/json_api/resources/concerns/relationships_dsl.rb +71 -0
  60. data/lib/json_api/resources/concerns/sortable_fields_dsl.rb +36 -0
  61. data/lib/json_api/resources/resource.rb +32 -0
  62. data/lib/json_api/resources/resource_loader.rb +35 -0
  63. data/lib/json_api/routing.rb +81 -0
  64. data/lib/json_api/serialization/concerns/attributes_deserialization.rb +27 -0
  65. data/lib/json_api/serialization/concerns/attributes_serialization.rb +50 -0
  66. data/lib/json_api/serialization/concerns/deserialization_helpers.rb +115 -0
  67. data/lib/json_api/serialization/concerns/includes_serialization.rb +82 -0
  68. data/lib/json_api/serialization/concerns/links_serialization.rb +33 -0
  69. data/lib/json_api/serialization/concerns/meta_serialization.rb +60 -0
  70. data/lib/json_api/serialization/concerns/model_attributes_transformation.rb +69 -0
  71. data/lib/json_api/serialization/concerns/relationship_processing.rb +119 -0
  72. data/lib/json_api/serialization/concerns/relationships_deserialization.rb +47 -0
  73. data/lib/json_api/serialization/concerns/relationships_serialization.rb +81 -0
  74. data/lib/json_api/serialization/deserializer.rb +26 -0
  75. data/lib/json_api/serialization/serializer.rb +77 -0
  76. data/lib/json_api/support/active_storage_support.rb +82 -0
  77. data/lib/json_api/support/collection_query.rb +50 -0
  78. data/lib/json_api/support/concerns/condition_building.rb +57 -0
  79. data/lib/json_api/support/concerns/nested_filters.rb +130 -0
  80. data/lib/json_api/support/concerns/pagination.rb +30 -0
  81. data/lib/json_api/support/concerns/polymorphic_filters.rb +75 -0
  82. data/lib/json_api/support/concerns/regular_filters.rb +81 -0
  83. data/lib/json_api/support/concerns/sorting.rb +88 -0
  84. data/lib/json_api/support/instrumentation.rb +43 -0
  85. data/lib/json_api/support/param_helpers.rb +54 -0
  86. data/lib/json_api/support/relationship_guard.rb +16 -0
  87. data/lib/json_api/support/relationship_helpers.rb +76 -0
  88. data/lib/json_api/support/resource_identifier.rb +87 -0
  89. data/lib/json_api/support/responders.rb +100 -0
  90. data/lib/json_api/support/response_helpers.rb +10 -0
  91. data/lib/json_api/support/sort_parsing.rb +21 -0
  92. data/lib/json_api/support/type_conversion.rb +21 -0
  93. data/lib/json_api/testing/test_helper.rb +76 -0
  94. data/lib/json_api/testing.rb +3 -0
  95. data/lib/{jpie → json_api}/version.rb +2 -2
  96. data/lib/json_api.rb +50 -0
  97. data/lib/rubocop/cop/custom/hash_value_omission.rb +53 -0
  98. metadata +100 -169
  99. data/.cursor/rules/dependencies.mdc +0 -19
  100. data/.cursor/rules/examples.mdc +0 -16
  101. data/.cursor/rules/git.mdc +0 -14
  102. data/.cursor/rules/project_structure.mdc +0 -30
  103. data/.cursor/rules/publish_gem.mdc +0 -73
  104. data/.cursor/rules/security.mdc +0 -14
  105. data/.cursor/rules/style.mdc +0 -15
  106. data/.cursor/rules/testing.mdc +0 -16
  107. data/.overcommit.yml +0 -35
  108. data/CHANGELOG.md +0 -164
  109. data/LICENSE.txt +0 -21
  110. data/PUBLISHING.md +0 -111
  111. data/examples/basic_example.md +0 -146
  112. data/examples/including_related_resources.md +0 -491
  113. data/examples/pagination.md +0 -303
  114. data/examples/relationships.md +0 -114
  115. data/examples/resource_attribute_configuration.md +0 -147
  116. data/examples/resource_meta_configuration.md +0 -244
  117. data/examples/rspec_testing.md +0 -130
  118. data/examples/single_table_inheritance.md +0 -160
  119. data/lib/jpie/configuration.rb +0 -12
  120. data/lib/jpie/controller/crud_actions.rb +0 -141
  121. data/lib/jpie/controller/error_handling/handler_setup.rb +0 -124
  122. data/lib/jpie/controller/error_handling/handlers.rb +0 -109
  123. data/lib/jpie/controller/error_handling.rb +0 -23
  124. data/lib/jpie/controller/json_api_validation.rb +0 -193
  125. data/lib/jpie/controller/parameter_parsing.rb +0 -78
  126. data/lib/jpie/controller/related_actions.rb +0 -45
  127. data/lib/jpie/controller/relationship_actions.rb +0 -291
  128. data/lib/jpie/controller/relationship_validation.rb +0 -117
  129. data/lib/jpie/controller/rendering.rb +0 -154
  130. data/lib/jpie/controller.rb +0 -45
  131. data/lib/jpie/deserializer.rb +0 -110
  132. data/lib/jpie/errors.rb +0 -117
  133. data/lib/jpie/generators/resource_generator.rb +0 -116
  134. data/lib/jpie/generators/templates/resource.rb.erb +0 -31
  135. data/lib/jpie/railtie.rb +0 -42
  136. data/lib/jpie/resource/attributable.rb +0 -112
  137. data/lib/jpie/resource/inferrable.rb +0 -43
  138. data/lib/jpie/resource/sortable.rb +0 -93
  139. data/lib/jpie/resource.rb +0 -147
  140. data/lib/jpie/routing.rb +0 -59
  141. 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
- ```
@@ -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
- ```
@@ -1,12 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module JPie
4
- class Configuration
5
- attr_accessor :default_page_size, :maximum_page_size
6
-
7
- def initialize
8
- @default_page_size = 20
9
- @maximum_page_size = 100
10
- end
11
- end
12
- end
@@ -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