Ruby On Rails and GraphQL Part 2

Aaron Schuyler
3 min readDec 23, 2020

--

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!

--

--