PostRevisor não consegue revisar posts em tópicos excluídos

Resumo

Para algumas postagens, chamar PostRevisor define post_id como nil. Estou louco?

Resposta: Não. PostRevisor acessa post.topic, que é nil para uma postagem em um tópico excluído. E então ele define post.topic como nil, o que por sua vez define post.topic_id como nil.

Acho que PostRevisor deveria obter o tópico assim:

 @topic = topic || Topic.with_deleted.find_by(id: post_topic_id)

em vez de assim:

 @topic = topic
post=Post.find_by(topic_id: 179227, post_number: 12)
post.topic_id => 179227
pr=PostRevisor.new(post)
post.topic_id => nil

A História Completa

Estou trabalhando em um script que corrige links goo.gl (o serviço está sendo desativado em breve, então o script encontra links goo.gl, busca para onde eles são redirecionados e substitui o URL goo.gl pelo que ele está sendo direcionado. Na maioria das vezes funciona.

Mas

Para várias postagens, tudo parece estar funcionando bem, mas então PostRevisor falha porque post.acting_user é nil. E então, em meu resgate, parece que o topic_id é nil, mas não é o post que é nil, porque ele ainda tem um post_number.

     begin
       puts "Revisando (#{count}/#{total_posts}) https://mysite.com/t/#{post.topic_id}/#{post.post_number}"
       puts "topic_id ausente para post #{post.id}" if !post.topic_id
       next if !post.topic_id
       PostRevisor.new(post).revise!(system_user, raw: new_raw, **revision_options)
     rescue => e
       puts "não é possível revisar (número: #{count} https://tw.forumosa.com/t/#{post.topic_id}/#{post.post_number}): #{e}"
     end
CORRIGINDO!!: https://goo.gl/maps/XaNG
B7qaZGzhBmM78 -----> https://www.google.com/maps/place/%E6%AD%A5%E9%81%93%E5%92%96%E5%95%A1%E9%A4%A8Cafe+Strada/@22.6300414,120.3153591,17z/d
ata=!3m1!4b1!4m5!3m4!1s0x346e04944a9b3471:0x520c1f01c3d62e57!8m2!3d22.6301115!4d120.3175543?shorturl=1
Revisando (680/1773) https://mysite.com/t/207069/1817
não é possível revisar (número: 680 https://mysite.com/t//1817): método indefinido `acting_user=' para nil

Para a grande maioria das postagens, isso funciona bem, mas para um subconjunto delas, falha assim. E se eu executar o código manualmente linha por linha, obtenho o mesmo resultado. Parece, no entanto, que se eu fizer um pr=PostRevisor.new(post), vejo que o post no registro pr não tem topic_id e então, se eu inspecionar o post, ele agora tem topic_id definido como nil.

1 curtida

Por curiosidade, há algum motivo para você não estar editando o modelo Post diretamente?

Porque se você estiver alterando 3000 posts com gsub e uma regex complicada com um monte de casos extremos (corrigir: goo.gl, http://goo.gl, https://goo.gl, mas não toque em https://maps.app.goo.gl, ou https://map.goo.gl, e talvez você atinja o limite de taxa do goo.gl, e assim por diante) você pode querer voltar ao post antes de estragá-lo totalmente!

Tem sido muito legal poder olhar as edições e ver o antes e o depois e poder reverter! Uma versão faria https://maps.app.goo.gl/abd12 em algo como https://maps.app.https://maps.google.com/;lkajw3rpoazse;flknmase;faijserfasefklasdfa, por exemplo.

1 curtida

faz sentido :slight_smile:

1 curtida

Há alguns anos, houve um script semelhante que tentei fazer com que o CDCK executasse para um cliente, e eles disseram (nas minhas palavras, não nas deles): “Cara. Você acha que vamos executar seu código que altera um zilhão de posts sem critério e não há como desfazer isso? Pense de novo.”

1 curtida

Sim, outra abordagem é executá-lo em um backup em uma área controlada. Mas eu adoro sua solução.

1 curtida

Então, aqui está o inicializador:

Então, de alguma forma, o post está chegando lá e, embora post_id tenha um valor, post não tem?

Não consigo reproduzir isso.
O último post.topic_id não é nulo e, como esperado, é uma repetição do resultado anterior.

Sim. Funcionou na maioria das postagens. Há algo estranho com algumas delas.

[63] pry(main)> post.topic_id
=> 179227
[64] pry(main)> post.topic
=> nil
[65] pry(main)>

Tenho quase certeza que isso não deveria acontecer. :person_shrugging:

Mas espere:

Topic.find(post.topic_id)
ActiveRecord::RecordNotFound: Couldn't find Topic with 'id'=179227 [WHERE "topics"."deleted_at" IS NULL]
from /var/www/discourse/vendor/bundle/ruby/3.3.0/gems/activerecord-7.2.2.1/lib/active_record/relation/finder_methods.rb:428:in `raise_record_not_found_exception!'

O tópico foi excluído.

Então, a questão é se é um bug que você não pode revisar postagens em tópicos excluídos.

Acho que não vou me importar e farei com que meu script verifique post.topic como nil em vez de post.topic_id.

1 curtida

Sim, uma falta de integridade desagradável ali com a chave estrangeira!

Acho que algumas das proteções (ahem) estão desativadas porque as tabelas geralmente são muito grandes.

Talvez alguém tenha executado um topic.delete em vez de destroy. Ops.

Minha busca pelas postagens foi como Post.where("raw like '%goo.gl%'"), e isso retornaria postagens em tópicos excluídos. E então essas postagens têm um topic_id, mas não um topic. Acho que há alguma maneira de fazer Topic.find retornar tópicos excluídos (porque um administrador pode ver esses tópicos, é por isso que eu estava tão confuso. Essa pequena lixeira é fácil de perder.)

Então é assim:

deleted_topic = Topic.with_deleted.find_by(id: 123)

Então, talvez eu devesse ter feito isso e atualizado a postagem antes de chamar o PostRevisor?

Mas na UX eu posso atualizar uma postagem em um tópico excluído, então estou pensando que

def initialize(post, topic = post.topic)
  @post = post
  @topic = topic
  # Make sure we have only one Topic instance
  post.topic = topic
end

deveria ser

def initialize(post, topic = post.topic)
  @post = post
  @topic = topic || Topic.with_deleted.find_by(id: post_topic_id)
  # Make sure we have only one Topic instance
  post.topic = topic
end

Vou mover isso para Bug caso alguém mais pense que isso é um.

Mas isso funciona:

        if !post.topic # posts in delted topics have no topic and break PostRevisor
           post.topic = Topic.with_deleted.find_by(id: post.topic_id)
           next if !post.topic
        end
        PostRevisor.new(post).revise!(system_user, raw: new_raw, **revision_options)

Houve postagens em 3 tópicos que fizeram o rails travar. Estou desistindo disso. :slight_smile:

1 curtida

E outra versão do acima que faz um deleted_topic = Topic.with_deleted.find_by(id: 123) para atualizar post.topic também funciona.

Ainda parece um bug, no entanto. Ou talvez, como o core faz algo diferente para gerenciar isso, não seja um bug.

1 curtida

Ou um Recurso (e, portanto, especificação) em falta?

Online, isto nunca será chamado para Posts em Tópicos eliminados?

Concordo, no entanto, que ele deve gerenciar isso adequadamente :thinking:

Talvez

Eles estão claramente fazendo algo para permitir que funcione em posts em tópicos excluídos, provavelmente como eu.

Sim. Alguém que toma tais decisões pode mover isso de volta para Dev se achar apropriado.

Este tópico foi fechado automaticamente 30 dias após a última resposta. Novas respostas não são mais permitidas.