JSON を出力するときに、ActiveRecord/ActiveModel クラスから特定のフィールドを除外したいと考えています。
これを行う最も簡単な方法はas_json
、おそらく次のようにオーバーライドすることです。
def as_json (options = nil)
options ||= {}
super(options.deep_merge({:except => filter_attributes}))
end
def filter_attributes
[:password_digest, :some_attribute]
end
これは機能しますが、少し冗長であり、DRY になるのが非常に高速ではありません。フィルタリングされたプロパティを魔法のクラス メソッドで宣言するだけでいいと思いました。例えば:
class User < ActiveRecord::Base
include FilterJson
has_secure_password
filter_json :password_digest
#...
end
module FilterJson
extend ActiveSupport::Concern
module ClassMethods
def filter_json (*attributes)
(@filter_attributes ||= Set.new).merge(attributes.map(&:to_s))
end
def filter_attributes
@filter_attributes
end
end
def as_json (options = nil)
options ||= {}
super(options.deep_merge({:except => self.class.filter_attributes.to_a}))
end
end
これに関する問題は、継承を適切に処理することです。User をサブクラス化するとしましょう:
class SecretiveUser < User
filter_json :some_attribute, :another_attribute
#...
end
:some_attribute
論理的には、 、:another_attribute
、および も除外することは理にかなっています:password_digest
。
ただし、これはクラスで宣言された属性のみをフィルタリングします。super
念のため、内で呼び出しを試みましfilter_attributes
たが、失敗しました。私はこれを思いつきました、そしてそれはハックです。
def filter_attributes
if superclass.respond_to?(:filter_attributes)
superclass.filter_attributes + @filter_attributes
else
@filter_attributes
end
end
これは明らかに脆く、慣用的なものではありませんが、私が達成しようとしている「何」があります。より正確に(そしてできればよりエレガントに)それを行う方法を考えられる人はいますか? ありがとう!