このエラーが出たときは、だいたいGarage::Repesenter
忘れなのですが、他のミスの場合もこのエラーが出るので、ググった時に引っかかるよう書いておきます。
前置き
code.rb
class User < ApplicationRecord
include Garage::Representer
has_many :group_user
has_many :groups, through: :group_user
property :id
property :name
property :groups
end
class Group < ApplicationRecord
include Garage::Representer
has_many :group_user
has_many :users, through: :group_user
property :id
property :name
property :groups
end
class UsersController < ApplicationController
def require_resource
@resource = User.find_by(id: params[:id])
end
end
こんな風のコードがあるとします。
問題
Postsを取得するために GET /users/10
するとこんな感じのエラーが出ます。困った...。
Garage::Representer::NonEncodableValue in UsersController#show
Groups::ActiveRecord_Associations_CollectionProxy can not be encoded directly. Forgot to include Garage::Representer?
ハマってしまい困っていたんですが、間違いはシンプルでUser
のproperty :groups
が、collection :groups
になるべきでした。
おまけ
最初、挙動がよく分からずコードを追ってしまっていました。このあたりの動きはgarage/representer
を読むと書いてあったので共有です。
include Garage::Representer
した時にextend
されるクラスメソッドがClassMethod
で定義され、self.included(base)
で適用されます。(これよくあるパターンぽい)
garage/representer.rb
module Garage::Representer
def self.included(base)
self.representers << base
base.class_eval do
if Rails.application
include Rails.application.routes.url_helpers
end
extend ClassMethods
end
end
module ClassMethods
attr_writer :representer_attrs
# ...
def representer_attrs
@representer_attrs ||= []
end
def property(name, options={})
representer_attrs << Definition.new(name, options)
end
def collection(name, options={})
representer_attrs << Collection.new(name, options)
end
# ...
end
# ...
class Collection < Definition
def encode(object, responder, selector = nil)
value = object.send(@name)
value.map do |item|
encode_value(item, responder, selector)
end
end
end
end
モデルのハッシュが必要になった場合、Definition#encode_value
でhashへ変換作業をしているのですが、ここでコケていたという雰囲気です。
Collection
の場合はmapしながらhashへの変換をしていくので、ActiveRecord_Associations_CollectionProxy
でも問題ないですね。