Railsにはas_json
っていう便利なメソッドがある。
irb(main):033:0> user = User.first
=> #<User id: 1, first_name: ‘Tatsuro’, last_name: ‘Baba’, email: ‘harakirisoul@gmail.com’>
irb(main):034:0> user.as_json
=> {"email"=>"user_1@example.com", "first_name"=>"User1", "id"=>1, "last_name"=>"USER1"}
ところが、これだとちょっと使い勝手が悪かったりする場合がある。そんなパターンに遭遇した時の、2つの解決策を紹介する。
Userのインスタンスが特殊なメソッドを持っていたりする場合
例えば、User#full_name
なんてメソッドがあったとして、それを含むjsonを書き出したい、というときに、どうするだろうか。ひとつの解決案は以下の通りだ。
user.as_json.merge(full_name: user.full_name)
多少無理やりだが、まぁHashなのでこれでも出来る。
でもちょっとスマートじゃない。ちょっとどころかだいぶスマートじゃない。ので、メソッド側でちゃんと準備してくれている。以下のように書いてみよう。
irb(main):035:0> user.as_json(methods: 'full_name')
=> {"email"=>"user_1@example.com", "first_name"=>"User1", "id"=>1, "last_name"=>"USER1”, “full_name”=>”User1 USER1”}
なんと便利な。full_name
はattributeじゃないにもかかわらず、他のattributeと同じようにHashに取り込まれている。
必要ないattributeを削りたい場合
例えば、上のUser
モデルのパターンで言うと、「emailは要らない!名前だけくれ!」というパターンがあるかもしれない。
そんなときは、以下のような書き方が出来る。
user.as_json.delete_if{|k, v| k == 'email' }
だが、ダサいしスマートじゃないしメンテコストが高い。そこで、やっぱり用意されているこのオプションを使おう。
user.as_json(except: 'email')
=> {"first_name"=>"User1", "id"=>1, "last_name"=>"USER1”}
あるいは、逆にホワイトリスト形式でも大丈夫。
user.as_json(only: ['id', 'first_name', 'last_name'])
=> {"first_name"=>"User1", "id"=>1, "last_name"=>"USER1”}
驚きの便利さである。
他にもincludes
とかオプションがあるので、ぜひ遊んでみて欲しい。