Graphql-ruby: "Duplicate type definition" when Defining two Relay Edge classes that set the same node_type

Created on 6 Jul 2018  路  9Comments  路  Source: rmosolgo/graphql-ruby

Using 1.8.4....

Two Connection classes:

# frozen_string_literal: true

# Define Graphql Connection for Roles
class RBAC::Connections::RolesConnection < ::Types::BaseConnection
  graphql_name 'RolesConnection'
  edge_type(RBAC::Edges::RolesEdge, node_type: RBAC::Types::RoleType)
end
# frozen_string_literal: true

# Define Graphql Connection for user to Roles
class RBAC::Connections::UserRolesConnection < ::Types::BaseConnection
  graphql_name 'UserRolesConnection'
  edge_type(RBAC::Edges::UserRolesEdge)



md5-1e64f120e46a5a44521bae3f65b0e58b



```ruby
# frozen_string_literal: true

# User => UsersRoles => Role
class RBAC::Edges::UserRolesEdge < ::Types::BaseEdge
  graphql_name 'UserRolesEdge'
  node_type(RBAC::Types::RoleType)
  field :added_on, String, 'The date that this User was added to this Role', null: true
  def added_on
    user = object.parent
    role = object.node

    # lets create a custom attribute for how long this relationship has been here
    # we will query from the UsersRole Join Table
    added_on = UsersRole.where(user: user, role: role).first
    added_on&.created_at
  end
end



md5-f24d4bfd4a34cffd3fd058208a3897d9



I, [2018-07-05T15:14:58.365193 #44737]  INFO -- : Completed 500 Internal Server Error in 345ms (ActiveRecord: 13.8ms)
F, [2018-07-05T15:14:58.365746 #44737] FATAL -- :
F, [2018-07-05T15:14:58.365771 #44737] FATAL -- : RuntimeError (Duplicate type definition found for name 'RoleEdge' at 'Field RolesConnection.edges's return type' (RBAC::Edges::UserRolesEdge, RBAC::Edges::RolesEdge)):
F, [2018-07-05T15:14:58.365786 #44737] FATAL -- :
F, [2018-07-05T15:14:58.365800 #44737] FATAL -- : app/controllers/rbac_graphql_controller.rb:18:in `query'

It seems that the template graphql-ruby/lib/graphql/types/relay/base_edge.rb class tries to automatically apply a graphql_name to the object edge returned by the "edges" field based on the class name of the node_type.

If you have implemented two different edges, that return the same node_type, then the namespace conflicts.

Most helpful comment

I found another temporay work around without monkey patching. Just add the #graphql_name call _after_ the #node_type method.

Example:

class ArticleReadlistEdgeType < GraphQL::Types::Relay::BaseEdge
  node_type(ArticleType)
  graphql_name('ArticleReadlistEdge')
  ...

This overrides the name after it's set in #node_type and resolves the duplicate.

I would love the see this fixed or documented. Having multple edges to one node type seems a fairly common use-case to me.

All 9 comments

Looking at your BaseEdge Class, it seems that setting "graphql_name" on line 35 is both redundant (since it's already set in the Edge class implementation), and causing this particular problem.

I commented it out completely and it solved this naming collision.

      def node_type(node_type = nil)
        if node_type
          @node_type = node_type
          wrapped_type_name = node_type.graphql_name
          # Set this to be named like the node type, but suffixed with `Edge`
          # graphql_name("#{wrapped_type_name}Edge")
          # Add a default `node` field
          field :node, node_type, null: true, description: 'The item at the end of the edge.'
        end
        @node_type
      end

Maybe that graphql_edge(...) call should be refactored to a ||=. Thanks for sharing your solution!

Hi @rmosolgo! May I ask why this issue was closed? It's still in master, causing the exact issue @clader described.

I don't have the capacity to prioritize the fix, and a solution was found by the reporter, so I didn't have any concrete next steps. Feel free to open a PR to address this case if you'd like!

@clader @rmosolgo Running into this as well - looks like we can't define two edges that use the same node_type. Does the monkey patching fix above have any known side effects?

I think the only side effect would be that if you don't give your custom edge a name, this patch will not let it fall back to a "default" name, and hence throw an error.

Got it. Just for my sanity - having different edges that have the same node_type is a valid (and common?) way to do graphql, right? How else do you add different sets of data to edges of the same node type? E.g. a model with lots of has_many :through relationships that have data in the through table.

I can鈥檛 say how common this is , but what you describe was my exact use case, and why I needed to do this.

I found another temporay work around without monkey patching. Just add the #graphql_name call _after_ the #node_type method.

Example:

class ArticleReadlistEdgeType < GraphQL::Types::Relay::BaseEdge
  node_type(ArticleType)
  graphql_name('ArticleReadlistEdge')
  ...

This overrides the name after it's set in #node_type and resolves the duplicate.

I would love the see this fixed or documented. Having multple edges to one node type seems a fairly common use-case to me.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

amozoss picture amozoss  路  3Comments

rylanc picture rylanc  路  3Comments

theodorton picture theodorton  路  3Comments

peterphan1996 picture peterphan1996  路  3Comments

rmosolgo picture rmosolgo  路  4Comments