振る舞いが把握しきれずどうにも気持ち悪いが、期待しない振る舞いを避ける方法は見つかったので一旦まとめ。
https://github.com/kyanny/playground/tree/gh-pages/grape-entity-collection-but-not-array
Item
に対するItemEntity
がある場合、ItemEntity.new(item)
とItemEntity.represent(item)
は同じ意味になる- どちらの
as_json
to_json
を呼んでもちゃんと期待するものを返す
- どちらの
Item
のコレクションとしてItems
がある場合、ItemEntity.new(items).as_json
もItemEntity.represent(items).as_json
も例外を吐くItemEntity missing attribute
name' on #<Items:0x007fd0f09dfa80>` みたいな感じ- 何故かというと grape-entity は与えられた object が
to_ary
に反応するときのみ object を配列とみなし、個々の要素を entity クラスでラップするから include Enumerable
はto_ary
を実装しないので grape-entity からはitems
がitem
のコレクションであることがわからないas_json
を呼ぶ前の entity クラスのインスタンスも#<ItemEntity:0x007fd0f09decc0 @object=#<Items:0x007fd0f09dfa80 @names=["taro", "hanako"]>, @options={}>
のようになっている
to_ary
が実装されているとItemEntity.new
は変わらずだがItemEntity.represent
は期待した通りitem
をItemEntity
で表現したものの配列を返す- new の場合
#<ItemEntity:0x007faed3a0a120 @object=#<Items:0x007faed3a0a6e8 @names=["taro", "hanako"]>, @options={}>
- represent の場合
[#<ItemEntity:0x007faed3a091f8 @object=#<Item:0x007faed3a096d0 @name="taro">, @options={:collection=>true}>, #<ItemEntity:0x007faed3a08fa0 @object=#<Item:0x007faed3a09608 @name="hanako">, @options={:collection=>true}>]
- entity クラスのインスタンスの内部表現の時点ですでに異なっている
- new の場合
to_ary
を実装したくない場合はitems.map { |item| ItemEntity.new(item) }.as_json
でも同じ結果が得られる- grape-entity の
root
とかが絡むとまたややこしくなるが、結局[{...}, {...}]
ではなく{"key": [{...},{...}]}
という形にしたい時に使うものっぽいので、裸の Array で返したいときは無視してよい。
まとまっていないが要するに、
- entity として表現したいオブジェクトが Enumerable の場合は
items.map { |item| Entity.new(item) }.as_json
する(new のかわりに represent でも可) - entity として表現したいオブジェクトが Array の場合(items << item)は
Entity.represent(items)
する(new ではダメ)