github-community-projects / github-community-projects/graphql-client
Can't use `#to_param` as a field any more
- 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
Assessment
This issue has not been assessed yet.