How can I use or reference a lambda that has been defined in base/super class?
Super class code
module Api
class ApplicationSerializer
include JSONAPI::Serializer
# I Also tried it this way
# serializer_for_proc = -> (object) { SerializerLookup.new.(object) }
def serializer_for_proc
-> (object) { SerializerLookup.new.(object) }
end
end
end
Child class code
module Api
class AnswerSerializer < ApplicationSerializer
attributes :values, :created_at, :updated_at, :usage
belongs_to :question, serializer: serializer_for_proc # NameError (undefined local variable or method `serializer_for_proc'
end
end
CodePudding user response:
As presented, serializer_for_proc
is an instance method of Api::ApplicationSerializer, but you're trying to invoke it directly on the class (or rather, directly on the subclass). In other words, all of the following fail for more-or-less the same reason:
belongs_to :question, serializer: serializer_for_proc
belongs_to :question, serializer: ApplicationSerializer.serializer_for_proc
belongs_to :question, serializer: AnswerSerializer.serializer_for_proc
You've never actually defined ApplicationSerializer.serializer_for_proc
, you've defined what is traditionally written as ApplicationSerializer#serializer_for_proc
, or in other words, ApplicationSerailizer.new.serializer_for_proc
.
The quickest way to fix this would be to make the original method definition a class method:
module Api
class ApplicationSerializer
include JSONAPI::Serializer
def self.serializer_for_proc
-> (object) { SerializerLookup.new.(object) }
end
end
end
You wrote in a comment that it did work when you copied it into the AnswerSerializer file, but this is unlikely (basically impossible). What would work would be copying the serializer_for_proc = -> (object) { SerializerLookup.new.(object) }
version into the AnswerSerializer file, because then serializer_for_proc
isn't a method name at all, it's just a local variable within the AnswerSerializer
file, same as x = 5
. But that's not inheritable.
Another solution (although one I like significantly less) would be making serializer_for_proc
a constant, e.g.:
# One file
module Api
class ApplicationSerializer
include JSONAPI::Serializer
SERIALIZER_FOR_PROC = -> (object) { SerializerLookup.new.(object) }
end
end
# Another file
module Api
class AnswerSerializer < ApplicationSerializer
attributes :values, :created_at, :updated_at, :usage
belongs_to :question, serializer: SERIALIZER_FOR_PROC
end
end
That works, but I don't like to rely on this because inheritance-based constant lookup in Ruby has some pretty weird edge cases. I'd personally just use Api::ApplicationSerializer::SERIALIZER_FOR_PROC
if I wanted to use a constant.