我想在输出 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
这行得通,但它有点冗长,并且不适合干得很快。我认为用一个神奇的类方法声明过滤的属性会很好。例如:
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
这样做的问题是让它正确处理继承。假设我是用户的子类:
class SecretiveUser < User
filter_json :some_attribute, :another_attribute
#...
end
:some_attribute
从逻辑上讲,过滤掉,:another_attribute
和 also是有意义的:password_digest
。
但是,这只会过滤类上声明的属性。为了达到预期的目的,我尝试在 inside 调用super
,filter_attributes
但失败了。我想出了这个,这是一个黑客。
def filter_attributes
if superclass.respond_to?(:filter_attributes)
superclass.filter_attributes + @filter_attributes
else
@filter_attributes
end
end
这显然很脆弱且不习惯,但这是我想要完成的“什么”。谁能想到一种更正确(并希望更优雅)的方法?谢谢!