Hello all!
I am trying to give my old Rails application a shiny new RedwoodJS frontend, but I’m running into a problem with modeling an existing has_many :through relationship, and since there may be some Rails expats here with experience, I figured i’d post, hoping someone has had a similar problem.
Basically I have a User model and a Role model, and they are joined through a relation table called “assignments” in the database, which I have mapped to be called “RolesOnUsers” in the prisma scheme. I am trying to model an explicit many-to-many (m-n) relationship according to the explicit variant in the prisma docs example here.
I expected to be able to query something like:
query FIND_USER_BY_ID($id: Int!) {
user: user(id: $id) {
firstName
lastName
roles {
name
id
}
}
}
and get the role names and id.
Instead I get the id of the relation table record, and since it doesn’t have a ‘name’ attribute it returns a ‘null’:
{
"data": {
"user": {
"firstName": "Digitador",
"lastName": "Dos",
"roles": [
{
"name": null,
"id": 361, // this is a relationship table id, not a Roles table id
"__typename": "Role"
}
],
"__typename": "User"
}
},
"loading": false,
"networkStatus": 7,
"stale": false
}
I’m still pretty new to Redwood and Prisma, so I’m still not clear where in my code I’m messing up. All examples I’ve seen for this type of relationship mapping Just Work™ .
Here are the relevant bits of my code (click triangle to expand):
schema.prisma
model User {
@@map(name: "users")
id Int @default(autoincrement()) @id
// has_many :assignments
roles. RolesOnUsers[] @relation(name: "toUser")
}
model Role {
@@map(name: "roles")
id Int @default(autoincrement()) @id
// has_many :assignments
// has_many :users, :through => :assignments
users RolesOnUsers[] @relation(name: "toRole")
name String?
}
model RolesOnUsers {
@@map(name: "assignments")
id Int @default(autoincrement()) @id
// belongs_to :user
user User @relation(name: "toUser", fields: [userId], references: [id])
userId Int @map("user_id")
// belongs_to :role
role Role @relation(name: "toRole",fields: [roleId], references: [id])
roleId Int @map("role_id")
}
users.js (service)
import { db } from 'src/lib/db'
export const users = () => {
return db.user.findMany({ take: 50 })
}
export const user = ({ id }) => {
return db.user.findOne({
where: { id },
})
}
export const User = {
roles: (_obj, { root }) =>
// db.user.findOne({ where: { id: root.id } }).roles(),
db.user.findOne({ where: { id: root.id } }).roles(),
}
users.sdl.js
export const schema = gql`
type User {
id: Int!
roles: [Role]
}
type Query {
users: [User!]!
user(id: Int!): User
}
`
And here are the GraphQL query and response:
GraphQL query on GraphiQL
query FIND_USER_BY_ID($id: Int!) {
user: user(id: $id) {
firstName
lastName
roles {
name
id
}
}
}
GraphQL response
{
"data": {
"user": {
"firstName": "Digitador",
"lastName": "Dos",
"roles": [
{
"name": null,
"id": 361,
"__typename": "Role"
}
],
"__typename": "User"
}
},
"loading": false,
"networkStatus": 7,
"stale": false
}
Unfortunately I can’t modify the database at all so I can’t use underscored implicit relationship tables as Prisma does, but I feel like this should be doable. Not sure if there’s anything special I need to be doing in the service side of things, or if it’s a schema/GraphQL issue.
I’m hoping you guys can give a recent Rails convert some guidance?
Thanks!
Simon