Graphql-engine: how to create relationship for polymorphic association

Created on 5 Dec 2018  路  7Comments  路  Source: hasura/graphql-engine

for polymorphic association, how to create relationship.

class Picture < ApplicationRecord
  belongs_to :imageable, polymorphic: true
end

class Employee < ApplicationRecord
  has_many :pictures, as: :imageable
end

class Product < ApplicationRecord
  has_many :pictures, as: :imageable
end

create_table :pictures do |t|
      t.string  :name
      t.integer :imageable_id
      t.string  :imageable_type
      t.timestamps
end

how to create relationship, so i can query like this

{
     products {
         name
         pictures {
              id
              name
         }
     }
}

thanks !

question

Most helpful comment

@dfang @SkaterDad

We don't natively support polymorphic associations like that of Rails, however you'll still be able to query like you wanted. The pictures table will be something along these lines:

pictures:
- id: integer 
- name: text 
- imageable_id: integer
- imageable_type: text

You can create views as follows:

create view employee_pictures as select * from pictures where imageable_type = 'employees';
create view product_pictures as select * from pictures where imageable_type = 'products';

Now you can define a manual relationship called pictures on employees and products table using these views. So your queries will now look like this:

{
  employees {
    id
    name
    pictures {
      id
      name
    }
  }
}

Another option is to use through table like @shahidhk suggested, i.e, employee_pictures, product_pictures .. etc. If you have such a modelling, Hasura makes it very easy to insert into these tables using relationships, i.e, you can insert a picture and associate it with an employee in a single query. If you have such a modelling, your queries will look like this:

{
  employees {
    id
    name
    pictures {
      picture {
        id
        name
      }
    }
  }
}

So it is up to you to pick a schema design that suits your use case. The GraphQL queries will roughly be the same.

All 7 comments

@dfang I have put together a demo with the schema you noted above: https://relationship-demo.herokuapp.com

Let me know how it goes.

@shahidhk i see, it works.

you create two tables, product_pictures, employee_pictures. when you insert, you need insert data to at least two tables(eg. pictures and product_pictures). normally in rails, we only insert data to pictures. ProductPicture is only pure model.

and if you have another types of pictures, you need to create new tables.
similarly, commentable, likeable, you need to create as many as sub tables.

thanks !

@shahidhk In your experience, which schema style will perform better on Postgres and Hasura?

  • The "Rails-style" version with a "type" column (no way to properly FK)
  • Many-to-Many table version, with a single pictures table (like your example)
  • Separate tables for employee_pictures and product_pictures

@dfang @SkaterDad I am not very familiar with Rails, so I will get back with a more clear understanding.

The Rails way is in the OP. A single table for images, which has columns for the id and type of the related entities.

There are articles arguing that its bad, and other people saying it's good. None are specifically about GraphQL, though, which will impact the types of queries being made.

@dfang @SkaterDad

We don't natively support polymorphic associations like that of Rails, however you'll still be able to query like you wanted. The pictures table will be something along these lines:

pictures:
- id: integer 
- name: text 
- imageable_id: integer
- imageable_type: text

You can create views as follows:

create view employee_pictures as select * from pictures where imageable_type = 'employees';
create view product_pictures as select * from pictures where imageable_type = 'products';

Now you can define a manual relationship called pictures on employees and products table using these views. So your queries will now look like this:

{
  employees {
    id
    name
    pictures {
      id
      name
    }
  }
}

Another option is to use through table like @shahidhk suggested, i.e, employee_pictures, product_pictures .. etc. If you have such a modelling, Hasura makes it very easy to insert into these tables using relationships, i.e, you can insert a picture and associate it with an employee in a single query. If you have such a modelling, your queries will look like this:

{
  employees {
    id
    name
    pictures {
      picture {
        id
        name
      }
    }
  }
}

So it is up to you to pick a schema design that suits your use case. The GraphQL queries will roughly be the same.

Hi @0x777

Thank you for the solution, nice workaround with views 馃憤

But I do have an issue, after creating my new relationship the UI for data schema crash (JS error) with the message "Something went wrong"

If I remove the relationship directly in the database it works again. I've traced the JS error to this line: https://github.com/hasura/graphql-engine/blob/c3f4c35141f1187fc2f0f107158c1dff26f34568/console/src/components/Services/Data/TableRelationships/autoRelations.js#L110

Here is my faulty hdb_relationship row:

table_schema table_name rel_name rel_type rel_def comment is_system_defined
public orders states array {"manual_configuration": {"remote_table": "orders_states", "column_mapping": {"id": "resource_id"}}} NULL f

Did I missed something or this is a bug? Thank you.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

macalinao picture macalinao  路  3Comments

revskill10 picture revskill10  路  3Comments

lishine picture lishine  路  3Comments

marionschleifer picture marionschleifer  路  3Comments

tirumaraiselvan picture tirumaraiselvan  路  3Comments