to_jsonメソッドの注意点
ActiveSupportには、to_json
という便利なメソッドがあります。
Railsで開発しているときに使う場面としては、DBから取得したレコードをAPIのレスポンスとして返す場合があります。
しかし、devise を認証に使っているサービスなどで、何も考えずに、user.to_json
のようなコードを書いてしまうと、以下のようなJSONがレスポンスに返されてしまいます。
コピー {
\ "id\":1111111,
\"email\":\"xxxxx@yyyyy.zzzzz\",
\"created_at\":\"2023-09-06T14:29:22.188+09:00\",
\"updated_at\":\"2023-09-06T15:29:38.638+09:00\",
\"last_sign_in_user_agent\":\"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/116.0.0.0 Safari/537.36\"
}
出力される属性がこれだけなら、それほど大きな問題がないようにも見えます。しかし、userモデルには、サービスへの機能追加に伴ってプライベートな情報が追加されやすいため、そういった情報がto_json
メソッドで出力されてしまったり、あるいは、本人以外のuser情報も併せて一覧で取得するような場合に、他人の email
やプライベートな情報が含まれてしまったりすると個人情報の漏洩問題になる可能性があります。
したがって、to_json
メソッドで出力する属性を制限するべきかどうかについて、注意し検討する必要が出てきます。
解決策
幸い、to_json
メソッドでは、オプションを指定することで、出力を絞り込むことができます。
option 内容 特定のassociation(has_manyやbelongs_toで指定しているような別のモデル)を出力に含めたい場合に使います。
特定のメソッドを呼び出した結果を含めたい場合に使います。
methodsオプションは、特定の属性を絞り込むというよりかは、追加で情報を出力する用途に使いますが、関連する機能なので併せて説明します。
以下、各オプションの使用例を示します。
only
さきほどの例で、only
を指定すると、以下のように指定した属性だけが出力されます。
コピー > user.to_json(only: [:id])
=> "{\"id\":1111111}"
except
さきほどの例で、except
を指定すると、以下のように指定した属性以外のものが出力されます(※)。
※読みやすくするために、改行を入れています。
コピー > user.to_json(except: [:email])
=>
{
\"id\":1111111,
\"created_at\":\"2023-09-06T14:29:22.188+09:00\",
\"updated_at\":\"2023-09-06T15:29:38.638+09:00\",
\"last_sign_in_user_agent\":\"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/116.0.0.0 Safari/537.36\"
}
include
さきほどの例で、include
を指定すると、以下のように指定したassociationの属性も併せて出力されます(※)。
※ some_associationという属性がある前提です。
コピー > user.to_json(include: [:some_association])
=>
{
\ "id\":1111111,
\"created_at\":\"2023-09-06T14:29:22.188+09:00\",
\"updated_at\":\"2023-09-06T15:29:38.638+09:00\",
\"last_sign_in_user_agent\":\"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/116.0.0.0 Safari/537.36\",
\"some_association\":{\"id\":222222,\"name\":\"名前1\"}
}
なお、includeで指定したassociation内でも出力する属性を制限したい場合は、以下のように書けます。
コピー > user.to_json(include: [{some_association : {only : :name}}])
=>
{
\ "id\":1111111,
\"email\":\"xxxxx@yyyyy.zzzzz\",
\"created_at\":\"2023-09-06T14:29:22.188+09:00\",
\"updated_at\":\"2023-09-06T15:29:38.638+09:00\",
\"last_sign_in_user_agent\":\"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/116.0.0.0 Safari/537.36\",
\"some_association\":{\"name\":\"名前1\"}
}
methods
さきほどの例で、methods
を指定すると、以下のように指定したメソッドの呼び出し結果も併せて出力されます(※)。
※some_methodというメソッドがある前提です。
コピー > user.to_json(methods: [:some_method])
=>
{
\"id\":1111111,
\"email\":\"xxxxx@yyyyy.zzzzz\",
\"created_at\":\"2023-09-06T14:29:22.188+09:00\",
\"updated_at\":\"2023-09-06T15:29:38.638+09:00\",
\"last_sign_in_user_agent\":\"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/116.0.0.0 Safari/537.36\",
\"some_method\": \"some_output\"}
}
本サイトの更新情報は、X(旧Twitter)の株式会社プレセナ・ストラテジック・パートナーズエンジニア公式 で発信しています。ご確認ください。