削除済み投稿を一括で完全に削除する?

If I am not mistaken there is a field called deleted_at

If it is deleted, then there should be a date time Stamp.

If it is not deleted then is null

Maybe look for the entry that is <> Null and delete

「いいね!」 1

Thanks Gav, but the ones that I am targeting aren’t marked as deleted. Rather, their Topic has been deleted and then destroy_all’d.

「いいね!」 2

I was playing around with this and i notice that part of your query was not returning the response you need.

SELECT topic_id from posts does not return an integer, but it returned a string

image

This might be the cause that your db still contains orphaned posts.

「いいね!」 2

これは、ラベルが topic_id の場合に Data Explorer が整数を自動的に URL に変換しているためだと思われます。

Data Explorer でこのクエリを実行すると、特定しようとしているすべての投稿がキャプチャされます(5000 をはるかに超えます)。

SELECT id, topic_id
FROM posts
WHERE topic_id not in (select id from topics)
ORDER by id

Rails の構文で明らかに間違っているのは、次のようになっていることです。

[1] pry(main)> Target = Post.where('topic_id not in (select id from topics)')
=> []

何が間違っているのか誰か教えてもらえませんか?

「いいね!」 1

@pfaffman のおかげで、これを使用して関連する投稿を特定できました。

Post.find_by_sql("select id from posts where topic_id not in (select id from topics)")

次のような出力が得られます。

