PostSerializer#rawでsuperを呼び出すと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>.json500 エラーを返す原因となります。

object.rawsuper の代わりに使うことで問題を回避できることは分かっていますが、特に他のメソッド(cookedpost_stream など)もオーバーライドしていて、それらのケースでは super が正常に動作するため、なぜ super がこのケースで例外を引き起こすのかを理解したいのです。

Discourse の内部構造にはまだ慣れていないため、以下の点について説明していただけると大変助かります。

  • PostSerializer#raw 内で super が実際に解決するものは何か
  • なぜこのケースで super を呼び出すと 500 エラーになるのか
  • なぜ rawcooked のようなメソッドとは異なる動作をするのか

よろしくお願いします!

これは、通常の投稿のシリアライザに raw が含まれていないためだと確信しています。raw が含まれるのは編集時だけです。投稿を表示するには cooked が必要なだけであり、必要でないときに raw も含めるのは無駄になります。

cookedpost_stream はシリアライザに含まれているため、super は機能します。

これはRubyの機能です。class ::PostSerializerを使用すると、元のクラスから継承するのではなく、その定義を上書きしています。PostSerializerを継承していないため、superは対応するメソッドを見つけることができません。

すでに定義されているクラスを再オープンする代わりに、prependを使用する必要があります。

「いいね!」 4

代わりに 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: それは違うやり方です

「いいね!」 2

ああ、そうか。知ってたよ。なんでそれが答えじゃなかったのかわからないな。:person_shrugging:

「いいね!」 2

技術的には、あなたの回答は500エラーを説明しているので正解でした。

「いいね!」 1

彼が尋ねた質問には私が答えた。あなたが答えたのは彼が尋ねるべきだった質問だ!

でも、少なくとも私は正解した。

「いいね!」 1