🪓

【Rails】to_jsonやas_jsonで特定の属性だけをJSON化したい

2023/03/01に公開

特定の値だけを変換したい時に便利なオプション

except, only

モデルのインスタンスをJSONに変換する際に便利なto_jsonやas_json。
以下のようにto_jsonはJSON形式の文字列を、as_jsonはJSON形式のHashを返してくれる。

hoge.to_json
=> "{\"id\":1,\"title\":\"タイトル\",\"content\":\"サンプルテキストです\",\"created_at\":\"2023-02-28T14:43:37.920Z\",\"updated_at\":\"2023-02-28T14:43:37.920Z\"}"

hoge.as_json
=> {"id"=>1,
 "title"=>"タイトル",                                                  
 "content"=>"サンプルテキストです",                                    
 "created_at"=>"2023-02-28T14:43:37.920Z",                             
 "updated_at"=>"2023-02-28T14:43:37.920Z"}  

ただ、APIなどで単純にインスタンスの情報だけを渡したい時などには、timestampが不要になったり特定の属性だけを変換したくなる。
そんな時に便利なのがexceptおよびonlyのオプション。
以下のように欲しい属性や不要な属性を指定することで、任意の情報のみをJSON形式に変換できる。

# except: 指定した属性を除いてJSON形式に変換する
hoge.as_json(except: %i[created_at updated_at])
=> {"id"=>1, "title"=>"タイトル", "content"=>"サンプルテキストです"}

# only: 指定した属性だけをJSON形式に変換する
hoge.as_json(only: :title)
=> {"title"=>"タイトル"}

おまけ:その他のオプション

root

root: trueとすることで、オブジェクトにちなんだ名前のルートノード(以下では"hoge")を追加する。
引数に値を渡すことで、任意の名前のルートノードを追加することも可能。

 hoge.as_json(root: true, except: %i[created_at updated_at])
=> {"hoge"=>{"id"=>1, "title"=>"タイトル", "content"=>"サンプルテキストです"}}

hoge.as_json(root: 'fuga', except: %i[created_at updated_at])
=> {"fuga"=>{"id"=>1, "title"=>"タイトル", "content"=>"サンプルテキストです"}}
irb(main):005:0> 

methods

インスタンスに対してメソッドを呼び出し、その戻り値を格納する。

hoge.as_json(methods: :greet, except: %i[created_at updated_at])
=> {"id"=>1, "title"=>"タイトル", "content"=>"サンプルテキストです", "greet"=>"こんにちは!"}

include

指定した関連モデルを含めたJSONを返す。
関連モデルに対してさらにオプションを指定することもできるため、これを利用してさらにネストしたモデルを取得することもできる。

user.as_json(include: :posts, except: %i[created_at updated_at])
=> 
{"id"=>1,
 "name"=>"山田太郎",
 "email"=>"tarou@example.com",
 "posts"=>[{"id"=>1, "title"=>"タイトル", "content"=>"サンプル文章です", "created_at"=>"2023-02-28T15:42:16.209Z", "updated_at"=>"2023-02-28T15:42:16.209Z", "user_id"=>1}]}
 
 # postsのtimestampも要らん場合
 user.as_json(include: { posts: { except: %i[created_at updated_at] } }, except: %i[created_at updated_at])
=> {"id"=>1, "name"=>"山田太郎", "email"=>"tarou@example.com", "posts"=>[{"id"=>1, "title"=>"タイトル", "content"=>"サンプル文章です", "user_id"=>1}]}

https://api.rubyonrails.org/classes/ActiveModel/Serializers/JSON.html#method-i-as_json

割と使い所の多そうな便利なオプションが充実している印象。

Discussion