-
Notifications
You must be signed in to change notification settings - Fork 59
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Allow decorating objects after pagination #91
Allow decorating objects after pagination #91
Conversation
@mamhoff Have you considered doing the decoration before the array is passed to the method? Eg.: 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
+ result = filtered.result.to_a.map { |user| UserDecorator.new() }
jsonapi_paginate(result) do |paginated|
- paginated = paginated.map { |user| UserDecorator.new() }
render jsonapi: paginated
end
end
end |
Yes - the problem is that the decoration materializes the ActiveRecord scope before pagination, and we instantiate and decorate way more objects than we need, leading to a pretty large performance problem, unfortunately. |
See stas/jsonapi.rb#91 for details on what these fix.
Ok @mamhoff but how is this an issue this project should solve? Could you just provide the right object interface to mimic an enumerable/array and do your jazz in the wrapper/decorator implementation on your side? I'm just confused why we need to bend this generic (and pretty flexible already) library to some specific use-case that just you guys have internally? 🙈 |
Sure, we can work around this issue in our local project; I found the fix I'm proposing here more elegant than writing that wrapper. I was confused about why the pagination was off, and only by digging through the source of this library did I find that we're making an assumption that the object being paginated is - and stays - and ActiveRecord relation between pagination and rendering OR is - and stays - an array between the two steps. I understand where you're coming from, but I don't see where this PR introduces more complexity to this library. |
The proposed changes are removing fixes for known and performance issues, like unscoping an ActiveRecord collection. It also moves the caching of the If you can work around the challenges you are facing in your project, I suggest taking that route, since I don't see a lot of upside in moving forward with this changeset 🙏 |
Currently, builds are failing because of Rubocop complaining about these three lines.
b7dc9bc
to
90a1f32
Compare
I've looked through the commit history to find those issues, but I couldn't find any that this changeset breaks. I do calculate the total size of the collection before paginating ("scoping") it, making the need for unscoping unnecessary. This will issue a
To the contrary: This fixes an issue with mutability. The current code in the library mutates the collection being passed in, with the consequence that I can't safely use
It turns out that because We're great fans of this library and really, really do value and appreciate your work on it. As a maintainer myself, I understand the value of being conservative with accepting change. However, in this particular case I have a hard time understanding the downsides of this change. |
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.
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 ```
90a1f32
to
1a5d075
Compare
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:
What is the current behavior?
When modifying objects after they are paginated, we lose the total count and get wrong pagination information.
What is the new behavior?
In this and other cases, we get correct pagination behaviour.
Checklist
Please make sure the following requirements are complete:
features)