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
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
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.
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

This might be the cause that your db still contains orphaned posts.
これは、ラベルが 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)')
=> []
何が間違っているのか誰か教えてもらえませんか?
@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 を適用する方法がわかりません。
これは(私の利益のために)役立つかもしれません。
何か提案はありますか?
これでうまくいくと思います
posts=
Post.find_by_sql("select id from posts where topic_id not in (select id from topics)")
posts.destroy_all
または、.destroy_all を find_by_sql に追加することもできます。
試しました。データは、投稿識別子とIDを含む配列として返されているようです(Delete deleted-posts permanently in bulk? - #45 by nathank を参照)。
.destroy_all を追加した場合、または提案された posts= を使用した場合に表示されるエラーは次のとおりです。
[2] pry(main)> posts.destroy_all
NoMethodError: undefined methoddestroy_all' for #<Array:0x000055fe7bc7fc98> from (pry):3:inpry’
ああ。それなら、
p=posts.first
が post_id かどうかを確認してみてください。もしそうなら、
x=Post.find(p)
x.destroy
として、それらをループ処理できます。
クエリを、post_id の配列ではなく、投稿の配列を取得するようにラップする必要があると思います。
ジェイさん、ありがとう。以下のような結果になります。
[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がそれ以降変更されたと思うと、とてもイライラします。
それは何をしたのですか? レールが変わったとは想像できません。
それが破棄したい投稿を返しますか?
Rails 3.x と Rails 4 の間で変更があり、構文が異なる必要があるとオンラインで検索した際にどこかで読みましたが、よく理解できませんでした。
最初に実行したときにいくつか取得され、それらを destroy_all しました。しかし、多くはありませんでした。現在、何も取得されませんが、SQL を Data Explorer で実行すると数千件が取得されます。
これらは、Topic が Destroy_all された孤立した投稿です。
配列のメンバーを反復処理するためにeach{}を使用し、各投稿を個別にdestroyすることはできますか?
Post.find_by_sql(“select id from posts where topic_id not in (select id from topics)”).each { |p| p.destroy }
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?
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)
前のメッセージからその部分をコピー&ペーストしたときに、どこかで引用符がカーリークォートに変換されたようです。それが本当のエラーだと思います。すみませんでした。
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 }
Simon、ありがとうございます。見事に機能しました。孤立した投稿はすべて削除され、今後24時間ほどでアップロードがほとんどなくなることを楽しみにしています。
後で
そして、そうなりました!3.5GBから0.7GBに。素晴らしい!!
素晴らしい、お役に立てて嬉しいです。回答をまとめるために、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を試して問題が発生しましたか、それとも制限なしでは試しませんでしたか?
制限なしで試したところ、少しおかしなことになりました。詳細は忘れてしまいましたが、すみません。
あなたの投稿を解決策としてマークすることはできますか、それともOPからのこれを使用できますか?

心配いりません。もしあなたが試していなければ、制限は必要ないかもしれないという注釈を付けたでしょうが、問題があったので、そのままにしておきます。
This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.