How do I update the existing discourse comment topics to point to the new blog location?
I guess I can manually update the posts contents, but will visiting the new blog site cause new topics to be created since they’re at a different url now?
I dealt with something similar to this recently. In that case the site had gone ahead and changed the domain of their blog. The result of doing that was that duplicate topics were created on Discourse for any of their blog posts that had already generated Discourse topics.
The solution was to run a script from the site’s Rails console to find all TopicEmbed entries that had an embed_url on the old domain. Those embed_url values were then updated to the correct domain after deleting the TopicEmbed entry for the duplicate topic. The new topics that had been generated were then deleted.
This seems like a difficult way to solve the issue. I can post details about the script that I used, but it would be great to hear if anyone else has ideas about how to approach the problem. It’s something that is bound to come up from time to time with embedded topics.
That would be awesome (and any info on how to run it would be helpful).
I guess I’ll need to manually update the post contents where they link back to the original article. (ie: the part of the post text that says “This is a companion discussion topic for the original entry at…”).
I agree - something that rarely needs to be done but seems like a total pain when it does.
I’ll share the script here. Keep in mind that I’m not certain that this is the best approach to the problem. The script needs to be run after duplicate topics have started to be created as a result of the domain name change. Since the topics will not get created until users have started to visit your blog posts at the new domain name, you’ll probably have to run the script multiple times to catch all the topics. Be sure to replace old.domain.com from the first line of the script with the actual domain that your blog used to be at.
# Run this first:
original_embeds = TopicEmbed.where("embed_url LIKE ?", "%old.domain.com%")
# Then:
original_embeds.each do |original_embed|
original_topic = Topic.find(original_embed.topic_id)
if (original_topic && original_topic.title)
possible_dups = Topic.where(title: original_topic.title).order(:created_at)
if possible_dups.length === 2
new_embed = TopicEmbed.find_by(topic_id: possible_dups.last.id)
new_embed_url = new_embed.embed_url
puts "Destroying TopicEmbed: #{new_embed.id} Topic: #{new_embed.topic_id}"
new_embed.destroy
puts "Updating TopicEmbed: #{original_embed.id} New embed_url: #{new_embed_url}"
original_embed.update(embed_url: new_embed_url)
end
end
end
To run the script, enter your site’s Rails console, then copy the first line of the script into the console and execute it. This will set the original_embeds variable to an array of TopicEmbed records. Once that’s been done, you can copy the rest of the script into the console and run it.
To be safe, you should create a backup of your site’s database before running the script. It would also be a good idea to do a dry run of the script that doesn’t make any changes. This will work for that:
original_embeds.each do |original_embed|
original_topic = Topic.find(original_embed.topic_id)
if (original_topic && original_topic.title)
possible_dups = Topic.where(title: original_topic.title).order(:created_at)
if possible_dups.length === 2
new_embed = TopicEmbed.find_by(topic_id: possible_dups.last.id)
new_embed_url = new_embed.embed_url
puts "(Dry run) Destroying TopicEmbed: #{new_embed.id} Topic: #{new_embed.topic_id}"
#new_embed.destroy
puts "(Dry run) Updating TopicEmbed: #{original_embed.id} New embed_url: #{new_embed_url}"
#original_embed.update(embed_url: new_embed_url)
end
end
end
Make sure the output seems reasonable before uncommenting the lines that make the actual changes to your database.
What the script is doing:
the original_embeds variable gets set to all TopicEmbed records that match your blog’s old domain
for each of the original_embeds it tries to find a topic with a duplicate title (the new duplicate embed)
if a duplicate topic is found, and a TopicEmbed record is found for the duplicate topic, that TopicEmbed record is deleted and the value of its embed_url property is transferred to the old TopicEmbed record.
I would make sure to do a dry run (using the second script from this post) before running the script that actually makes changes. If any errors are returned from the dry run you’ll have to see what’s causing them. Looking at the code now, I can see a possible issue that could occur if there was a topic on your Discourse site that had a duplicate title to an embedded topic, but did not have a TopicEmbed associated with it. If that’s the case it’s something that could be dealt with.
In my case I think things are even simpler since the blog site hasn’t been moved yet and I don’t have any duplicates. I think all I need to do is update the existing embed entries with the new url.
I’ve never used ruby before, but from your example I’ve hacked together the script below. In addition to updating the topic embeds I’ve extended it to also update the text and links in the associated posts.
Would you mind giving it a quick look over to make sure I’m on the right track? I’ve run it with the updates commented out and it seems to be displaying the right stuff.
(btw: what’s the normal way to run these scripts? I’ve been editing in a text editor and then pasting into the console)
Brad
original_embeds = TopicEmbed.where("embed_url LIKE ?", "https://blog.cantabilesoftware.com%")
old_url_prefix = "https://blog.cantabilesoftware.com/"
new_url_prefix = "https://www.cantabilesoftware.com/blog/"
original_embeds.each do |original_embed|
new_embed_url = original_embed.embed_url
new_embed_url.sub!(old_url_prefix, new_url_prefix)
puts "Updating TopicEmbed: #{original_embed.id} with new url: #{new_embed_url}"
#original_embed.update(embed_url: new_embed_url)
post = Post.find_by(id: original_embed.post_id)
new_raw = post.raw
new_raw.gsub!(old_url_prefix, new_url_prefix)
new_cooked = post.cooked
new_cooked.gsub!(old_url_prefix, new_url_prefix)
puts "Updating raw with #{new_raw}"
puts "Updating cooked with #{new_cooked}"
#post.update(raw: new_raw, cooked: new_cooked)
end