Skip to content

Commit 5f52cdd

Browse files
mamhoffstas
andauthored
Allow decorating objects after pagination (#91)
* Rubocop fix: Use filter_map instead of map { ... }.compact Currently, builds are failing because of Rubocop complaining about these three lines. * Fix specs with Ransack 4.0 Ransack 4 requires explicitly allowlisting ransackable attributes and associations for each model. This causes the specs to fail with the most recent Ransack version. This fixes those spec failures. * Allow decorating objects after pagination This simplification allows decorating objects after they are paginated, without losing the correct total object count. I'm using an instance variable on the including controller here, because the decorating the paginated collection will have us lose the instance variable we set on it. Here's the case where this happens: We have a complex ActiveRecord collection that we run through Ransack and Kaminari, but before rendering we want to convert each object in it using a `SimpleDelegator`. Here's a simplified version of the controller action we're looking at: ``` class UserDecorator < SimpleDelegator def fantastic_for_rendering "Whoah" end end def index allowed_fields = [ :first_name, :last_name, :created_at, :notes_created_at, :notes_quantity ] options = { sort_with_expressions: true } jsonapi_filter(User.all, allowed_fields, options) do |filtered| result = filtered.result jsonapi_paginate(result) do |paginated| paginated = paginated.map { |user| UserDecorator.new() } render jsonapi: paginated end end end ``` --------- Co-authored-by: Stas <stas@users.noreply.github.com>
1 parent 52b4128 commit 5f52cdd

3 files changed

Lines changed: 27 additions & 12 deletions

File tree

lib/jsonapi/pagination.rb

Lines changed: 4 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -13,14 +13,13 @@ module Pagination
1313
def jsonapi_paginate(resources)
1414
offset, limit, _ = jsonapi_pagination_params
1515

16+
# Cache the original resources size to be used for pagination meta
17+
@_jsonapi_original_size = resources.size
18+
1619
if resources.respond_to?(:offset)
1720
resources = resources.offset(offset).limit(limit)
1821
else
19-
original_size = resources.size
2022
resources = resources[(offset)..(offset + limit - 1)] || []
21-
22-
# Cache the original resources size to be used for pagination meta
23-
resources.instance_variable_set(:@original_size, original_size)
2423
end
2524

2625
block_given? ? yield(resources) : resources
@@ -64,13 +63,7 @@ def jsonapi_pagination_meta(resources)
6463

6564
numbers = { current: page }
6665

67-
if resources.respond_to?(:unscope)
68-
total = resources.unscope(:limit, :offset, :order).size
69-
else
70-
# Try to fetch the cached size first
71-
total = resources.instance_variable_get(:@original_size)
72-
total ||= resources.size
73-
end
66+
total = @_jsonapi_original_size
7467

7568
last_page = [1, (total.to_f / limit).ceil].max
7669

spec/dummy.rb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,7 @@ def index
119119
result = result.to_a if params[:as_list]
120120

121121
jsonapi_paginate(result) do |paginated|
122+
paginated = paginated.to_a if params[:decorate_after_pagination]
122123
render jsonapi: paginated
123124
end
124125
end

spec/pagination_spec.rb

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,11 +53,13 @@
5353

5454
context 'on page 2 out of 3' do
5555
let(:as_list) { }
56+
let(:decorate_after_pagination) { }
5657
let(:params) do
5758
{
5859
page: { number: 2, size: 1 },
5960
sort: '-created_at',
60-
as_list: as_list
61+
as_list: as_list,
62+
decorate_after_pagination: decorate_after_pagination
6163
}.compact_blank
6264
end
6365

@@ -80,6 +82,25 @@
8082
end
8183
end
8284

85+
context 'when decorating objects after pagination' do
86+
let(:decorate_after_pagination) { true }
87+
88+
it do
89+
expect(response).to have_http_status(:ok)
90+
expect(response_json['data'].size).to eq(1)
91+
expect(response_json['data'][0]).to have_id(second_user.id.to_s)
92+
93+
expect(response_json['meta']['pagination']).to eq(
94+
'current' => 2,
95+
'first' => 1,
96+
'prev' => 1,
97+
'next' => 3,
98+
'last' => 3,
99+
'records' => 3
100+
)
101+
end
102+
end
103+
83104
it do
84105
expect(response).to have_http_status(:ok)
85106
expect(response_json['data'].size).to eq(1)

0 commit comments

Comments
 (0)