# Polymorphic associations
Let's assume we have tables Comment
, Issue
and PullRequest
. Both Issue
and PullRequest
can have a list of comments. Comment
has a column commentableId
to hold the foreign key and commentableType
to hold the related model type.
class Comment extends Model {
static get tableName() {
return 'comments';
}
}
class Issue extends Model {
static get tableName() {
return 'issues';
}
static get relationMappings() {
return {
comments: {
relation: Model.HasManyRelation,
modelClass: Comment,
filter(builder) {
builder.where('commentableType', 'Issue');
},
beforeInsert(model) {
model.commentableType = 'Issue';
},
join: {
from: 'issues.id',
to: 'comments.commentableId'
}
}
};
}
}
class PullRequest extends Model {
static get tableName() {
return 'pullrequests';
}
static get relationMappings() {
return {
comments: {
relation: Model.HasManyRelation,
modelClass: Comment,
filter(builder) {
builder.where('commentableType', 'PullRequest');
},
beforeInsert(model) {
model.commentableType = 'PullRequest';
},
join: {
from: 'pullrequests.id',
to: 'comments.commentableId'
}
}
};
}
}
The where('commentableType', 'Type')
filter adds a WHERE "commentableType" = 'Type'
clause to the relation fetch query. The beforeInsert
hook takes care of setting the type on insert.
This kind of associations don't have referential integrity and should be avoided if possible. Instead, consider using the exclusive arc table pattern discussed here (opens new window).