https://github.com/kyanny/playground/tree/gh-pages/grape-entity-polymorphic
Grape の present
メソッドは :with
オプションで引数オブジェクトに適用するエンティティクラスを指定できるが、 :with
オプション無しの場合は grape 自身がオブジェクトからエンティティクラスを類推する。
present
の引数オブジェクトが Array の場合、 grape は Array の先頭のオブジェクトをもとにエンティティクラスを類推し、そのエンティティクラスが Array の全ての要素に適用される (#present, #entity_class_for_obj) なので、 polymorphism 気取りで「だいたい同じだけど呼び出しに反応する属性・メソッドが異なるオブジェクト」を一緒くたにして present
に渡すと、 Array 内での並び順によって例外が発生することがある。
{"error":"HDD::Entity missing attribute `rpm' on #\u003cSSD:0x007fe4653a0d80\u003e"}
このように、片方がもう片方のサブセットみたいなオブジェクト群をまとめて present
したい場合は、属性・メソッドが足りないオブジェクトのほうのエンティティクラスで以下のように :if
オプションを使い、反応できない属性・メソッド呼び出しを回避するとうまくいく。
# Grape::Entity::DSL を使う場合 entity :rpm, if: ->(obj, opt) { obj.respond_to?(:rpm) } # Grape::Entity を継承する場合 expose :rpm, if: -> (obj, opt) { obj.respond_to?(:rpm) }
[{"capacity_gb":500,"rpm":5400},{"capacity_gb":2000,"rpm":7200},{"capacity_gb":256,"rpm":null},{"capacity_gb":512,"rpm":null}]