Edited at

Railsのas_jsonをもうちょっと便利に使うオプション

More than 5 years have passed since last update.

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とかオプションがあるので、ぜひ遊んでみて欲しい。