Edited at

Rails ActiveRecordでto_jsonやas_jsonなどする時に出力されるフィールドを隠す

More than 3 years have passed since last update.


やりたいこと

ActiveRecordのModelをas_jsonしたりto_jsonしたりto_xmlすると、パスワードとかユーザ属性別のフラグ等、見せたくないフィールドまでだだ漏れてしまう…。

[1] pry(main)> User.first.as_json

User Load (8.7ms) SELECT `users`.* FROM `users` ORDER BY `users `.`id` ASC LIMIT 1
=> {"id"=>#<UUID:0x34328adf UUID:05b0ab39-d126-c347-b64a-31d100123eb4f>,
"email"=>"test@example.org",
"crypted_password"=>"$2a$10$8/X2-fdasFD817fDJNAS9Fc7fDJNAS9FXOnCDIAzfzylmkEkzD/bUfJFc.XZ",
"salt"=>"UFHDdfjnsahbdfINFASYBhlna",
"name"=>"Taro Tanaka",
"created_at"=>Thu, 12 Mar 2015 12:17:52 UTC +00:00,
"updated_at"=>Wed, 01 Apr 2015 05:05:19 UTC +00:00}

そんな時はたいてい、as_jsonやto_jsonをオーバーライドして、

   def as_json(options={})

options[:except] ||= [:crypted_password, :salt]
super(options)
end

みたいにされている方が多いと思われますが、モデルごとに毎度オーバーライドするのはなんだかDRYじゃないしイケてないかも…?と思う人のための解法(案)です。


やり方

親モデルを作成し、以下の通り設定します。


base_model.rb

class BaseModel < ActiveRecord::Base

self.abstract_class = true

def self.except_from_serialization(*args)
@@EXCEPT_FIELDS ||= []
@@EXCEPT_FIELDS.concat args
end

def serializable_hash(options = nil)
options ||= {}
options[:except] = Array(options[:except])
options[:except].concat Array(@@EXCEPT_FIELDS)
super(options)
end
end


特定のフィールドを隠したい子モデル側では、親モデルを継承した上で以下の通り設定します。


user.rb

class User < BaseModel

except_from_serialization :crypted_password, :salt
end


結果

[1] pry(main)> User.first.as_json

User Load (8.6ms) SELECT `users`.* FROM `users` ORDER BY `users`.`id` ASC LIMIT 1
=> {"id"=>#<UUID:0x34328adf UUID:05b0ab39-d126-c347-b64a-31d100123eb4f>,
"email"=>"test@example.org",
"name"=>"Taro Tanaka",
"created_at"=>Thu, 12 Mar 2015 12:17:52 UTC +00:00,
"updated_at"=>Wed, 01 Apr 2015 05:05:19 UTC +00:00}

楽しい!!! :v:('ω':v: )三:v:('ω'):v:三( :v:'ω'):v:


あとがき

なんでこんな記事書いたのっていうと、このやり方が不安だったからです。

有識者の方のコメントや改善案お待ちしております!