jsonapi_responses 1.0.1 → 1.1.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/CHANGELOG.md +39 -0
- data/README.md +148 -0
- data/lib/jsonapi_responses/respondable.rb +33 -2
- data/lib/jsonapi_responses/responder.rb +44 -0
- data/lib/jsonapi_responses/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: '066548a9ebf27a83035e88ae033d84a8aee310cb6ee13fb4e789498ebdfa5d72'
|
|
4
|
+
data.tar.gz: 8714c314df3e5125f56cfd79119dc5acbdf1aaa66583dce4ed6e74faa13ca25c
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: d2c2603d5d6f1cf28211af7742f22954562b84283d2818f1bfab517e305b5aa86bf2a7f5214e2b9c8e1d558371f8d440b138a58086faa4d814d4cfd22f5e476a
|
|
7
|
+
data.tar.gz: db9adb8eb6635f91fd5d18595285d7d42dc1f4aac13be52d4471f572a5404defe6abde66d816b51f68357ff78587241026a2509d5ae86a864848d00a5ead5869
|
data/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,44 @@
|
|
|
1
1
|
## [Unreleased]
|
|
2
2
|
|
|
3
|
+
## [1.1.0] - 2025-11-21
|
|
4
|
+
|
|
5
|
+
### Added
|
|
6
|
+
|
|
7
|
+
- **Automatic Pagination Support**: `respond_for_index` now auto-detects Kaminari/WillPaginate pagination and includes meta automatically
|
|
8
|
+
- **Pagination Helpers in Responder**: Added `paginated?`, `pagination_meta`, and `render_collection_with_meta` methods
|
|
9
|
+
- **Smart Meta Handling**: Automatically merges pagination meta with context meta if both are present
|
|
10
|
+
|
|
11
|
+
### Features
|
|
12
|
+
|
|
13
|
+
- Auto-detection of paginated collections (checks for `current_page`, `total_pages`, `total_count` methods)
|
|
14
|
+
- Automatic inclusion of pagination metadata: `current_page`, `total_pages`, `total_count`, `per_page`
|
|
15
|
+
- Backward compatible - works with manual `meta` in context or auto-detects pagination
|
|
16
|
+
- Works with both Kaminari and WillPaginate gems
|
|
17
|
+
|
|
18
|
+
### Example Usage
|
|
19
|
+
|
|
20
|
+
```ruby
|
|
21
|
+
# Controller - Automatic pagination meta
|
|
22
|
+
def index
|
|
23
|
+
@academies = Academy.page(params[:page]).per(15)
|
|
24
|
+
render_with(@academies) # Auto-includes pagination meta!
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
# Manual meta still works
|
|
28
|
+
def index
|
|
29
|
+
@academies = Academy.page(params[:page]).per(15)
|
|
30
|
+
render_with(@academies, context: { meta: { custom: 'data' } })
|
|
31
|
+
# Merges pagination + custom meta
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
# Custom responder with pagination helper
|
|
35
|
+
class MyResponder < JsonapiResponses::Responder
|
|
36
|
+
def render
|
|
37
|
+
render_collection_with_meta(record, { custom: 'meta' })
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
```
|
|
41
|
+
|
|
3
42
|
## [1.0.0] - 2025-10-07
|
|
4
43
|
|
|
5
44
|
### 🎉 Major Release - Breaking Changes
|
data/README.md
CHANGED
|
@@ -153,6 +153,154 @@ By allowing the frontend to request only the needed data, you can:
|
|
|
153
153
|
- Avoid creating multiple endpoints for different data requirements
|
|
154
154
|
- Optimize database queries based on the requested view
|
|
155
155
|
|
|
156
|
+
## Automatic Pagination Support
|
|
157
|
+
|
|
158
|
+
**New in v1.1.0:** JsonapiResponses now automatically detects and handles paginated collections using Kaminari, making pagination effortless.
|
|
159
|
+
|
|
160
|
+
### Basic Usage
|
|
161
|
+
|
|
162
|
+
When you paginate your records with Kaminari, pagination metadata is automatically included in the response:
|
|
163
|
+
|
|
164
|
+
```ruby
|
|
165
|
+
class Api::V1::AcademiesController < ApplicationController
|
|
166
|
+
include JsonapiResponses::Respondable
|
|
167
|
+
|
|
168
|
+
def index
|
|
169
|
+
academies = Academy.page(params[:page]).per(15)
|
|
170
|
+
|
|
171
|
+
# That's it! Pagination is automatic
|
|
172
|
+
render_with(academies)
|
|
173
|
+
end
|
|
174
|
+
end
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
**Response:**
|
|
178
|
+
|
|
179
|
+
```json
|
|
180
|
+
{
|
|
181
|
+
"data": [
|
|
182
|
+
{ "id": 1, "name": "Academy 1", ... },
|
|
183
|
+
{ "id": 2, "name": "Academy 2", ... }
|
|
184
|
+
],
|
|
185
|
+
"meta": {
|
|
186
|
+
"current_page": 1,
|
|
187
|
+
"total_pages": 5,
|
|
188
|
+
"total_count": 73,
|
|
189
|
+
"per_page": 15
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
### How It Works
|
|
195
|
+
|
|
196
|
+
JsonapiResponses automatically detects if your collection responds to Kaminari's pagination methods:
|
|
197
|
+
- `current_page`
|
|
198
|
+
- `total_pages`
|
|
199
|
+
- `total_count`
|
|
200
|
+
|
|
201
|
+
If these methods exist, pagination metadata is automatically included in the response.
|
|
202
|
+
|
|
203
|
+
### With Custom Views
|
|
204
|
+
|
|
205
|
+
Pagination works seamlessly with different view formats:
|
|
206
|
+
|
|
207
|
+
```ruby
|
|
208
|
+
def index
|
|
209
|
+
academies = Academy
|
|
210
|
+
.includes(:owner, :courses)
|
|
211
|
+
.page(params[:page])
|
|
212
|
+
.per(params[:per_page] || 15)
|
|
213
|
+
|
|
214
|
+
# Supports view parameter and automatic pagination
|
|
215
|
+
render_with(academies)
|
|
216
|
+
end
|
|
217
|
+
```
|
|
218
|
+
|
|
219
|
+
**Request:**
|
|
220
|
+
```
|
|
221
|
+
GET /api/v1/academies?page=2&per_page=20&view=summary
|
|
222
|
+
```
|
|
223
|
+
|
|
224
|
+
**Response:**
|
|
225
|
+
```json
|
|
226
|
+
{
|
|
227
|
+
"data": [
|
|
228
|
+
{ "id": 21, "name": "Academy 21", ... }
|
|
229
|
+
],
|
|
230
|
+
"meta": {
|
|
231
|
+
"current_page": 2,
|
|
232
|
+
"total_pages": 4,
|
|
233
|
+
"total_count": 73,
|
|
234
|
+
"per_page": 20
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
```
|
|
238
|
+
|
|
239
|
+
### Requirements
|
|
240
|
+
|
|
241
|
+
- **Kaminari gem** must be installed and configured
|
|
242
|
+
- Your collection must be paginated with `.page()` method
|
|
243
|
+
|
|
244
|
+
### Custom Pagination Metadata
|
|
245
|
+
|
|
246
|
+
You can add additional metadata alongside automatic pagination:
|
|
247
|
+
|
|
248
|
+
```ruby
|
|
249
|
+
def index
|
|
250
|
+
academies = Academy.page(params[:page]).per(15)
|
|
251
|
+
|
|
252
|
+
render_with(
|
|
253
|
+
academies,
|
|
254
|
+
context: { view: view },
|
|
255
|
+
meta: {
|
|
256
|
+
fetched_at: Time.current,
|
|
257
|
+
filters_applied: params[:search].present?
|
|
258
|
+
}
|
|
259
|
+
)
|
|
260
|
+
end
|
|
261
|
+
```
|
|
262
|
+
|
|
263
|
+
**Response:**
|
|
264
|
+
```json
|
|
265
|
+
{
|
|
266
|
+
"data": [...],
|
|
267
|
+
"meta": {
|
|
268
|
+
"current_page": 1,
|
|
269
|
+
"total_pages": 5,
|
|
270
|
+
"total_count": 73,
|
|
271
|
+
"per_page": 15,
|
|
272
|
+
"fetched_at": "2024-01-15T10:30:00Z",
|
|
273
|
+
"filters_applied": true
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
```
|
|
277
|
+
|
|
278
|
+
### Using Pagination Helpers
|
|
279
|
+
|
|
280
|
+
For custom responders, use the built-in pagination helpers:
|
|
281
|
+
|
|
282
|
+
```ruby
|
|
283
|
+
class AcademyResponder < JsonapiResponses::Responder
|
|
284
|
+
def respond_for_index
|
|
285
|
+
if paginated?(record)
|
|
286
|
+
render json: {
|
|
287
|
+
data: serialize_collection(record, serializer_class, context),
|
|
288
|
+
meta: pagination_meta(record, context)
|
|
289
|
+
}
|
|
290
|
+
else
|
|
291
|
+
render json: {
|
|
292
|
+
data: serialize_collection(record, serializer_class, context)
|
|
293
|
+
}
|
|
294
|
+
end
|
|
295
|
+
end
|
|
296
|
+
end
|
|
297
|
+
```
|
|
298
|
+
|
|
299
|
+
Available helpers:
|
|
300
|
+
- `paginated?(record)` - Check if record supports pagination
|
|
301
|
+
- `pagination_meta(record, context)` - Extract pagination metadata hash
|
|
302
|
+
- `render_collection_with_meta(record, serializer_class, context)` - Render with automatic pagination
|
|
303
|
+
|
|
156
304
|
## Development
|
|
157
305
|
|
|
158
306
|
After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
|
|
@@ -165,7 +165,8 @@ module JsonapiResponses
|
|
|
165
165
|
def render_with(record, options = {})
|
|
166
166
|
action = options[:action] || action_name.to_sym
|
|
167
167
|
context = (options[:context] || {}).merge(serialization_user)
|
|
168
|
-
|
|
168
|
+
# Only use params[:view] if view is not already provided in context
|
|
169
|
+
context[:view] ||= params[:view]&.to_sym
|
|
169
170
|
serializer_class = options[:serializer] || "#{controller_name.singularize.camelize}Serializer".constantize
|
|
170
171
|
|
|
171
172
|
# If a custom responder is provided, use it
|
|
@@ -212,7 +213,17 @@ module JsonapiResponses
|
|
|
212
213
|
end
|
|
213
214
|
|
|
214
215
|
def respond_for_index(record, serializer_class, context)
|
|
215
|
-
|
|
216
|
+
response = { data: serialize_collection(record, serializer_class, context) }
|
|
217
|
+
|
|
218
|
+
# Auto-detect pagination and add meta if available
|
|
219
|
+
if paginated?(record)
|
|
220
|
+
response[:meta] = pagination_meta(record, context)
|
|
221
|
+
elsif context[:meta]
|
|
222
|
+
# Allow manual meta from context
|
|
223
|
+
response[:meta] = context[:meta]
|
|
224
|
+
end
|
|
225
|
+
|
|
226
|
+
render json: response
|
|
216
227
|
end
|
|
217
228
|
|
|
218
229
|
def respond_for_show(record, serializer_class, context)
|
|
@@ -259,5 +270,25 @@ module JsonapiResponses
|
|
|
259
270
|
]
|
|
260
271
|
}, status: :bad_request
|
|
261
272
|
end
|
|
273
|
+
|
|
274
|
+
# Check if record is paginated (Kaminari or WillPaginate support)
|
|
275
|
+
def paginated?(record)
|
|
276
|
+
record.respond_to?(:current_page) &&
|
|
277
|
+
record.respond_to?(:total_pages) &&
|
|
278
|
+
record.respond_to?(:total_count)
|
|
279
|
+
end
|
|
280
|
+
|
|
281
|
+
# Extract pagination metadata from paginated record
|
|
282
|
+
def pagination_meta(record, context = {})
|
|
283
|
+
base_meta = {
|
|
284
|
+
current_page: record.current_page,
|
|
285
|
+
total_pages: record.total_pages,
|
|
286
|
+
total_count: record.total_count,
|
|
287
|
+
per_page: record.try(:limit_value) || record.try(:per_page) || context[:per_page]
|
|
288
|
+
}.compact
|
|
289
|
+
|
|
290
|
+
# Merge with any additional meta from context
|
|
291
|
+
context[:meta] ? base_meta.merge(context[:meta]) : base_meta
|
|
292
|
+
end
|
|
262
293
|
end
|
|
263
294
|
end
|
|
@@ -101,5 +101,49 @@ module JsonapiResponses
|
|
|
101
101
|
def single_item?
|
|
102
102
|
!collection?
|
|
103
103
|
end
|
|
104
|
+
|
|
105
|
+
# Check if record is paginated (Kaminari or WillPaginate support)
|
|
106
|
+
# @return [Boolean]
|
|
107
|
+
def paginated?
|
|
108
|
+
record.respond_to?(:current_page) &&
|
|
109
|
+
record.respond_to?(:total_pages) &&
|
|
110
|
+
record.respond_to?(:total_count)
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
# Extract pagination metadata from paginated record
|
|
114
|
+
# @return [Hash, nil] Pagination metadata or nil if not paginated
|
|
115
|
+
def pagination_meta
|
|
116
|
+
return nil unless paginated?
|
|
117
|
+
|
|
118
|
+
{
|
|
119
|
+
current_page: record.current_page,
|
|
120
|
+
total_pages: record.total_pages,
|
|
121
|
+
total_count: record.total_count,
|
|
122
|
+
per_page: record.try(:limit_value) || record.try(:per_page)
|
|
123
|
+
}.compact
|
|
124
|
+
end
|
|
125
|
+
|
|
126
|
+
# Render collection with automatic pagination support
|
|
127
|
+
# @param records [Array, ActiveRecord::Relation] Records to render
|
|
128
|
+
# @param additional_meta [Hash] Additional metadata to include
|
|
129
|
+
def render_collection_with_meta(records = nil, additional_meta = {})
|
|
130
|
+
records ||= record
|
|
131
|
+
response = { data: serialize_collection(records) }
|
|
132
|
+
|
|
133
|
+
# Auto-detect pagination
|
|
134
|
+
if records.respond_to?(:current_page)
|
|
135
|
+
meta = {
|
|
136
|
+
current_page: records.current_page,
|
|
137
|
+
total_pages: records.total_pages,
|
|
138
|
+
total_count: records.total_count,
|
|
139
|
+
per_page: records.try(:limit_value) || records.try(:per_page)
|
|
140
|
+
}.compact
|
|
141
|
+
response[:meta] = meta.merge(additional_meta)
|
|
142
|
+
elsif additional_meta.any?
|
|
143
|
+
response[:meta] = additional_meta
|
|
144
|
+
end
|
|
145
|
+
|
|
146
|
+
render_json(response)
|
|
147
|
+
end
|
|
104
148
|
end
|
|
105
149
|
end
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: jsonapi_responses
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 1.
|
|
4
|
+
version: 1.1.1
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Oscar Ortega
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: exe
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2025-
|
|
11
|
+
date: 2025-11-22 00:00:00.000000000 Z
|
|
12
12
|
dependencies: []
|
|
13
13
|
description: JsonapiResponses simplifies API response handling by allowing multiple
|
|
14
14
|
response formats from a single endpoint, improving performance and reducing endpoint
|