graphql-api icon indicating copy to clipboard operation
graphql-api copied to clipboard

Polymorphic relationships?

Open Amnesthesia opened this issue 7 years ago • 6 comments

I began setting up a schema using ruby-graphql, but when I stumbled across this library I decided to check it out - something I wasn't sure how to get done through ruby-graphql but which I presume could be solved with interfaces, was polymorphic relationships.

Turns out that when I use GraphQL-api, any models defining polymorphic relationships will cause the schema generation to fail:

/Users/amnesthesia/.rvm/gems/ruby-2.3.3@eventyr-api/gems/activesupport-5.0.1/lib/active_support/inflector/methods.rb:268:in `const_get': uninitialized constant Target (NameError)
        from /Users/amnesthesia/.rvm/gems/ruby-2.3.3@eventyr-api/gems/activesupport-5.0.1/lib/active_support/inflector/methods.rb:268:in `block in constantize'
        from /Users/amnesthesia/.rvm/gems/ruby-2.3.3@eventyr-api/gems/activesupport-5.0.1/lib/active_support/inflector/methods.rb:266:in `each'
        from /Users/amnesthesia/.rvm/gems/ruby-2.3.3@eventyr-api/gems/activesupport-5.0.1/lib/active_support/inflector/methods.rb:266:in `inject'
        from /Users/amnesthesia/.rvm/gems/ruby-2.3.3@eventyr-api/gems/activesupport-5.0.1/lib/active_support/inflector/methods.rb:266:in `constantize'
        from /Users/amnesthesia/.rvm/gems/ruby-2.3.3@eventyr-api/gems/activesupport-5.0.1/lib/active_support/core_ext/string/inflections.rb:66:in `constantize'
        from /Users/amnesthesia/.rvm/gems/ruby-2.3.3@eventyr-api/gems/graphql-api-0.2.0/lib/graphql/api/schema.rb:73:in `block (3 levels) in create_type'
        from /Users/amnesthesia/.rvm/gems/ruby-2.3.3@eventyr-api/gems/graphql-1.4.4/lib/graphql/define/instance_definable.rb:131:in `instance_eval'
        from /Users/amnesthesia/.rvm/gems/ruby-2.3.3@eventyr-api/gems/graphql-1.4.4/lib/graphql/define/instance_definable.rb:131:in `ensure_defined'
        from /Users/amnesthesia/.rvm/gems/ruby-2.3.3@eventyr-api/gems/graphql-1.4.4/lib/graphql/define/instance_definable.rb:178:in `block (3 levels) in ensure_defined'
        from /Users/amnesthesia/.rvm/gems/ruby-2.3.3@eventyr-api/gems/graphql-1.4.4/lib/graphql/schema/validation.rb:29:in `public_send'
        from /Users/amnesthesia/.rvm/gems/ruby-2.3.3@eventyr-api/gems/graphql-1.4.4/lib/graphql/schema/validation.rb:29:in `block in assert_property'
        from /Users/amnesthesia/.rvm/gems/ruby-2.3.3@eventyr-api/gems/graphql-1.4.4/lib/graphql/schema/validation.rb:19:in `block in validate'
        from /Users/amnesthesia/.rvm/gems/ruby-2.3.3@eventyr-api/gems/graphql-1.4.4/lib/graphql/schema/validation.rb:19:in `each'
        from /Users/amnesthesia/.rvm/gems/ruby-2.3.3@eventyr-api/gems/graphql-1.4.4/lib/graphql/schema/validation.rb:19:in `reduce'
        from /Users/amnesthesia/.rvm/gems/ruby-2.3.3@eventyr-api/gems/graphql-1.4.4/lib/graphql/schema/validation.rb:19:in `validate'
        from /Users/amnesthesia/.rvm/gems/ruby-2.3.3@eventyr-api/gems/graphql-1.4.4/lib/graphql/schema/validation.rb:80:in `block (2 levels) in assert_named_items_are_valid'
        from /Users/amnesthesia/.rvm/gems/ruby-2.3.3@eventyr-api/gems/graphql-1.4.4/lib/graphql/schema/validation.rb:79:in `each'
        from /Users/amnesthesia/.rvm/gems/ruby-2.3.3@eventyr-api/gems/graphql-1.4.4/lib/graphql/schema/validation.rb:79:in `block in assert_named_items_are_valid'
        from /Users/amnesthesia/.rvm/gems/ruby-2.3.3@eventyr-api/gems/graphql-1.4.4/lib/graphql/schema/validation.rb:19:in `block in validate'
        from /Users/amnesthesia/.rvm/gems/ruby-2.3.3@eventyr-api/gems/graphql-1.4.4/lib/graphql/schema/validation.rb:19:in `each'
        from /Users/amnesthesia/.rvm/gems/ruby-2.3.3@eventyr-api/gems/graphql-1.4.4/lib/graphql/schema/validation.rb:19:in `reduce'
        from /Users/amnesthesia/.rvm/gems/ruby-2.3.3@eventyr-api/gems/graphql-1.4.4/lib/graphql/schema/validation.rb:19:in `validate'
        from /Users/amnesthesia/.rvm/gems/ruby-2.3.3@eventyr-api/gems/graphql-1.4.4/lib/graphql/schema/reduce_types.rb:62:in `validate_type'
        from /Users/amnesthesia/.rvm/gems/ruby-2.3.3@eventyr-api/gems/graphql-1.4.4/lib/graphql/schema/reduce_types.rb:29:in `reduce_type'
        from /Users/amnesthesia/.rvm/gems/ruby-2.3.3@eventyr-api/gems/graphql-1.4.4/lib/graphql/schema/reduce_types.rb:38:in `block in crawl_type'
        from /Users/amnesthesia/.rvm/gems/ruby-2.3.3@eventyr-api/gems/graphql-1.4.4/lib/graphql/schema/reduce_types.rb:37:in `each'
        from /Users/amnesthesia/.rvm/gems/ruby-2.3.3@eventyr-api/gems/graphql-1.4.4/lib/graphql/schema/reduce_types.rb:37:in `crawl_type'
        from /Users/amnesthesia/.rvm/gems/ruby-2.3.3@eventyr-api/gems/graphql-1.4.4/lib/graphql/schema/reduce_types.rb:31:in `reduce_type'
        from /Users/amnesthesia/.rvm/gems/ruby-2.3.3@eventyr-api/gems/graphql-1.4.4/lib/graphql/schema/reduce_types.rb:38:in `block in crawl_type'
        from /Users/amnesthesia/.rvm/gems/ruby-2.3.3@eventyr-api/gems/graphql-1.4.4/lib/graphql/schema/reduce_types.rb:37:in `each'
        from /Users/amnesthesia/.rvm/gems/ruby-2.3.3@eventyr-api/gems/graphql-1.4.4/lib/graphql/schema/reduce_types.rb:37:in `crawl_type'
        from /Users/amnesthesia/.rvm/gems/ruby-2.3.3@eventyr-api/gems/graphql-1.4.4/lib/graphql/schema/reduce_types.rb:31:in `reduce_type'
        from /Users/amnesthesia/.rvm/gems/ruby-2.3.3@eventyr-api/gems/graphql-1.4.4/lib/graphql/schema/reduce_types.rb:38:in `block in crawl_type'
        from /Users/amnesthesia/.rvm/gems/ruby-2.3.3@eventyr-api/gems/graphql-1.4.4/lib/graphql/schema/reduce_types.rb:37:in `each'
        from /Users/amnesthesia/.rvm/gems/ruby-2.3.3@eventyr-api/gems/graphql-1.4.4/lib/graphql/schema/reduce_types.rb:37:in `crawl_type'
        from /Users/amnesthesia/.rvm/gems/ruby-2.3.3@eventyr-api/gems/graphql-1.4.4/lib/graphql/schema/reduce_types.rb:31:in `reduce_type'
        from /Users/amnesthesia/.rvm/gems/ruby-2.3.3@eventyr-api/gems/graphql-1.4.4/lib/graphql/schema/reduce_types.rb:38:in `block in crawl_type'
        from /Users/amnesthesia/.rvm/gems/ruby-2.3.3@eventyr-api/gems/graphql-1.4.4/lib/graphql/schema/reduce_types.rb:37:in `each'
        from /Users/amnesthesia/.rvm/gems/ruby-2.3.3@eventyr-api/gems/graphql-1.4.4/lib/graphql/schema/reduce_types.rb:37:in `crawl_type'
        from /Users/amnesthesia/.rvm/gems/ruby-2.3.3@eventyr-api/gems/graphql-1.4.4/lib/graphql/schema/reduce_types.rb:31:in `reduce_type'
        from /Users/amnesthesia/.rvm/gems/ruby-2.3.3@eventyr-api/gems/graphql-1.4.4/lib/graphql/schema/reduce_types.rb:10:in `block in reduce'
        from /Users/amnesthesia/.rvm/gems/ruby-2.3.3@eventyr-api/gems/graphql-1.4.4/lib/graphql/schema/reduce_types.rb:9:in `each'
        from /Users/amnesthesia/.rvm/gems/ruby-2.3.3@eventyr-api/gems/graphql-1.4.4/lib/graphql/schema/reduce_types.rb:9:in `reduce'
        from /Users/amnesthesia/.rvm/gems/ruby-2.3.3@eventyr-api/gems/graphql-1.4.4/lib/graphql/schema.rb:392:in `build_types_map'
        from /Users/amnesthesia/.rvm/gems/ruby-2.3.3@eventyr-api/gems/graphql-1.4.4/lib/graphql/schema.rb:154:in `define'
        from /Users/amnesthesia/.rvm/gems/ruby-2.3.3@eventyr-api/gems/graphql-1.4.4/lib/graphql/define/instance_definable.rb:152:in `define'
        from /Users/amnesthesia/.rvm/gems/ruby-2.3.3@eventyr-api/gems/graphql-api-0.2.0/lib/graphql/api/schema.rb:228:in `schema'
        from /Users/amnesthesia/Code/AchievementsApp/Eventyr-API/config/initializers/graphql_schema.rb:1:in `<top (required)>'
        from /Users/amnesthesia/.rvm/gems/ruby-2.3.3@eventyr-api/gems/railties-5.0.1/lib/rails/engine.rb:648:in `block in load_config_initializer'
        from /Users/amnesthesia/.rvm/gems/ruby-2.3.3@eventyr-api/gems/activesupport-5.0.1/lib/active_support/notifications.rb:166:in `instrument'
        from /Users/amnesthesia/.rvm/gems/ruby-2.3.3@eventyr-api/gems/railties-5.0.1/lib/rails/engine.rb:647:in `load_config_initializer'
        from /Users/amnesthesia/.rvm/gems/ruby-2.3.3@eventyr-api/gems/railties-5.0.1/lib/rails/engine.rb:612:in `block (2 levels) in <class:Engine>'
        from /Users/amnesthesia/.rvm/gems/ruby-2.3.3@eventyr-api/gems/railties-5.0.1/lib/rails/engine.rb:611:in `each'
        from /Users/amnesthesia/.rvm/gems/ruby-2.3.3@eventyr-api/gems/railties-5.0.1/lib/rails/engine.rb:611:in `block in <class:Engine>'
        from /Users/amnesthesia/.rvm/gems/ruby-2.3.3@eventyr-api/gems/railties-5.0.1/lib/rails/initializable.rb:30:in `instance_exec'
        from /Users/amnesthesia/.rvm/gems/ruby-2.3.3@eventyr-api/gems/railties-5.0.1/lib/rails/initializable.rb:30:in `run'
        from /Users/amnesthesia/.rvm/gems/ruby-2.3.3@eventyr-api/gems/railties-5.0.1/lib/rails/initializable.rb:55:in `block in run_initializers'
        from /Users/amnesthesia/.rvm/rubies/ruby-2.3.3/lib/ruby/2.3.0/tsort.rb:228:in `block in tsort_each'
        from /Users/amnesthesia/.rvm/rubies/ruby-2.3.3/lib/ruby/2.3.0/tsort.rb:350:in `block (2 levels) in each_strongly_connected_component'
        from /Users/amnesthesia/.rvm/rubies/ruby-2.3.3/lib/ruby/2.3.0/tsort.rb:422:in `block (2 levels) in each_strongly_connected_component_from'
        from /Users/amnesthesia/.rvm/rubies/ruby-2.3.3/lib/ruby/2.3.0/tsort.rb:431:in `each_strongly_connected_component_from'
        from /Users/amnesthesia/.rvm/rubies/ruby-2.3.3/lib/ruby/2.3.0/tsort.rb:421:in `block in each_strongly_connected_component_from'
        from /Users/amnesthesia/.rvm/gems/ruby-2.3.3@eventyr-api/gems/railties-5.0.1/lib/rails/initializable.rb:44:in `each'
        from /Users/amnesthesia/.rvm/gems/ruby-2.3.3@eventyr-api/gems/railties-5.0.1/lib/rails/initializable.rb:44:in `tsort_each_child'
        from /Users/amnesthesia/.rvm/rubies/ruby-2.3.3/lib/ruby/2.3.0/tsort.rb:415:in `call'
        from /Users/amnesthesia/.rvm/rubies/ruby-2.3.3/lib/ruby/2.3.0/tsort.rb:415:in `each_strongly_connected_component_from'
        from /Users/amnesthesia/.rvm/rubies/ruby-2.3.3/lib/ruby/2.3.0/tsort.rb:349:in `block in each_strongly_connected_component'
        from /Users/amnesthesia/.rvm/rubies/ruby-2.3.3/lib/ruby/2.3.0/tsort.rb:347:in `each'
        from /Users/amnesthesia/.rvm/rubies/ruby-2.3.3/lib/ruby/2.3.0/tsort.rb:347:in `call'
        from /Users/amnesthesia/.rvm/rubies/ruby-2.3.3/lib/ruby/2.3.0/tsort.rb:347:in `each_strongly_connected_component'
        from /Users/amnesthesia/.rvm/rubies/ruby-2.3.3/lib/ruby/2.3.0/tsort.rb:226:in `tsort_each'
        from /Users/amnesthesia/.rvm/rubies/ruby-2.3.3/lib/ruby/2.3.0/tsort.rb:205:in `tsort_each'
        from /Users/amnesthesia/.rvm/gems/ruby-2.3.3@eventyr-api/gems/railties-5.0.1/lib/rails/initializable.rb:54:in `run_initializers'
        from /Users/amnesthesia/.rvm/gems/ruby-2.3.3@eventyr-api/gems/railties-5.0.1/lib/rails/application.rb:352:in `initialize!'
        from /Users/amnesthesia/Code/AchievementsApp/Eventyr-API/config/environment.rb:5:in `<top (required)>'
        from /Users/amnesthesia/Code/AchievementsApp/Eventyr-API/config.ru:3:in `block in <main>'
        from /Users/amnesthesia/.rvm/gems/ruby-2.3.3@eventyr-api/gems/rack-2.0.1/lib/rack/builder.rb:55:in `instance_eval'
        from /Users/amnesthesia/.rvm/gems/ruby-2.3.3@eventyr-api/gems/rack-2.0.1/lib/rack/builder.rb:55:in `initialize'
        from /Users/amnesthesia/Code/AchievementsApp/Eventyr-API/config.ru:in `new'
        from /Users/amnesthesia/Code/AchievementsApp/Eventyr-API/config.ru:in `<main>'
        from /Users/amnesthesia/.rvm/gems/ruby-2.3.3@eventyr-api/gems/rack-2.0.1/lib/rack/builder.rb:49:in `eval'
        from /Users/amnesthesia/.rvm/gems/ruby-2.3.3@eventyr-api/gems/rack-2.0.1/lib/rack/builder.rb:49:in `new_from_string'
        from /Users/amnesthesia/.rvm/gems/ruby-2.3.3@eventyr-api/gems/rack-2.0.1/lib/rack/builder.rb:40:in `parse_file'
        from /Users/amnesthesia/.rvm/gems/ruby-2.3.3@eventyr-api/gems/rack-2.0.1/lib/rack/server.rb:318:in `build_app_and_options_from_config'
        from /Users/amnesthesia/.rvm/gems/ruby-2.3.3@eventyr-api/gems/rack-2.0.1/lib/rack/server.rb:218:in `app'
        from /Users/amnesthesia/.rvm/gems/ruby-2.3.3@eventyr-api/gems/railties-5.0.1/lib/rails/commands/server.rb:59:in `app'
        from /Users/amnesthesia/.rvm/gems/ruby-2.3.3@eventyr-api/gems/rack-2.0.1/lib/rack/server.rb:353:in `wrapped_app'
        from /Users/amnesthesia/.rvm/gems/ruby-2.3.3@eventyr-api/gems/railties-5.0.1/lib/rails/commands/server.rb:124:in `log_to_stdout'
        from /Users/amnesthesia/.rvm/gems/ruby-2.3.3@eventyr-api/gems/railties-5.0.1/lib/rails/commands/server.rb:77:in `start'
        from /Users/amnesthesia/.rvm/gems/ruby-2.3.3@eventyr-api/gems/railties-5.0.1/lib/rails/commands/commands_tasks.rb:90:in `block in server'
        from /Users/amnesthesia/.rvm/gems/ruby-2.3.3@eventyr-api/gems/railties-5.0.1/lib/rails/commands/commands_tasks.rb:85:in `tap'
        from /Users/amnesthesia/.rvm/gems/ruby-2.3.3@eventyr-api/gems/railties-5.0.1/lib/rails/commands/commands_tasks.rb:85:in `server'
        from /Users/amnesthesia/.rvm/gems/ruby-2.3.3@eventyr-api/gems/railties-5.0.1/lib/rails/commands/commands_tasks.rb:49:in `run_command!'
        from /Users/amnesthesia/.rvm/gems/ruby-2.3.3@eventyr-api/gems/railties-5.0.1/lib/rails/commands.rb:18:in `<top (required)>'
        from /Users/amnesthesia/Code/AchievementsApp/Eventyr-API/bin/rails:8:in `require'
        from /Users/amnesthesia/Code/AchievementsApp/Eventyr-API/bin/rails:8:in `<top (required)>'
        from /Users/amnesthesia/.rvm/gems/ruby-2.3.3@eventyr-api/gems/spring-2.0.1/lib/spring/client/rails.rb:28:in `load'
        from /Users/amnesthesia/.rvm/gems/ruby-2.3.3@eventyr-api/gems/spring-2.0.1/lib/spring/client/rails.rb:28:in `call'
        from /Users/amnesthesia/.rvm/gems/ruby-2.3.3@eventyr-api/gems/spring-2.0.1/lib/spring/client/command.rb:7:in `call'
        from /Users/amnesthesia/.rvm/gems/ruby-2.3.3@eventyr-api/gems/spring-2.0.1/lib/spring/client.rb:30:in `run'
        from /Users/amnesthesia/.rvm/gems/ruby-2.3.3@eventyr-api/gems/spring-2.0.1/bin/spring:49:in `<top (required)>'
        from /Users/amnesthesia/.rvm/gems/ruby-2.3.3@eventyr-api/gems/spring-2.0.1/lib/spring/binstub.rb:31:in `load'
        from /Users/amnesthesia/.rvm/gems/ruby-2.3.3@eventyr-api/gems/spring-2.0.1/lib/spring/binstub.rb:31:in `<top (required)>'

