September 01, 2020
今回のゴールは次のようなレスポンスを返すことです。
期待するレスポンス
{
"data": [
{
"id": 1,
"title": "Rails APIについて",
"body": "RailsをAPIモードで作成します。",
"user": "山田太郎"
},
{
"id": 2,
"title": "DockerでRails環境を構築",
"body": "Docker+docker-composeでRails6の環境を構築します。",
"user": "鈴木一郎"
},
{
"id": 3,
"title": "MySQLをRials環境で使う",
"body": "MySQLをRails環境で使用します。",
"user": "田中三郎"
}
]
}
ブログ記事(Post)一覧をGETで取得するする際にブログ記事を書いたユーザー(User)も一緒にJSONで返したいとなったときに使います。
GET
で/posts
にリクエストが来ることを想定しているので、index
でルーティングの設定をします。
Rails.application.routes.draw do
resources :posts, only: %i[index]
end
http://localhost:3000/posts
今回レスポンスとして返したい情報は次のようなposts
テーブルのid
, title
, body
とusers
テーブルのname
のみとします。そのためcreated_at
やupdated_at
、user.id
などは不要な情報なので省きたいです。
UserモデルとPostモデルを作成します。
$ rails g model user name:string
$ rails g model post title:string body:text user:references
$ rails db:migrate
ユーザーは複数のブログ記事を持ち、ブログ記事は1人のユーザーに紐づくため、1対多のリレーションを設定します。
# user.rb(Userモデル)
class User < ApplicationRecord
has_many :posts
end
# post.rb(Postモデル)
class Post < ApplicationRecord
belongs_to :user
end
記事一覧を呼び出したいので、ユーザーとそれに紐づくブログ記事を作成します。
User.create(name: "山田太郎").posts.create(title: "Rails APIについて", body: "RailsをAPIモードで作成します。")
User.create(name: "鈴木一郎").posts.create(title: "DockerでRails環境を構築", body: "Docker+docker-composeでRails6の環境を構築します。")
User.create(name: "田中三郎").posts.create(title: "MySQLをRials環境で使う", body: "MySQLをRails環境で使用します。")
$ rails db:seed
postsコントローラとindexアクションを作成します。
$ rails g controller posts index
まずは、全てのブログ記事を取得して、jsonで返却してみます。
class PostsController < ApplicationController
def index
posts = Post.all
render json: { data: posts }
end
end
Postmanをお持ちでない方はインストールして確認してみてください。
GET: http://localhost:3000/postsとして「send」をクリックします。
すると次のように、ブログ記事一覧が表示されます。
ここでは、posts
テーブルの全てのカラム情報がレスポンスとして帰ってきており、ユーザー名もないので必要な情報を入れて、不要な情報はレスポンスとして帰ってこないようにしたいです。
class PostsController < ApplicationController
def index
posts = User.joins(:posts).select('posts.id, title, body, name AS user')
render json: { data: posts }
end
end
posts
コントローラを上のように修正しました。まずは結果を確認してみましょう。
無事に必要な情報だけを持つ、ブログ記事一覧の取得ができました。
joins
メソッドとselect
メソッドjoins
メソッドは2つのテーブルを内部結合することができるメソッドです。
# モデル.joins(:関連モデル)
User.joins(:posts)
joins、内部結合に関しては次の記事が参考になります。 Rails における内部結合、外部結合まとめ
joins
メソッドを使って、users
テーブルとposts
テーブルを内部結合させます。
内部結合させたあとに、select
メソッドを使って、必要なカラムを指定して取得します。
.select('posts.id, title, body, name AS user')
ここでposts.id
となっているのは、テーブル同士でカラム名が重複している場合、テーブルを指定してid
を取得しています。title
やbody
などの重複していないカラムはそのまま指定することができます。
name AS user
としているのは、users
テーブルのname
カラム名を表示用にuser
と変更しています。posts
テーブルのカラムと一緒に返却しているためname
だと分かりづらいためuser
に変更しています。
SELECT posts.id, title, body, name AS user FROM `users` INNER JOIN `posts` ON `posts`.`user_id` = `users`.`id`