3
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

【Rails】ActiveModel::Serializersでネストを明示したりしなかったり

Last updated at Posted at 2020-11-07

なにこれ

RailsのActiveModel::Serializersを使っている時に、
2つのjsonオブジェクトをrenderしたい時、片方だけにネストさせたり、あえてネストさせない方法を
自分への備忘録として書く記事です。

この記事で得られること

Railsのメソッド内で下記みたいなコードを書く時に、ネストさせたいオブジェクトを
好きなようにいじくる方法を知れます。

users_controller.rb
render json: { hoge: hoge, fuga: fuga }, include: :piyo

答え

Railsのas_jsonメソッドを使えば解決する!

環境

Ruby 2.6
Rails 6.0
active_model_serializers 0.10.10

前提

下記4つのモデルがあります。

  • user.rb
  • facility.rb
  • product.rb

userとfacilityは1:N、
productモデルとuserモデルはアソシエーション組んでません。
今回はカラムは必要ないので省略。

user.rb
class User < ApplicationRecord
  belongs_to :facility
end
facility.rb
class Facility < ApplicationRecord
  has_many :users
end
product.rb
class Product < ApplicationRecord
  # アソシエーションなし
end

状況

users#showアクションを呼び出した時に、
userとproductsオブジェクトの2つをrenderする必要があり、
userのネストしたオブジェクトも取り出す必要がある。

実際に遭遇したエラー

users_controller.rb
  def show
    user = User.find(params[:id])
    products = Product.all
    render json: { user: user, products: products }, include: ['facility']
  end

上記のコードで書いてレスポンスを受け取る時、下記のエラーが発生します!

NoMethodError (undefined method `facility' for #<Product:0x00007fed8d885518>):

renderするjsonオブジェクトにincludeすることを明示しました。
でも、上記の書き方だと
userオブジェクトとproductsオブジェクトの両方にfacilityがネストされてしまう。
productsモデルとfacilityモデルはアソシエーションを組んでいないので、
当然そんなメソッド(モデル?)はないので、
Railsは「facility?そんなメソッド知らないよ!」と言ってしまう。

じゃあどうするか

結論

変数を代入するタイミングでas_jsonメソッドを使ってjson整形して、
includeでfacilityモデルをネストすることを明示する。

users_controller.rb
  def show
    user = User.find(params[:id]).as_json(include: 'facility')
    products = Product.all
    render json: {user: user, products: products}, status: :ok
  end

こうすることで、変数userだけにfacilityモデルをネストすることができます。

応用編

もし、「facilityモデルが不要なので、facilityモデルをネストさせないでデータを取得したい!」って時は、こうする。

users_controller.rb
  def show
    user = User.find(params[:id]).as_json
    products = Product.all
    render json: {user: user, products: products}, status: :ok
  end

記述方法は分かったけど、正直なぜネストされないでjsonが整形されるかは分からないです。
勝手にネストされるときとネストされない時がある?
ここは要検証

おまけ:as_jsonのオプションはActiveModel as_json のオプション一覧という記事で詳しく解説してくれています。ありがたや〜

Railsのas_jsonメソッドの公式ドキュメントはこちら:https://railsdoc.com/page/as_json

3
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?