Will polymorphic relationships be supported in the future, or should they be avoided altogether?

Amnesthesia avatar Feb 26 '17 17:02 Amnesthesia

Thanks for opening the issue, I will take a look into this today. I'm imagining another class that could be included in the project and marked as the interface type for the polymorphic relation. This class would receive the type, whatever it is, and then return the necessary fields for that interface.

colinjfw avatar Feb 27 '17 16:02 colinjfw

Fantastic! Thank you for your time and effort - this is great!

Amnesthesia avatar Feb 27 '17 18:02 Amnesthesia

Any status on this? :)

Amnesthesia avatar Mar 18 '17 16:03 Amnesthesia

ran into the same :(

grosser avatar Apr 27 '17 19:04 grosser

I've made a fix that works for me. It's quite specific, so be sure to read the code and fix it so it works for you as well.

These are the lines of the most interest for you: https://github.com/vfonic/graphql-api/commit/8bb9860290b16513ffc27cd31b8b055fdd9d582f#diff-7570a94ad4616e9c899c78ed96929a53R39-R44

The Event, Headline and Place are active record models in my application, the only possible types on the other side of the polymorphic association. You should replace these with your own.

/cc @rchasman @scmathew

vfonic avatar Aug 05 '19 01:08 vfonic

@vfonic thanks for the idea! Would be definitely cool if we could get this in generically.

colinjfw avatar Aug 05 '19 18:08 colinjfw