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.
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.
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.
Next, consider the case of polymorphic association. Besides user, petShop also owns dog.
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