{"action":"created","issue":{"url":"https://api.github.com/repos/rmosolgo/graphql-ruby/issues/1809","repository_url":"https://api.github.com/repos/rmosolgo/graphql-ruby","labels_url":"https://api.github.com/repos/rmosolgo/graphql-ruby/issues/1809/labels{/name}","comments_url":"https://api.github.com/repos/rmosolgo/graphql-ruby/issues/1809/comments","events_url":"https://api.github.com/repos/rmosolgo/graphql-ruby/issues/1809/events","html_url":"https://github.com/rmosolgo/graphql-ruby/issues/1809","id":354295870,"node_id":"MDU6SXNzdWUzNTQyOTU4NzA=","number":1809,"title":"Acesssing parent objects to show/hide fields","user":{"login":"jacob-s-son","id":791916,"node_id":"MDQ6VXNlcjc5MTkxNg==","avatar_url":"https://avatars1.githubusercontent.com/u/791916?v=4","gravatar_id":"","url":"https://api.github.com/users/jacob-s-son","html_url":"https://github.com/jacob-s-son","followers_url":"https://api.github.com/users/jacob-s-son/followers","following_url":"https://api.github.com/users/jacob-s-son/following{/other_user}","gists_url":"https://api.github.com/users/jacob-s-son/gists{/gist_id}","starred_url":"https://api.github.com/users/jacob-s-son/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/jacob-s-son/subscriptions","organizations_url":"https://api.github.com/users/jacob-s-son/orgs","repos_url":"https://api.github.com/users/jacob-s-son/repos","events_url":"https://api.github.com/users/jacob-s-son/events{/privacy}","received_events_url":"https://api.github.com/users/jacob-s-son/received_events","type":"User","site_admin":false},"labels":[],"state":"open","locked":false,"assignee":null,"assignees":[],"milestone":null,"comments":0,"created_at":"2018-08-27T12:19:14Z","updated_at":"2018-09-06T14:38:28Z","closed_at":null,"author_association":"NONE","body":"The docs suggest using `#visible?` method to define, if the field is visible to client, but the context passed to that method is not enough to deduce the access. \r\n\r\nConcrete example: a competition is organized and every submission has a rank that consists of several fields. The organizer, when setting up the competition, can decide which rank fields are allowed to be seen by participants. Browser queries our backend this way:\r\n```\r\nquery {\r\n  submission(id: $id) {\r\n    #..other fields\r\n    competition {\r\n      #....\r\n    }\r\n    rank {\r\n      place_in_rank,\r\n      is_tied,\r\n    }\r\n  }\r\n}\r\n```\r\n\r\nOur goal is to make sure that if `competition` object `is_allowed_to_see_ranks` and/or `is_allowed_to_see_ties` is set to false, the query that is listed above takes out `place_in_rank` and `is_tied` accordingly.\r\n\r\nCurrently, as rank object is calculated value object not an entity, we simply remove the fields that are not allowed when calculating, but we would prefer to do this on authorization, not data calculation layer.\r\nWe iterated over several options, trying to understand how this can be solved:\r\n1) when query is being executed additional information is injected into queries context\r\n2) accessing parent through context (does not work with current versions AFAIK: https://github.com/rmosolgo/graphql-ruby/issues/881#issuecomment-383117637)\r\n3) use method definitions, where `parent` is still accessible in a context. There are several issues with this approach:\r\n  - parent tree is different, because rank is accessible two ways - through submission, and through subscription\r\n  - at that point it's not possible cleanly remove the fields from the response, but they would be nullified\r\n\r\nAnother problem that might plague the mentioned options - N+1, how to keep the instance of the auction for every field authorization without re-fetching it ? One of the options I thought about is to define some sort of implicitly passed arguments that are mandatory for rank object.\r\n\r\nAny thoughts?"},"comment":{"url":"https://api.github.com/repos/rmosolgo/graphql-ruby/issues/comments/419118003","html_url":"https://github.com/rmosolgo/graphql-ruby/issues/1809#issuecomment-419118003","issue_url":"https://api.github.com/repos/rmosolgo/graphql-ruby/issues/1809","id":419118003,"node_id":"MDEyOklzc3VlQ29tbWVudDQxOTExODAwMw==","user":{"login":"rmosolgo","id":2231765,"node_id":"MDQ6VXNlcjIyMzE3NjU=","avatar_url":"https://avatars3.githubusercontent.com/u/2231765?v=4","gravatar_id":"","url":"https://api.github.com/users/rmosolgo","html_url":"https://github.com/rmosolgo","followers_url":"https://api.github.com/users/rmosolgo/followers","following_url":"https://api.github.com/users/rmosolgo/following{/other_user}","gists_url":"https://api.github.com/users/rmosolgo/gists{/gist_id}","starred_url":"https://api.github.com/users/rmosolgo/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/rmosolgo/subscriptions","organizations_url":"https://api.github.com/users/rmosolgo/orgs","repos_url":"https://api.github.com/users/rmosolgo/repos","events_url":"https://api.github.com/users/rmosolgo/events{/privacy}","received_events_url":"https://api.github.com/users/rmosolgo/received_events","type":"User","site_admin":true},"created_at":"2018-09-06T14:38:28Z","updated_at":"2018-09-06T14:38:28Z","author_association":"OWNER","body":"I have a few thoughts. First, on this: \r\n\r\n> if `competition` object `is_allowed_to_see_ranks`\r\n\r\nDo you mean checking the value of a Ruby method, eg `competition.is_allowed_to_see_ranks?` ? If so, then `#visible?` won't work for you. `#visible?` is called before any data is fetched (before the query is evaluated at all), so you don't have access to any runtime values.\r\n\r\nInstead, you could use `#authorized?(parent, ctx)`, which will be called with the parent of the `rank` (which looks like the `submission`). So for example you could have: \r\n\r\n```ruby \r\nclass Types::RankField < Types::BaseField\r\n  def authorized?(submission, ctx)\r\n    if name == \"place_in_rank\"\r\n      # Hide this field unless this check returns true:\r\n      submission.competition.is_allowed_to_see_ranks?\r\n    elsif name == \"is_tied\" \r\n      # similar check here \r\n    else \r\n      # OTher fields are always visible: \r\n      true \r\n    end \r\n  end \r\nend \r\n```\r\n\r\nThen use that custom field for the Rank type: \r\n\r\n```ruby \r\nclass Types::Rank \r\n  # implements permission checks for these fields: \r\n  field_class Types::RankField \r\nend \r\n```\r\n\r\nThen, some fields will be rejected when those Ruby checks return false. \r\n\r\nIs that what you're hoping to do here?"}}
{"actor":{"display_login":"rmosolgo"}}