#ruby #lambda #proc
#ruby #лямбда #proc
Вопрос:
Как я могу использовать или ссылаться на лямбду, которая была определена в базовом / суперклассе?
Код суперкласса
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
Код дочернего класса
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
Комментарии:
1. Я так не думаю, потому что, если я перенесу определение лямбды в подкласс (AnswerSerializer), он будет нормально работать с этим синтаксисом.
2. Это не имеет никакого отношения к лямбдам или процедурам. OP не понимает, как работают методы.
Ответ №1:
Как представлено, serializer_for_proc
это метод экземпляра Api::ApplicationSerializer, но вы пытаетесь вызвать его непосредственно в классе (или, скорее, непосредственно в подклассе). Другими словами, все следующие ошибки не выполняются по более или менее одной и той же причине:
belongs_to :question, serializer: serializer_for_proc
belongs_to :question, serializer: ApplicationSerializer.serializer_for_proc
belongs_to :question, serializer: AnswerSerializer.serializer_for_proc
Вы на самом деле никогда не определяли ApplicationSerializer.serializer_for_proc
, вы определили то, что традиционно записывается как ApplicationSerializer#serializer_for_proc
, или, другими словами, ApplicationSerailizer.new.serializer_for_proc
.
Самый быстрый способ исправить это — сделать исходное определение метода методом класса:
module Api
class ApplicationSerializer
include JSONAPI::Serializer
def self.serializer_for_proc
-> (object) { SerializerLookup.new.(object) }
end
end
end
Вы написали в комментарии, что это сработало, когда вы скопировали его в файл AnswerSerializer, но это маловероятно (в принципе невозможно). Что бы сработало, так это скопировать serializer_for_proc = -> (object) { SerializerLookup.new.(object) }
версию в файл AnswerSerializer, потому что тогда serializer_for_proc
это вообще не имя метода, это просто локальная переменная внутри AnswerSerializer
файла, такая же, как x = 5
. Но это не наследуется.
Другим решением (хотя оно мне нравится значительно меньше) было бы создание serializer_for_proc
константы, например:
# 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
Это работает, но мне не нравится полагаться на это, потому что постоянный поиск на основе наследования в Ruby имеет несколько довольно странных крайних случаев. Я бы лично просто использовал Api::ApplicationSerializer::SERIALIZER_FOR_PROC
, если бы хотел использовать константу.