-
Notifications
You must be signed in to change notification settings - Fork 1.4k
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
Double call of scope_items method before and after pagination #4253
Comments
Hi, thanks for the detailed report! I agree the list should only be scoped once and that the current behavior is a bug. I think the reason for this bug is that connection types make an extra call to |
@rmosolgo could you check the PR and provide your feedback? Does it look like valid fix? |
I think this fix ended up producing the opposite of the desired behavior; scope_items is now called only on the unpaginated connection, rather than on the final materialized paginated array. What I want is for scoped_items to not run for the connection, but to only run for the list that results from that connection. I've got this in my BaseObject, which is how I dealt with the two-pass behavior before: def self.scope_items(items, context)
if items.is_a? Array
items.select { |i| authorized?(i, context) }
else
items
end
end Right now, graphql-ruby's behavior when any item in a list is unauthorized is to null the entire list. This turns out to be a problem in a few cases in my application, where my field resolvers resolve lists of records and then count on type authorization to determine if it's visible or not. What I want to have happen is for a list of items to be loaded, and then any unauthorized items just silently removed. I did this rather than allowing for nullable lists, as nullable nodes connections end up being a pain clientside, where we have to handle In 2.0.15, the two-pass nature of What's happening now is the worst of both: the |
In my case, this does the trick: I do actually double-scope, but the scope on the connection turns into a no-op, then I re-enable scoping on the nodes/edges. This results in scope_items only being run on my arrays. class Types::BaseConnection < Types::BaseObject
include GraphQL::Types::Relay::ConnectionBehaviors
def self.edge_type(*args, field_options: {}, **kwargs)
field_options[:scope] = true # Add this to all nodes fields
super(*args, field_options: field_options, **kwargs)
end
def self.nodes_field(field_options: {}, **kwargs)
field_options[:scope] = true # Add this to all nodes fields
super(field_options: field_options, **kwargs)
end
# Don't apply any actual scoping to connections. Instead, we're going to scope the nodes directly.
def self.scope_items(items, context)
items
end
end |
Describe the bug
Hello.
I see weird behaviour in my project when resolver with cursor pagination calls scope_items method in type two times.
First time the scope in this method is a full set of data without pagination. Second time the scope with pagination.
It affects the performance because first call works with big amounts of data.
I use scope_items method to remove records that not available for current user and policy checks for thousands of records is not what I want :)
Versions
graphql
version: 2.0.15rails
(or other framework): 6.1.5GraphQL schema
GraphQL query
Steps to reproduce
Try to call any resolver with cursor pagination that works with type object with scope_items method. Set breakpoint in scope_items method.
Expected behavior
scope_items method call should be made once for paginated data set
Actual behavior
scope_items call made for non paginated and paginated data
Additional context
Add any other context about the problem here.
With these details, we can efficiently hunt down the bug!
The text was updated successfully, but these errors were encountered: