Ojを使ってArrayでラップしたオブジェクトをフィルターしたい件
Rails環境なのを除外して、例えばRubyのオブジェクトをJSON化するときってto_jsonを実装してあーだらこーだらするわけですが
そのときにJSONに出力するキーとかをフィルターしたいとかってあると思うんですが...
require "oj"
class Sample
def initialize(name)
@id = 1
@name = name
end
def as_json(options = {})
data = { id: @id, name: @name }
options[:keys] ? data.slice(*Array(options[:keys])) : data
end
def to_json(options = {})
Oj.dump(as_json(options), mode: :compat)
end
end
samples = [
Sample.new("hoge"),
Sample.new("fuga"),
Sample.new("foobar")
]
puts Oj.dump(samples, mode: :rails, keys: [:name])
まあ要はdumpの引数にkeysを指定して出力するデータをsliceで切り出したりとかするわけですが、これ実行するとどうなるかっていうと
[{"name":"hoge"},{"id":1,"name":"fuga"},{"id":1,"name":"foobar"}]
ってわけになる。最初のオブジェクトにはちゃんとsliceで切り出せれてるけどそれ以降ではそれが正しく作用してない。
これ何が根本的な原因なのかはちょっと不明なんだけど、mode: :railsをするとas_jsonに渡される引数にちゃんと伝番されないっぽい
require "oj"
class Sample
def initialize(name)
@id = 1
@name = name
end
def as_json(options = {})
data = { id: @id, name: @name }
options[:keys] ? data.slice(*Array(options[:keys])) : data
end
def to_json(options = {})
Oj.dump(as_json(options), mode: :compat)
end
end
samples = [
Sample.new("hoge"),
Sample.new("fuga"),
Sample.new("foobar")
]
# mode:を:compatにする
puts Oj.dump(samples, mode: :compat, keys: [:name])
これで実行すると
[{"name":"hoge"},{"name":"fuga"},{"name":"foobar"}]
っていう感じになる。ということで配列でラップしたオブジェクトを実装したto_jsonなどを使って出力する場合がある場合にはここらへん注意かもね
ちなみに多分RailsっていうかActiveSupport自体にはこういうのがあるっぽいけど面倒くさいので省略
余談
mode: :railsのときにas_jsonの引数に渡されるのが
{:mode=>:rails, :keys=>[:name]}
{}
{}
mode: :compatのときにas_jsonの引数に渡されるのが
{:mode=>:compat, :keys=>[:name]}
{:mode=>:compat, :keys=>[:name]}
{:mode=>:compat, :keys=>[:name]}
というようにmode: :railsしてるときにちゃんとas_jsonの引数で受け取れない場合があるっぽい