ActiveModelSerializers を 0.9 から 0.10 にアップデートしたメモ
ActiveModelSerializers を 0.9 (0.9.5) から 0.10 (0.10.0) にアップデートした時のメモです。 0.10 で API が大幅に変更されたため、アプリケーション側にも修正を加える必要がありました。
しかし、アップデートが完全に終わったわけではなく、0.10 はアソシエーションの扱いがガラッと変わっているため、 その部分だけ作業中となっています (内容については記事の一番下に書いています)。
ActiveModelSerializers を使用しているアプリケーションで、アップデートを行った時に対応した内容を以下に記載します。
initializer の root キー設定
root キーの設定はデフォルトで false
になりました。
以下のように initializer に root キーを含めない設定を書いている場合は削除します。
config/initializers/active_model_serializers.rb:
ActiveModel::Serializer.root = false
ActiveModel::ArraySerializer.root = false
ActiveModel::ArraySerializer
→ ActiveModel::Serializer::CollectionSerializer
each_serializer
オプションが serializer
に変わったため、以下のような書き方になります:
serializer = ActiveModel::Serializer::CollectionSerializer.new(
posts,
serializer: PostSerializer,
# ...
)
serialization_options
→ instance_options
Serializer 中で使用するデータを参照するための変数名が変更になりました。
def foo
object.bar(instance_options[:baz])
end
データを渡す方法も変更になっています。
0.9.5:
serializer = PostSerializer.new(@post)
post = serializer.as_json(foo: foo, bar: bar)
0.10.0:
serializer = PostSerializer.new(@post, foo: foo, bar: bar)
post = serializer.as_json
メソッドが評価されるタイミング
0.10 では Serializer にデータを渡したタイミングで attribute
で定義されたメソッドが評価されるようになりました。以下のように UserSerializer
に渡す時にメソッド内の object
が nil
の時にエラーになってしまいます。この場合 Serializer を呼び出さないような考慮が必要です。
def user
return nil if object.user.nil?
serializer = UserSerializer.new(object.user)
serializer.as_json
end
使用しないキーを除外する filter
キーを含めるかどうかの条件は attribute
や has_one
メソッドの if
オプションに書くようになりました。
0.9.5:
attributes :id, :body
has_one :foo, serializer: FooSerializer
def filter(keys)
keys.delete :foo unless object.foo?
end
0.10.0:
attributes :id
attribute :foo_id, if: -> { object.foo? }
has_one :foo, serializer: FooSerializer, if: -> { object.foo? }
アソシエーションのキー名を指定するオプション名変更
root
→ key
に変更されました。
0.10.0:
has_one :foo, serializer: FooSerializer, key: :bar
番外: アソシエーション周りの問題
モデルのアソシエーションではなく、Serializer のメソッドをアソシエーションに指定した場合に
Serializer が使用されず単純に as_json
した結果が出力される、という現象です。
カテゴリとサブカテゴリがあったとして、以下のような書き方をした時に発生します。
has_one :category, serializer: CategorySerializer
def category
object.root # ancestry gem
end
これは以下のように書くと一応実現できるのですが、冗長な感じになります。
attribute :category, if: -> { object.respond_to?(:root) }
def category
return nil if object.root.nil?
CategorySerializer.new(object.root)
end
0.9 で偶然書けていただけで 0.10 の挙動が正しいのかもしれません... 自分でも整理できていないところなので、詳しいことが分かったら更新します。
- 2016/09/16: 修正されたかもしれない Pull Request がありました。v0.10.2 でリリースされている模様です。