Почему вызов super в PostSerializer#raw вызывает ошибку 500, а вызов object.raw работает?

Всем привет,

Я изучаю, как расширять сериализаторы Discourse, и столкнулся с поведением, которое до конца не понимаю.

Я добавил этот код для переопределения PostSerializer#raw:

require_dependency "post_serializer"

class ::PostSerializer
  def raw
    if scope.can_edit?(object)
      object.raw
    else
      object.raw&.truncate(300)
    end
  end
end

Это работает идеально.

Однако, если я изменю код, чтобы использовать super:

require_dependency "post_serializer"

class ::PostSerializer
  def raw
    if scope.can_edit?(object)
      super
    else
      object.raw&.truncate(300)
    end
  end
end

Когда scope.can_edit?(object) возвращает true, вызов super приводит к тому, что /posts/<id>.json возвращает ошибку 500.

Я знаю, что могу избежать проблемы, используя object.raw вместо super, но я хочу понять, почему super вызывает исключение в этом случае, особенно потому, что я также переопределяю другие методы (cooked, post_stream и т. д.), и super работает там без проблем.

Поскольку я всё ещё новичок во внутренних механизмах Discourse, я был бы очень признателен за объяснение:

  • на что именно ссылается super внутри PostSerializer#raw,
  • почему вызов super в данном случае приводит к ошибке 500,
  • и почему raw ведёт себя иначе по сравнению с методами вроде cooked.

Заранее спасибо за любую помощь!

Я почти уверен, что это связано с тем, что raw отсутствует в сериализаторе для обычного поста. Он включается только при редактировании. Для отображения поста достаточно поля cooked; было бы расточительно включать raw, если он не нужен.

cooked и post_stream присутствуют в сериализаторе, поэтому super работает корректно.

Это особенность Ruby. Когда вы используете class ::PostSerializer, вы переопределяете определение в исходном классе, а не наследуете его. Поскольку вы не наследуете PostSerializer, метод super не может найти соответствующий метод.

Вместо повторного открытия уже определённого класса следует использовать prepend.

Вам следует использовать add_to_serializer.

Например: How to add user data to the post serializer?

Спасибо за объяснение!
Вы правы — повторное открытие ::PostSerializer было проблемой. После переключения на prepend всё работает как ожидалось.

Теперь я использую этот модуль:

module PostSerializerExtension
  def raw
    if scope.can_edit?(object)
      super
    else
      object.raw&.truncate(300)
    end
  end
end

reloadable_patch do
  require_dependency "post_serializer"
  ::PostSerializer.prepend(::PostSerializerExtension)
end

У меня это работает идеально. Ещё раз спасибо за помощь!

Нет, :roll_eyes: это не тот путь

Ах, точно. Я это знал. Не уверен, почему я не ответил этим. :person_shrugging:

Технически ваш ответ был верным, так как он объясняет ошибку 500.

Я отвечаю на вопрос, который он задал. А ты отвечаешь на вопрос, который он должен был задать!

Но по крайней мере я ответил правильно.