[Rails] Express polymorphic with graphql-ruby

Introduction

Recently, I have implemented API with graphql-ruby. Rails has a handy feature called polymorphic for associating models. I will explain how to express this in graphql using UnionType.

Thing you want to do

Consider the case where the User and PetShop tables are ownerable and polymorphic in the Dog table. When getting a dog with graphql, make sure that the column of its ownerable (user or pet_shop) is also taken.

If not polymorphic

First, let's review the case of normal associations (belongs_to, has_many, etc.). Suppose User and Dog are one-to-many as shown below.

user.rb


Class User < ApplicationRecord
  has_many: dogs
end

dog.rb


Class Dog < ApplicationRecord
  belongs_to: user
end

ObjectType To express the association defined in the model with graphql-ruby, write ObjectType as follows.

user_type.rb


Class UserType < Types::BaseObject
  field :id, ID, null: false
end

dog_type.rb


Class DogType < Type::BaseObject
  field :name, String, null: false
  field :user, ObjectTypes::UserType, null: false #Association with user
end

If you define ObjectType as above, it will also get the associated user object when returning the dog object.

For polymorphic

Next, consider the case of polymorphic association. Besides user, petShop also owns dog.

Model association

For polymorphic, the Rials model association is as follows:

user.rb


Class User < ApplicationRecord
  has_many :dogs, as: :ownerable
end

pet_shop.rb


Class PetShop < ApplicationRecord
  has_many :dogs, as: :ownerable
end

dog.rb


Class Dog < ApplicationRecord
  belongs_to :ownerable, polymorphic: true
end

ObjectType Next, define the Object type. The petShop object has been added and the dogType field has been changed to ownerable to indicate a polymorphic association instead of user.

user_type.rb


Class UserType < Types::BaseObject
  field :id, ID, null: false
end

pet_shop_type.rb


Class PetShopType < Types::BaseObject
  field :id, ID, null: false
end

dog_type.rb


Class DogType < Type::BaseObject
  field :name, String, null: false
  field :ownerable, UnionTypes::OwnerableType, null: false #Association with ownerable
end

Note that the ownerable type is UnioTypes instead of ObjectTypes. UnionType will be defined from now on. UnioneType UnioType is the heart of this article. The ownerable defined in dogType is defined as UnionType, and it distinguishes between userType and petShopType.

ownerable_type.rb


module UnionTypes
  class OwnerableType < Types::BaseUnion
    # possible_Declare the types that can be associated with types
    possible_types ObjectTypes::UserType, ObjectTypes::PetShopType

   #Describe branch processing
    def self.resolve_type(object, _context)
      if object.is_a?(User)
        ObjectTypes::PostType
      elsif object.is_a?(PetShop)
        ObjectTypes::ReplyType
      end
    end
  end
end

By writing as above, it will determine the type to be returned by resolver and select User or PetShop. (It doesn't look like ruby, but ...) Query When using UnionType, query is also written in a slightly special way.

query{
  dog(id: [dog_id]){
    id
    ownerable {
      __typename #Specify the type
      ... on User {
        id
      }
      __typename
      ... on PetShop {
        id
      }
    }
  }
}

You can select the owner you want by specifying the typename as above.

Recommended Posts

[Rails] Express polymorphic with graphql-ruby
Double polymorphic with Rails
Rails deploy with Docker
[Rails 6] RuntimeError with $ rails s
Handle devise with Rails
[Rails] Learning with Rails tutorial
[Rails] Test with RSpec
[Rails] Development with MySQL
Supports multilingualization with Rails!
Clogged with Express npm install
[Rails] Upload videos with Rails (ActiveStorage)
Try using view_component with rails
[Vue Rails] "Hello Vue!" Displayed with Vue + Rails
Japaneseize using i18n with Rails
API creation with Rails + GraphQL
Preparation for developing with Rails
Run Rails whenever with docker
[Docker] Rails 5.2 environment construction with docker
Use multiple databases with Rails 6.0
[Rails] Specify format with link_to
Login function implementation with rails
[Docker] Use whenever with Docker + Rails
Rails + MySQL environment construction with Docker
Create portfolio with rails + postgres sql
[Rails] Push transmission with LINE Bot
[Rails] Make pagination compatible with Ajax
Run nginx + express with fargate 4 core
Implemented mail sending function with rails
[Rails] Creating a new project with rails new
Minimal Rails with reduced file generation
Create pagination function with Rails Kaminari
Build environment with vue.js + rails + docker
Eliminate Rails FatModel with value object
Recognize Rails projects with Intellij idea
[Grover] Generate PDF with Rails [2020 version]
Build Rails environment with Docker Compose
[Rails] Initial data creation with seed
Track Rails app errors with Sentry
[Environment construction with Docker] Rails 6 & MySQL 8
Connect to Rails server with iPhone
How to get along with Rails
Create My Page with Rails devise
Introducing React to Rails with react-rails
Initial data input with [Rails] seed_fu!
Timeless search with Rails + JavaScript (jQuery)
Let's unit test with [rails] Rspec!