Railsでは通常のページにアクセスすれば、対象のビューファイルがHTML形式でブラウザに表示されます。
ですが、RailsをDB操作などバックエンドとして使う場合など、他のアプリケーションがアクセスしたときにDBや処理したデータをJSON形式で受け取る(APIとして利用する)ことができるととても便利な場合があります。
Railsには、Jbuilder(ジェービルダー)という、JSON形式のデータを返すことができるとても便利なgemがデフォルトで入っていいます。
あまり聞きなれない名前ですが、使い方は簡単です。
ここでは、Jbuilderとは何か?や実際の使い方について解説しています。
Jbuilderとは?
jbuilderとは、簡単に言うと、ビューファイルのJSON版で、そのファイルにアクセスするとJSON形式のデータを返します。
scaffoldを実行すると、各ビューファイルに対応するJbuilderファイルを自動で生成してくれます。
Jbuilderのファイルとアクセス方法
Jbuilderのファイルの拡張子は、.json.jbuilder
になります。
ファイルの扱い方は、ビューファイル(.html.erb)と並列として扱うと考えるとわかりやすいです。
ファイル名(〇〇.json.jbuilder)やファイル作成場所、ファイルへのアクセスの仕方はビューファイルと同様になります。
項目 | 書き方 |
---|---|
拡張子 | .json.jbuilder |
設置場所 | ビューファイルと同じ |
ファイル名 | ビューファイルと合わせる。〇〇.json.jbuilder |
アクセス | ビューファイルのURIの末尾に .json をつける |
例えば、rails g controller projects index
で、projectsコントローラとindexアクションを生成すると、viewsディレクトリ配下に、対応するディレクトリとビューファイルが生成されます。
views > projects > index.html.erb
またデフォルトのルーティングでは、index.html.erbを開くには、/projects/index にアクセスします。
Jbuilderを使ってJSONを返すデータにアクセスしたい場合は、ビューファイルと同じ場所に拡張子を.json.jbuilderにしたファイルを置き、中にコードを記述します。
そのファイルにアクセスするときは、URIの末尾に.jsonをつけます。これで完成です。
app
|
|- views
|
|- projects
|- index.html.erb
|- index.json.jbuilder
上記の場合、https://example.com/projects/index.json にアクセスすればjbuilderのファイルにアクセスすることができます。
Jbuilderの書き方
JbuilderファイルにアクセスしてJSON形式のデータを返すには決まった書き方をする必要があります。
キーと値のセットを作る
一番の基本となるキーと値を指定するには、json.set!
を使ってシンボルでキー名を指定する方法と、キーと値を直接指定する方法があります。
以下の2つは同じ処理になります。
json.set! :キー名, 値
json.キー名 値
実例
json.set! :名前, "テスト"
json.set! :年齢, "24"
json.性別 "女性"
json.身長 "160cm"
↓ ページにアクセスした結果(出力)
{"名前":"テスト","年齢":"24","性別":"女性","身長":"160cm"}
json.キー名とjson.set!の違いは、キー名を動的に指定できるかどうかです。
json.キー名とjson.set!の違いは、キー名を動的に指定できるかどうかです。
柔軟性が高いのはjson.set!です。json.キー名は動的にキー名を指定することができません。
json.set!はキー名を動的に指定できる
@client = { id:1, name:"test", age:'24' }
@client.each do |key, value|
json.set! key, value
end
出力結果は、{"id":1,"name":"test","age":"24"}
になります。
json.キー名はキー名を指定できない
@client = { id:1, name:"test", age:'24' }
@client.each do |key, value|
json.key value
end
出力結果は、{"key":"24"}
になります。 idやnameのデータがありません。
キーと値のセットにキー名をつける
キーと値のセットをひとまとめにして、キー名をつけるにはjson.set! :キー名 do
を使います。(※キー名には「:」を忘れずに)
こちらもjson.キー名
を使った書き方もできます。以下の2つは同じ処理になります。
json.set! キー名 do
指定したキー名の中に入れるデータ
end
json.キー名 do
指定したキー名の中に入れるデータ
end
実例
json.set! :ユーザー1 do
json.set! :名前, "テスト"
json.set! :年齢, "24"
end
json.ユーザー2 do
json.名前 "テスト2"
json.年齢 "32"
end
↓ ページにアクセスした結果(出力)
{"ユーザー1":{"名前":"テスト","年齢":"24"},"ユーザー2":{"名前":"テスト2","年齢":"32"}}
マージする
あるキーの中にデータを追加(マージ)するには、ハッシュ(変数)とjson.merge!
を使います。
変数名 = { オブジェクト }
json.キー名 do
json.キー名 "値"
json.marge! 変数名
end
実例
books = { "本1": { "カテゴリー": "マンガ", "価格":450 } }
json.ユーザー do
json.名前 "ユーザー1"
json.set! :年齢, "24"
json.merge! books
end
↓ ページにアクセスした結果(出力)
{"ユーザー":{"名前":"ユーザー1","年齢":"24","本1":{"カテゴリー":"マンガ","価格":450}}}
nilのデータを無視する
値がnilやセットされていないデータを除外したい場合はjson.ignore_nil!
を記述します。
json.ignore_nil!
nilを除外したい処理
実例
json.ignore_nil!
books = { "本1": { "カテゴリー": "マンガ", "価格":450 }, "本2": nil }
json.ユーザー do
json.名前 "ユーザー1"
json.set! :年齢, "24"
json.set! :性別
json.set! :身長, nil
json.merge! books
end
↓ ページにアクセスした結果(出力)
{"ユーザー":{"名前":"ユーザー1","年齢":"24","本1":{"カテゴリー":"マンガ","価格":450},"本2":null}}
jbuilderを使って生成したオブジェクトのnilは削除されますが、変数の中に定義したnilはそのまま出力されます(出力結果はnullになります)
モデルへの適用
jbuilderの便利なところは、モデル経由で取得してきたデータ(モデルのインスタンス)にも使えるところです。
例えば、usersテーブルからすべてのデータを取得する場合、User.all が使えます。このUser.allをJSON形式で出力することができます。
モデル経由でDBを操作する方法については下記をご参考ください。
【Rails】モデルを使ってテーブルの一覧表示やデータ追加・更新・変更・削除する方法(データベース操作)
すべてのデータを抜き出す
テーブルから取得してきた全てのデータをJSON形式で返す方法は大きく3つあります。
- json.array!を使う
- キー名をつけて抜き出す
▼例:User.allの実行結果
irb(main):001:0> User.all
User Load (0.9ms) SELECT "users".* FROM "users" /* loading for inspect */ LIMIT $1 [["LIMIT", 11]]
=> #<ActiveRecord::Relation [#<User id: 1, name: "test1", age: 24, created_at: "2021-07-29 04:38:52.761212000 +0000", updated_at: "2021-07-29 04:38:52.761212000 +0000">, #<User id: 3, name: "test2", age: 25, created_at: "2021-07-30 23:18:28.177139000 +0000", updated_at: "2021-07-30 23:18:28.177139000 +0000">, #<User id: 4, name: "test3", age: 28, created_at: "2021-07-30 23:19:35.242567000 +0000", updated_at: "2021-07-30 23:19:35.242567000 +0000">, #<User id: 5, name: "test4", age: 30, created_at: "2021-07-30 23:19:44.976725000 +0000", updated_at: "2021-07-30 23:19:44.976725000 +0000">, #<User id: 6, name: "test5", age: 32, created_at: "2021-07-30 23:19:54.558410000 +0000", updated_at: "2021-07-30 23:19:54.558410000 +0000">]>
json.array!を使う
最も簡単な方法は、json.array!を使う方法です。後ろにモデルクラス名.all
で取得してきたデータを指定すれば、すべてのデータをJOSN形式で返すことができます。
※コンパイル後の最上位は配列になります。
変数名 = モデルクラス名.all
json.array! 変数名
ひとまとまりのデータにキー名をつデータ全体にキー名をつける場合は、json.キー名 do endの中で回します。
変数名 = モデルクラス名.all
json.キー名 do
json.array! 変数名
end
実例
@users = User.all
json.array! @users
↓ ページにアクセスした結果(出力)
[{"id":1,"name":"test1","age":24,"created_at":"2021-07-29T04:38:52.761Z","updated_at":"2021-07-29T04:38:52.761Z"},{"id":3,"name":"test2","age":25,"created_at":"2021-07-30T23:18:28.177Z","updated_at":"2021-07-30T23:18:28.177Z"},{"id":4,"name":"test3","age":28,"created_at":"2021-07-30T23:19:35.242Z","updated_at":"2021-07-30T23:19:35.242Z"},{"id":5,"name":"test4","age":30,"created_at":"2021-07-30T23:19:44.976Z","updated_at":"2021-07-30T23:19:44.976Z"},{"id":6,"name":"test5","age":32,"created_at":"2021-07-30T23:19:54.558Z","updated_at":"2021-07-30T23:19:54.558Z"}]
キー名をつけて抜き出す
モデルクラス名.all
で取得してきたデータにキー名をつけてJSON形式で返す方法です。(※キー名の中は配列になります)
1行ずつのデータをハッシュとして取り出し、json.merge!で結合します。
インスタンス変数 = モデルクラス名.all
json.キー名 インスタンス変数 do |変数名|
json.merge! 変数名
end
出力は キー名:[ {カラム名1:値1,,,,,},{},{} ]
のようになります。
実例
@users = User.all
json.users @users.each do |user|
json.merge! user
end
↓ ページにアクセスした結果(出力)
{"users":[{"id":1,"name":"test1","age":24,"created_at":"2021-07-29T04:38:52.761Z","updated_at":"2021-07-29T04:38:52.761Z"},{"id":3,"name":"test2","age":25,"created_at":"2021-07-30T23:18:28.177Z","updated_at":"2021-07-30T23:18:28.177Z"},{"id":4,"name":"test3","age":28,"created_at":"2021-07-30T23:19:35.242Z","updated_at":"2021-07-30T23:19:35.242Z"},{"id":5,"name":"test4","age":30,"created_at":"2021-07-30T23:19:44.976Z","updated_at":"2021-07-30T23:19:44.976Z"},{"id":6,"name":"test5","age":32,"created_at":"2021-07-30T23:19:54.558Z","updated_at":"2021-07-30T23:19:54.558Z"}]}
指定したカラムのみ抜き出す
テーブルの指定したカラムのデータのみをJSON形式で返す方法は大きく3つあります。
- json.array!を使う(最上位が配列になります)
- キー名をつけて抜き出す
json.array!を使う
最も簡単な方法は、json.array!を使う方法です。後ろにモデルクラス名.all
で取得してきたデータを指定し、カンマで区切って、:カラム名 を指定します。
※コンパイル後の最上位は配列になります。
変数名 = モデルクラス名.all
json.array! 変数名, :カラム名1, :カラム名2,,,
データ全体にキー名をつける場合は、json.キー名 do endの中で回します。
変数名 = モデルクラス名.all
json.キー名 do
json.array! 変数名, :カラム名1, :カラム名2,,,
end
実例
@users = User.all
json.array! @users, :id, :name
↓ ページにアクセスした結果(出力)
[{"id":1,"name":"test1"},{"id":3,"name":"test2"},{"id":4,"name":"test3"},{"id":5,"name":"test4"},{"id":6,"name":"test5"}]
キー名をつけて抜き出す
モデルクラス名.all
で取得してきたデータにキー名をつけてJSON形式で返す方法です。(※キー名の中は配列になります)
ブロックの中で欲しいカラムのみを指定します。
インスタンス変数 = モデルクラス名.all
json.キー名 インスタンス変数 do |変数名|
json.カラム名1 変数名.カラム名1
json.カラム名2 変数名.カラム名2
・
・
end
出力は {キー名:[ {カラム名1:値1,,,,,},{},{} ]}
のようになります。
実例
@users = User.all
json.users @users do |user|
json.id user.id
json.name user.name
end
↓ ページにアクセスした結果(出力)
{"users":[{"id":1,"name":"test1"},{"id":3,"name":"test2"},{"id":4,"name":"test3"},{"id":5,"name":"test4"},{"id":6,"name":"test5"}]}
すべての行データJSONにする
対象のデータのIDを指定した場合など、必要なデータ行のみが含まれたデータをJSON形式に変換する方法にはattributes
とjson.merge!
を使います。
インスタンス変数 = モデルクラスで取得したオブジェクトデータ.attributes
json.キー名 do
json.merge! インスタンス変数
end
出力は {キー名:[ {カラム名1:値1,,,,,},{},{} ]}
のようになります。
実例
@user = User.first.attributes
json.user do
json.merge! @user
end
↓ ページにアクセスした結果(出力)
{"user":{"id":1,"name":"test1","age":24,"created_at":"2021-07-29T04:38:52.761Z","updated_at":"2021-07-29T04:38:52.761Z"}}
カラムを指定して行のデータを抜き出す
モデル経由で取得した行データのうち必要なカラムのみを指定してJSONに変換するにjson.extract!を使います。
インスタンス変数 = モデルクラスで取得したオブジェクトデータ
json.extract! インスタンス変数, :カラム名1, :カラム名2,,,
実例
@user = User.first
json.extract! @user, :id, :name, :age
↓ ページにアクセスした結果(出力)
{"id":1,"name":"test1","age":24}
パーシャルを使う
ビューのパーシャル(部分テンプレート)のように、.json.builderもパーシャルを作成することができます。
ビューのパーシャルと同じくファイル名の冒頭にアンダースコアを付けます。(例: _user.json.builder)
パーシャルを使う目的
メインの .json.builderファイルにはモデルを使ったデータの取得と、パーシャルの指定のみを記述します。
そして対象のパーシャルでJSONで表示するための処理を記述します。
こうすることで、指定するパーシャル名を変更するだけで、出力するJSONデータを変えることができます。
パーシャルの指定方法
パーシャルを指定するときは、allメソッドで取得したActiveRecord::Relationのデータと、findやfind_byで取得したオブジェクト型のデータで呼び出し方が異なります。
allメソッドで取得したデータの場合
クラスインスタンス = モデルクラス.all
json.array! クラスインスタンス, partial: 'ディレクトリ名/パーシャル名', as: :渡すデータのキー名
- whereメソッドで取得したデータも使えます。
- パーシャルファイルが同じ階層にある場合はディレクトリ名を省略できます。
- アクセスするURIが一覧表示ページ(indexアクション)と一致する場合は、インスタンスの代入式を省略できます。
例: Usersコントローラのindexアクションに対応する /users.json にアクセスする場合は以下のようにも記述できます。
json.array! @users, partial: "user", as: :user
@usersが、@users = User.allになっています。
findやfind_byメソッドで取得したデータの場合
クラスインスタンス = モデルクラス.find(1)
json.partial! 'ディレクトリ名/パーシャル名', 渡すデータのキー名: クラスインスタンス
- メソッドは一例です。
- パーシャルファイルが同じ階層にある場合はディレクトリ名を省略できます。
- アクセスするURIが一覧表示ページ(showアクション)と一致する場合は、インスタンスの代入式を省略できます。
例: Usersコントローラのshowアクションに対応する /users/:id.json にアクセスする場合は以下のようにも記述できます。
json.partial! "users/user", user: @user
@usersが、@users = User.allになっています。
パーシャル使用の実例
usersディレクトリ配下に index.json.jbuilderと、show.json.jbuiilderを作成し、パーシャルとして_user.json.jbuilderを呼び出す場合は次のようになります。
(rails g scaffold user
を実行すると自動生成される状態です)
ディレクトリ構造
app
|
|- views
|
|- users
|- index.json.jbuilder
|- index.html.erb
|- show.json.jbuilder
|- show.html.erb
|- _user.json.jbuilder
index.json.jbuilder
json.array! @users, partial: "users/user", as: :user
show.json.jbuiilder
json.partial! "users/user", user: @user
_user.json.jbuilder
json.extract! user, :id, :name, :age, :created_at, :updated_at
json.url user_url(user, format: :json)
json.extract!
で、カラムを指定してデータを取得しています。
json.url user_url(user, format: :json)
は、キー名が「url」値が「user_url(user, format: :json)」のデータです。
"url":"http://localhost:3001/users/3.json"
のようなキーと値のセットになります。
出力結果
上記設定で、それぞれ、/users.jsonと、/users/1.jsonにアクセスするとWEBページの表示は次のようになります。
▼/users.json
[{"id":1,"name":"test1","age":24,"created_at":"2021-07-29T04:38:52.761Z","updated_at":"2021-07-29T04:38:52.761Z","url":"http://localhost:3001/users/1.json"},{"id":3,"name":"test2","age":25,"created_at":"2021-07-30T23:18:28.177Z","updated_at":"2021-07-30T23:18:28.177Z","url":"http://localhost:3001/users/3.json"},{"id":4,"name":"test3","age":28,"created_at":"2021-07-30T23:19:35.242Z","updated_at":"2021-07-30T23:19:35.242Z","url":"http://localhost:3001/users/4.json"},{"id":5,"name":"test4","age":30,"created_at":"2021-07-30T23:19:44.976Z","updated_at":"2021-07-30T23:19:44.976Z","url":"http://localhost:3001/users/5.json"},{"id":6,"name":"test5","age":32,"created_at":"2021-07-30T23:19:54.558Z","updated_at":"2021-07-30T23:19:54.558Z","url":"http://localhost:3001/users/6.json"}]
▼ /users/1.json
{"id":1,"name":"test1","age":24,"created_at":"2021-07-29T04:38:52.761Z","updated_at":"2021-07-29T04:38:52.761Z","url":"http://localhost:3001/users/1.json"}