Ruby On Rails and GraphQL Part 2
As a second installment to my last post, here is a guide on how to use GraphQL to get all posts by a user and how to get all comments with our post.
First off, we need to create a comments table:
rails g resource Comment content:text user:references post:referencesrails db:migrate
Now we need to go in and add the has_many part of the relationships with the posts and users:
# /app/models/post.rb class
Post < ApplicationRecord
belongs_to :user
has_many :comments
end #app/models/user.rb
class User < ApplicationRecord
has_many :posts
has_many :comments
end
Next we need to run a GraphQL generator:
rails g graphql:object comment
After that generator, we should be able to see a new type in /app/graphql/types named comment_type.rb. Let’s edit post_type.rb to add our comments to it.
# /app/graphql/types/post_type.rb
module Types
class PostType < Types::BaseObject
field :id, ID, null: false
field :title, String, null: true
field :content, String, null: true
field :user, Types::UserType, null: false
# new code
field :comments, [Types::CommentType], null: true
# end new code
field :created_at, GraphQL::Types::ISO8601DateTime, null: false
field :updated_at, GraphQL::Types::ISO8601DateTime, null: false
end
end
The brackets around the type tell GraphQL that we want an array of comments, not just one, which makes sense with our has_many relationship.
If you followed the last guide, we generated some posts already, so lets add some comments to that. In the console run the following:
rails c
Comment.create(post_id: 1, content: ‘this is a comment’, user_id: 1)
Comment.create(post_id: 2, content: ‘this is a comment’, user_id: 1)
Comment.create(post_id: 1, content: ‘this is another comment by a different user’, user_id: 2)
Now if you submit the following GraphQL query:
{
posts {
title,
content,
comments {
content
}
}
}
You should get this result!
Now let’s add the username to those comments. Keep in mind that the following will create an N+1 situation for you. There are ways to help with this, and I may cover those in future blog posts, but it is beyond the scope of this article.
It’s simply a matter of adding the user type to our comment type:
module Types
class CommentType < Types::BaseObject
field :id, ID, null: false
field :content, String, null: true
# replace the user_id field with the following
field :user, Types::UserType, null: false
field :post_id, Integer, null: false
field :created_at, GraphQL::Types::ISO8601DateTime, null: false
field :updated_at, GraphQL::Types::ISO8601DateTime, null: false
end
end
That’s it! Try the following query out now:
{
posts {
title,
content,
comments {
content,
user {
username
}
}
}
}
And here is the result:
Let’s get all the posts by a user. This one is easy too!
Change your query type file to the following:
module Types
class QueryType < Types::BaseObject
field :users, [Types::UserType], null: false field :posts, [Types::PostType], null: false do
argument :user_id, ID, required: false
end field :post, Types::PostType, null: false do
argument :id, ID, required: true
end def post(id:)
Post.find(id)
end def posts(args)
if args
Post.where(args)
else
Post.all
end
end def users
User.all
end
end
end
If you submit the following query, you should see the posts by first_user:
query ($userId: ID) {
posts (userId: $userId) {
title,
content,
comments {
content,
user {
username
}
}
}
}
With variables set as:
{
"userId": 1
}
Good job, you did it! Happy Coding!