[1] pry(main)> Post.find_by_sql(“select id from posts where topic_id not in (select id from topics)”)
=> [#<Post:0x000055df30d4ee90 id: 150>,
#<Post:0x000055df2e538ff0 id: 51097>,
#<Post:0x000055df2e50ba28 id: 83>,
#<Post:0x000055df2e4ee8b0 id: 40636>,
#<Post:0x000055df2e4a92d8 id: 62562>,
#<Post:0x000055df2e4b7978 id: 13522>,
etc

しかし、この選択に destroy_all を適用する方法がわかりません。

これは(私の利益のために)役立つかもしれません。

何か提案はありますか?

「いいね!」 1

これでうまくいくと思います

posts=
Post.find_by_sql("select id from posts where topic_id not in (select id from topics)")


posts.destroy_all

または、.destroy_allfind_by_sql に追加することもできます。

「いいね!」 2

試しました。データは、投稿識別子とIDを含む配列として返されているようです(Delete deleted-posts permanently in bulk? - #45 by nathank を参照)。

.destroy_all を追加した場合、または提案された posts= を使用した場合に表示されるエラーは次のとおりです。

[2] pry(main)> posts.destroy_all
NoMethodError: undefined method destroy_all' for #<Array:0x000055fe7bc7fc98> from (pry):3:in pry

「いいね!」 1

ああ。それなら、

 p=posts.first

が post_id かどうかを確認してみてください。もしそうなら、

x=Post.find(p)
x.destroy

として、それらをループ処理できます。

クエリを、post_id の配列ではなく、投稿の配列を取得するようにラップする必要があると思います。

「いいね!」 1

ジェイさん、ありがとう。以下のような結果になります。

[3] pry(main)> p=
[3] pry(main)* posts.first
=> #<Post:0x0000563a24cab908 id: 150>
[4] pry(main)> x=Post.find(p)
ArgumentError: You are passing an instance of ActiveRecord::Base to `find`. Please pass the id of the object by calling `.id`.
from /var/www/discourse/vendor/bundle/ruby/2.7.0/gems/activerecord-6.1.4.1/lib/active_record/relation/finder_methods.rb:467:in `find_one'

さて、このラップについて教えてください。サムさんのRailsコマンドがここで機能するはずなのに、Railsがそれ以降変更されたと思うと、とてもイライラします。

「いいね!」 1

それは何をしたのですか? レールが変わったとは想像できません。

「いいね!」 1

それが破棄したい投稿を返しますか?

「いいね!」 1

Rails 3.x と Rails 4 の間で変更があり、構文が異なる必要があるとオンラインで検索した際にどこかで読みましたが、よく理解できませんでした。

最初に実行したときにいくつか取得され、それらを destroy_all しました。しかし、多くはありませんでした。現在、何も取得されませんが、SQL を Data Explorer で実行すると数千件が取得されます。

これらは、Topic が Destroy_all された孤立した投稿です。

「いいね!」 1

配列のメンバーを反復処理するためにeach{}を使用し、各投稿を個別にdestroyすることはできますか?

Post.find_by_sql(“select id from posts where topic_id not in (select id from topics)”).each { |p| p.destroy }
「いいね!」 2

Well, I’ve given it a try. First it didn’t like the SQL wrapped up like that nor the syntax:

Post.find_by_sql(“select id from posts where topic_id not in (select id from topics)”).each { |p| p.destroy_all }
SyntaxError: unexpected `in’, expecting ‘(’
…rom posts where topic_id not in (select id from topics)”)…
… ^~
SyntaxError: unexpected local variable or method, expecting end-of-input
…t in (select id from topics)”).each { |p| p.destroy_all }

So I had another hacky crack by splitting it up:

posts=Post.find_by_sql("select id from posts where topic_id not in (select id from topics)")
posts.each do |p|
p.destroy
end

This seemed to run okay, but adding the p.destroy throws this up:

ActiveModel::MissingAttributeError: missing attribute: user_id
from /var/www/discourse/vendor/bundle/ruby/2.7.0/gems/activemodel-6.1.4.1/lib/active_model/attribute.rb:222:in `value’

Tried a few ways to get that in there but then gave up. @sam, can you help?

P.S.

I even tried to convert the SQL to AR via scuttle.io as per this:

Post.select([:id, :topic_id]).where(Topic.select(:id))

Alas, I get this error:

ArgumentError: Unsupported argument type: #Topic::ActiveRecord_Relation:0x000055c67a7131d0 (Topic::ActiveRecord_Relation)

「いいね!」 3

前のメッセージからその部分をコピー&ペーストしたときに、どこかで引用符がカーリークォートに変換されたようです。それが本当のエラーだと思います。すみませんでした。

find_by_sql は、SQLクエリで指定された値を持つオブジェクトを返すように説明されています。これはおそらく、id プロパティのみが設定されており、user_id やその他のすべてが欠落している Post オブジェクトを取得していることを意味します。

... find_by_sql("select * ... で対応できます。すべてを選択するのではなく、破棄を達成するために選択できる値のサブセットがあるかもしれませんが、そのサブセットが何であるかはわかりません。

したがって、全体は次のようになります。(今回はカーリークォートなしで…)

Post.find_by_sql("select * from posts where topic_id not in (select id from topics)").each { |p| p.destroy }
「いいね!」 4

:partying_face: 万歳!!! :partying_face:

Simon、ありがとうございます。見事に機能しました。孤立した投稿はすべて削除され、今後24時間ほどでアップロードがほとんどなくなることを楽しみにしています。

後で
そして、そうなりました!3.5GBから0.7GBに。素晴らしい!!

「いいね!」 7

素晴らしい、お役に立てて嬉しいです。回答をまとめるために、Railsコンソールで以下を使用して、90日以上前に削除されたすべてのトピックを削除できます。1000件を超えるトピックがある場合は、必要に応じて繰り返してください。

Topic.with_deleted.where(deleted_at: ...90.days.ago).limit(1000).destroy_all

それが完了したら、削除されたトピックから孤立したすべての投稿を削除するために、以下を使用できます。

Post.find_by_sql("select * from posts where topic_id not in (select id from topics)").each { |p| p.destroy }

上記のコマンドは、削除されたトピックとその孤立した投稿のみを削除し、削除された投稿は削除しないことに注意してください。90日以上前の削除された投稿も削除するには、以下を使用します。必要に応じて繰り返してください。

Post.with_deleted.where(deleted_at: ...90.days.ago).limit(1000).destroy_all

追伸 ちなみに、limit(1000)なしでdestroy_allを試して問題が発生しましたか、それとも制限なしでは試しませんでしたか?

「いいね!」 8

制限なしで試したところ、少しおかしなことになりました。詳細は忘れてしまいましたが、すみません。

あなたの投稿を解決策としてマークすることはできますか、それともOPからのこれを使用できますか?

image

「いいね!」 3

心配いりません。もしあなたが試していなければ、制限は必要ないかもしれないという注釈を付けたでしょうが、問題があったので、そのままにしておきます。

「いいね!」 1

This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.