RailsでAPIを作成するためにActiveModel::Serializerを使うことは多いかと思います。
普通にActiveRecordのオブジェクト(User.find(hoge)とかで取得したオブジェクト)を引き渡す場合は特に問題ないのですが、純粋な値や配列を引き渡そうとすると、NoMethodErrorを発生します。
しかし、意外と簡単な解決方法がありましたので紹介します。
事の起こり
app/serializers/user_serializer.rb:
class UserSerializer < ActiveModel::Serializer
attribute(:id) { object&.dig('id') }
attribute(:name) { object&.dig('name') }
end
上記のようなシリアライザ−をセットして、下記コントローラで外部APIから取得したデータの一部をJson形式で返却するAPIを実装したい。
app/controllers/users_controller.rb:
class UserController < ApplicationController
def index
users = (外部APIで情報を取得。Json形式で値が返却される。)
render json: users, each_serializer: UserApiSerializer
end
end
ただ、これだと下記エラーが出ます。
NoMethodError (undefined method `model_name’ for〜のエラー
NoMethodError (undefined method `model_name' for Hash:Class
object.class.model_name.to_s.underscore
^^^^^^^^^^^
Did you mean? module_parent):
「ハッシュに対してmodel_nameは定義されてないよ」
つまり、ActiveModelが、ActiveRecordのオブジェクトが引き渡されたと勘違いしている。
解決策
下記記事で紹介している「ホ1:ルートキーの変更」と同様の対応で解決できます。
つまり、
app/serializers/user_serializer.rb:
class UserApiSerializer < ActiveModel::Serializer
type 'user_api'
attribute(:id) { object&.dig('id') }
attribute(:name) { object&.dig('name') }
end
とtypeを設定してあげればOK。これでActiveModelが「ActiveRecordのオブジェクトとは限らないのでは・・・!」と認識してくれるっぽい。
ルートキーをResponse Bodyに含めたくない場合は、コントローラーでadapter: :attributes
を設定しておけば問題ありません。(デフォルトで設定されていれば、このままでOK)
はるすと
最後まで読んでくださってありがとうございました!
コメント