きっかけ
親子関係のあるデータについて、親のエンドポイントにアクセスした時には親のデータとその親に紐づく子のデータを含めたい、そして子のデータだけにもアクセスできるようにしたい、ただ jbuilder を親と子で同じ内容を書くのが DRY じゃなくてダサい。json.partial!
が使えそうだけど、他のディレクトリにあるテンプテートはどうやって呼び出すのかがググり力不足でわからず。
めっちゃ簡単なモデル
parent.rb
class Parent < ApplicationRecord
has_many :children
end
child.rb
class Child < ApplicationRecord
belongs_to :parent
end
ディレクトリ構成
views/
|-parents/
| |-show.jbuilder
|-children/
|-_detail.jbuilder
|-show.jbuilder
parents/show.jbuilder
で children/_detail.jbuilder
を呼び出したい
10分ググり続けてもマニュアルが見当たらなかったのでソースコードを読んだ。
https://github.com/rails/jbuilder/blob/ad01e8496e1b4c537314a2b74a76dfb4594f67bf/lib/jbuilder/jbuilder_template.rb
上記クラスの _render_explicit_partial
メソッドに、テンプレートのviewから見たパスと、渡したい変数を locals で渡せれば良さそう。
jbuilder_template.rb
def partial!(*args)
if args.one? && _is_active_model?(args.first)
_render_active_model_partial args.first
else
_render_explicit_partial(*args)
end
end
# 中略
private
# 中略
def _render_explicit_partial(name_or_options, locals = {})
case name_or_options
when ::Hash
# partial! partial: 'name', foo: 'bar'
options = name_or_options
# 以下略
コメントにあるように json.partial! partial: 'name', foo: 'bar'
の形で使ってあげれば良さそう。
結論
こう書きました。
parents/show.jbuilder
json.id(@parent.id)
json.set! :children do
json.array!(@parent.children) do |child|
json.partial! partial: 'children/detail', locals: { child: child }
end
end
children/_detail.jbuilder
json.id(child.id)
んでAPI叩く。
curl -X GET http://localhost:3000/parent/1
{
"id": 1,
"children": [
{ "id": 1 },
{ "id": 2 }
]
}
動きました:)
追記
普通にreadme.md に書いてありました…ググり力が足りなすぎる…