github-community-projects / github-community-projects/graphql-client

Can't use `#to_param` as a field any more

Open
#20 0 comments 1 reaction 0 assignees View on GitHub
Dominant language
Ruby
Stars
78
Forks
228
PR merge metrics
No merged PRs in 30d

Description

Below is a piece of code that used to work fine until v0.16.0 and stopped since v0.17.0. Tested with Ruby 3.2.2.

We use similar code to make the objects returned from GraphQL queries work with Rails' route helpers and for that we need to add `#to_param` to our type definitions.

In a Rails project `#to_param` is defined on the base `Object` class and by default returns `self.to_s` ([source](https://github.com/rails/rails/blob/2c611602d0349b633dc45203309718d51161e61f/activesupport/lib/active_support/core_ext/object/to_query.rb)).

The objects returned from queries inherit from `GraphQL::Client::Schema::ObjectClass` which inherits from `Object`. So when we call `#to_param` on an object returned from the query it gets dispatched as `Object#to_param` and doesn't end up in `GraphQL::Client::Schema::ObjectClass#method_missing`. Thus instead of IDs of records we get strings like `"#<#::User:0x0000000106316d50>"`.

It looks that in v0.16.0 all the typed fields were defined as methods on the query objects and since v0.17.0 the library moved to `method_missing` dispatch. That's why it's no longer possible to use fields that correspond to instance methods of `Object`, like `#to_param`.

```ruby
#!/usr/bin/env ruby
require "bundler/inline"
gemfile do
source "https://rubygems.org"

gem "graphql", "1.13.2"
# gem "graphql-client", "0.16.0" # <--- this works as expected
gem "graphql-client", "0.21.0"
gem "activesupport", "7.1.3.2"
end
require "graphql"
require "graphql/client"
require "active_support/core_ext/object/to_query"

module MyData
User = Data.define(:id)
end

module MyTypes
class User < GraphQL::Schema::Object
field :id, ID, null: false
field :to_param, String, null: false, resolver_method: :resolve_to_param

def resolve_to_param
"user-#{object.id}"
end
end

class Query < GraphQL::Schema::Object
field :current_user, User, null: false

def current_user
MyData::User.new(id: 1)
end
end
end

class MySchema < GraphQL::Schema
query(MyTypes::Query)
end

client = GraphQL::Client.new(schema: MySchema, execute: MySchema)

TEST_QUERY = client.parse(<<~GRAPHQL)
query {
currentUser {
toParam
}
}
GRAPHQL

current_user = client.query(TEST_QUERY).data.current_user

puts "current_user is #{current_user.inspect}"
puts "Expecting #to_param to return \"user-1\", got: #{current_user.to_param.inspect}"
```

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.