How to permanent delete a topic from database (with his posts)?


(Roberto_Pezzali) #1

I need a quick help: I’m importing my old forum because we finally go live and I have a problem: the import process halt on a discussion with 4.6k replies and now I have the topic imported for an half. I’m keeping the same ID, so I must delete the old topic (or move to another id). I cannot start from the beginning: it’s about 4 hour of import.

Is there a fast way to delete a topic from console?


(Sam Saffron) #2

Topic.destroy(id) may work (I think it will nuke the dependent objects)


Using topic.destroy(id) to delete illegal content
(Sam Stickland) #3

I’m not so sure about this. I tried this just now with a similar failed import:

my_category.topics.where.not(id: 12).each { |t| t.destroy }

And I found that I had orphaned posts, which started giving this error:

undefined method `title' for nil:NilClass
/var/www/discourse/app/models/post_action.rb:216:in `create_message_for_post_action'

I tried to fix that with:

Post.all.select { |p| p.topic.nil? }.each { |p| p.destroy }

But there’s clearly still some more orphaned objects, as the error now morphed into:

undefined method `topic' for nil:NilClass
/var/www/discourse/app/models/post_action.rb:216:in `create_message_for_post_action'

What else should I remove to fix this?


(Sam Saffron) #4

next up is post_actions, but you are on your own here, this is not really a supported scenario.


Using topic.destroy(id) to delete illegal content
(Sam Stickland) #5

Yeah, I’ve just searched for “belongs_to :post” and found the many objects I need to look at! Oh well :smile:

I’d just assumed destroying a post via the console would trigger callbacks, but I guess not?


(Sam Stickland) #6

Tbh, I need to start digging into the codebase at some point anyway, as I suspect we will be needing to make some additional customisations for integration into our site.


(Sam Stickland) #7

Well, in case anyone else stumbles across this topic, I got as far as doing this:

objs = Post.all.select { |obj| obj.topic.nil? }
puts "Post: #{objs.count}"
objs.each { |obj| obj.destroy }; nil

%w(TopicLink PostSearchData PostUpload PostDetail PostAction Permalink EmailLog PostRevision UserBadge IncomingLink QuotedPost UserHistory TopicEmbed).each do |classname|
  objs = classname.constantize.all.select { |obj| obj.post.nil? }
  puts "#{classname}: #{objs.count}"
  objs.each { |obj| obj.destroy }
end; nil

The PostReply tablle is tricker because it doesn’t have a primary key, so you can’t call destroy directly.

After doing this though I remembered I had turned on daily backups, so I simply did a restore :slight_smile: