この記事について
RailsのActiveViewではブラウザに表示させるHTML形式以外に、JSONでのデータ出力などが簡単にできます。
しかし、簡単なはずのJSONデータ出力にハマった経験を共有させていただきたいと思います。
jbuilderテンプレートを置いたのに、レンダリングに使われない??
Railsガイド-Action Viewの概要にしたがって、
jbuilderのテンプレートファイルを置いたのに、以下のようにテンプレートが読まれた結果にならず、どハマりしました。
前提
この記事は、以下のようなアプリケーション構成を前提に記載させていただきます。
| 項目 | 値 |
|---|---|
| アプリケーション名 | apptest |
| モデル名 | sample |
| view名 | index |
| モデルの属性 | title:string, description:string |
テンプレートファイルの内容
モデルの内容に関係のないものを出力する中身のない簡単なテンプレートを作りました。
※ここでは、apptest/app/views/samples/index.json.jbuilderというファイル名で記載しています。
json.test("hoge")
予期していた結果はこちら。
前出のRailsガイドによれば、apptest/samples/index.jsonにアクセスすれば以下のようなご回答をいただけるものと思っていたのですが。。
{
"test": "hoge"
}
実際の結果
しかし、実際に取得できたのは以下のようにSampleモデルのデータそのもの。
[{"id":1,"title":"test","description":"sample","created_at":"2020-05-06T05:54:20.885Z","updated_at":"2020-05-06T05:54:20.885Z"}]
原因
scaffoldで生成されたコントローラは以下のような内容になりますが、
このままだと、変数@samplesの内容をjson形式にしたものがレンダリングされてしまうためでした。
class SamplesController < ApplicationController
def index
@samples = Sample.all();
respond_to do | format |
format.html # index.html.erb
format.xml { render xml: @samples }
format.json { render json: @samples } # <== ここです!
end
end
end
解決!!
renderさんに、「ちゃんと"index"というテンプレートがあるんだよ」と教えてあげます。
class SamplesController < ApplicationController
def index
@samples = Sample.all();
respond_to do | format |
format.html # index.html.erb
format.xml { render xml: @samples }
format.json { render :index } # renderにindexのテンプレートを使うように指定
end
end
end
どう言うことか?
自分の理解不足により、家で2時間くらい悩み続けてしまいましたが、
render json: や render xml:という書き方は、後ろに指定した変数の内容を指定した形式に変換して出力するという意味になるんですね。
render テンプレート名とすることで、指定したテンプレートを使用した出力を行ってくれます。
ちなみに、今回の場合は以下の書き方でもうまく動きました。
よく考えたら、デフォルトではコントローラのメソッド名(ここではindex)と同じ名前のテンプレートを勝手に使ってくれるんでしたね。
class SamplesController < ApplicationController
def index
@samples = Sample.all();
respond_to do | format |
format.json
end
end
end