Sto imparando come estendere i serializer di Discourse e mi sono imbattuto in un comportamento che non capisco del tutto.
Ho aggiunto questo codice per sovrascrivere 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
Questo funziona perfettamente.
Tuttavia, se lo modifico per usare super:
require_dependency "post_serializer"
class ::PostSerializer
def raw
if scope.can_edit?(object)
super
else
object.raw&.truncate(300)
end
end
end
Quando scope.can_edit?(object) è vero, la chiamata a super causa un errore 500 per /posts/:id.json.
So che posso evitare il problema usando object.raw invece di super, ma voglio capire perché super causa un’eccezione in questo caso, specialmente perché sovrascrivo anche altri metodi (cooked, post_stream, ecc.) e super funziona bene in quei casi.
Dato che sono ancora nuovo agli interni di Discourse, apprezzerei molto una spiegazione su:
a cosa si risolve super all’interno di PostSerializer#raw,
perché chiamare super in questo caso porta a un errore 500,
e perché raw si comporta diversamente rispetto a metodi come cooked.
Sono abbastanza sicuro che sia perché raw non è nel serializzatore per un post normale. Viene incluso solo quando si modifica. Per visualizzare un post è necessario solo cooked; sarebbe uno spreco includere anche raw quando non è necessario.
cooked e post_stream sono nel serializzatore, quindi super funziona.
Questa è una funzionalità di Ruby. Quando usi class ::PostSerializer, stai sovrascrivendo la definizione nella classe originale invece di ereditarla. Poiché non stai ereditando da PostSerializer, super non riesce a trovare il metodo corrispondente.
Dovresti usare prepend invece di riaprire una classe già definita.
Grazie per la spiegazione!
Hai ragione: riaprire ::PostSerializer era il problema. Dopo essere passato a prepend, tutto funziona come previsto.
Ora sto usando questo modulo:
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
Questo funziona perfettamente da parte mia. Grazie ancora per la guida!