PostRevisor は削除されたトピック内の投稿を修正できません

tl;dr

一部の投稿で PostRevisor を呼び出すと post_idnil に設定されます。私がおかしいのでしょうか?

回答:いいえ。PostRevisorpost.topic にアクセスしますが、これは削除されたトピック内の投稿では nil です。そして post.topicnil に設定し、それが post.topic_idnil に設定します。

PostRevisor はトピックを次のように取得すべきだと思います。

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

次のようにするのではなく:

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

全体のストーリー

goo.gl リンクを修正するスクリプトを作成しています(サービスがまもなく終了するため、スクリプトは goo.gl リンクを見つけ、リダイレクト先を取得し、goo.gl URL をリダイレクト先の URL に gsub します。ほとんど機能します)。

しかし

多くの投稿で、すべてがうまくいっているように見えますが、その後 PostRevisorpost.acting_usernil のために失敗します。そして、私の rescue では、topic_idnil になっているようですが、postnil なわけではありません。なぜなら、まだ post_number を持っているからです。

      begin
        puts "Revising (#{count}/#{total_posts}) https://mysite.com/t/#{post.topic_id}/#{post.post_number}"
        puts "missing topic_id for 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 "cannot revise (number: #{count} https://tw.forumosa.com/t/#{post.topic_id}/#{post.post_number}): #{e}"
      end
FIXING!!: 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/data=!3m1!4b1!4m5!3m4!1s0x346e04944a9b3471:0x520c1f01c3d62e57!8m2!3d22.6301115!4d120.3175543?shorturl=1
Revising (680/1773) https://mysite.com/t/207069/1817
cannot revise (number: 680 https://mysite.com/t//1817): undefined method `acting_user=' for nil

ほとんどの投稿では、これは問題なく機能しますが、一部の投稿ではこのように失敗します。そして、コードを一行ずつ手動で実行しても同じ結果になります。しかし、pr=PostRevisor.new(post) を実行すると、pr レコード内の投稿に topic_id がなく、その後 post を検査すると topic_idnil に設定されていることがわかります。

「いいね!」 1

興味本位で伺いますが、なぜ直接Postモデルを編集しないのですか?

3000件の投稿をgsubと複雑な正規表現で、多くのエッジケース(修正:goo.glhttp://goo.glhttps://goo.gl、ただしhttps://maps.app.goo.glhttps://map.goo.glは変更しない、そしてgoo.glでレート制限される可能性もある、など)を考慮して変更する場合、完全に台無しにする前に、投稿を元に戻したいと思うかもしれません!

編集内容を確認し、変更前と変更後を見て、元に戻すことができるのは非常に便利でした!例えば、あるバージョンではhttps://maps.app.goo.gl/abd12https://maps.app.https://maps.google.com/;lkajw3rpoazse;flknmase;faijserfasefklasdfaのようになりかねません。

「いいね!」 1

なるほど :slight_smile:

「いいね!」 1

数年前、あるクライアントのためにCDCKで実行しようとした似たようなスクリプトがありましたが、彼らは(私の言葉で言うと)「おい、お前は、元に戻す方法が全くない、数えきれないほどの投稿を勝手に変更するようなコードを実行させたいのか?もう一度考え直せ」と言いました。

「いいね!」 1

はい、別の方法は、制御された領域でバックアップを実行することです。しかし、あなたのソリューションは素晴らしいです。

「いいね!」 1

初期化子は次のとおりです。

したがって、何らかの方法で投稿がそこに到達し、post_id には値がありますが、post にはないのですか?

これは再現できません。

最後の post.topic_id は nil ではなく、予想どおり前の結果の繰り返しです。

はい。ほとんどの投稿で機能しましたが、一部の投稿には何か問題があるようです。

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

これは本来あるべき姿ではないと確信しています。 :person_shrugging:

しかし、待ってください:

 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!'

トピックは削除されています。

では、削除されたトピックの投稿を修正できないのはバグなのか、という疑問が生じます。

気にするのはやめて、post.topic_id の代わりに post.topic が nil かどうかをチェックするようにスクリプトを設定します。

「いいね!」 1

外部キーに重大な整合性の欠如がありますね!

テーブルが大きすぎることが多いため、いくつかのガードレール(ahem)がオフになっているのだと思います。

誰かが topic.destroy ではなく topic.delete を実行したのかもしれません。おっと。

投稿の検索は Post.where("raw like '%goo.gl%'") のような形で行い、削除されたトピック内の投稿を取得しました。そして、それらの投稿には topic_id はありますが、topic はありません。Topic.find で削除されたトピックを取得する方法があるはずです(管理者はそれらのトピックを見ることができるため、混乱していました。あの小さなゴミ箱は簡単に見落としてしまいます。)

それは次のようなものです。

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

それで、おそらくそれを実行してから PostRevisor を呼び出すべきだったのでしょうか?

しかし、UXでは削除されたトピック内の投稿を更新できるため、次のように考えています。

def initialize(post, topic = post.topic)
  @post = post
  @topic = topic
  # Topicインスタンスが1つだけであることを確認
  post.topic = topic
end

は次のようにすべきです。

def initialize(post, topic = post.topic)
  @post = post
  @topic = topic || Topic.with_deleted.find_by(id: post_topic_id)
  # Topicインスタンスが1つだけであることを確認
  post.topic = topic
end

他の人もバグだと思うかもしれないので、これを Bug に移動します。

しかし、これは機能します:

        if !post.topic # 削除されたトピック内の投稿にはtopicがなく、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)

Railsをクラッシュさせた3つのトピックに投稿がありました。もう諦めます。 :slight_smile:

「いいね!」 1

そして、deleted_topic = Topic.with_deleted.find_by(id: 123) を使用して post.topic を更新する上記とは別のバージョンも機能します。

それでもバグのように思えます。あるいは、コアがこれを管理するために別のことを行っているため、バグではないのかもしれません。

「いいね!」 1

それとも、機能(したがって仕様)が不足しているということですか?

オンラインでは、削除されたトピックの投稿に対してこれは決して呼び出されないのでしょうか?

しかし、それが適切に管理されるべきであることには同意します :thinking:

おそらく

彼らは明らかに、削除されたトピックの投稿でも機能するように何かをしているようです。おそらく私と同じように。

ええ。そのような決定を下す人が、適切だと考えればこれを#devに戻すことができます。

このトピックは、最後の返信から30日後に自動的にクローズされました。新しい返信は許可されていません。