Перенос сайта, использующего интеграции Discourse для комментариев

Всем привет,

Я использую интеграции Discourse для размещения комментариев к блогу, который находится на поддомене, но хочу перенести блог в подкаталог основного домена.

Например: сейчас блог находится по адресу

blog.somedomain.com

но я хочу перенести его по адресу

somedomain.com/blog

Как обновить существующие темы комментариев Discourse, чтобы они указывали на новое расположение блога?

Я предполагаю, что могу вручную обновить содержимое постов, но вызовет ли посещение нового сайта блога создание новых тем, поскольку они теперь находятся по другому URL?

(Блог работает на Ghost, на случай если это важно).

Буду благодарен за любую помощь.
Брэд

Недавно я сталкивался с чем-то подобным. В том случае сайт уже изменил домен своего блога. В результате этого для всех постов блога, у которых уже были созданы темы в Discourse, были сгенерированы дубликаты тем.

Решением стало выполнение скрипта из консоли Rails сайта для поиска всех записей TopicEmbed, у которых embed_url указывал на старый домен. Значения embed_url были обновлены на правильный домен после удаления записи TopicEmbed для дублирующейся темы. Затем были удалены новые темы, которые были созданы.

Это кажется сложным способом решения проблемы. Я могу опубликовать подробности о скрипте, который использовал, но было бы здорово услышать, есть ли у кого-то другие идеи по подходу к этой задаче. Это вопрос, который неизбежно будет возникать время от времени при использовании встроенных тем.

Привет, Саймон,

Спасибо.

Это было бы здорово (и любая информация о том, как его запустить, была бы полезна).

Думаю, мне придётся вручную обновлять содержимое постов, где есть ссылки на оригинальную статью. (То есть ту часть текста поста, где написано: «Это тема для обсуждения, сопутствующая оригинальной записи по адресу…».)

Я согласен — это что-то, что нужно делать редко, но когда приходится, это кажется сплошной головной болью.

Брэд

Я поделюсь здесь скриптом. Имейте в виду, что я не уверен, что это лучший подход к решению проблемы. Скрипт нужно запускать после того, как начнут создаваться дубликаты тем в результате изменения доменного имени. Поскольку темы не будут созданы, пока пользователи не начнут посещать ваши записи блога по новому домену, вам, вероятно, придется запускать скрипт несколько раз, чтобы обработать все темы. Обязательно замените old.domain.com в первой строке скрипта на реальный домен, на котором ранее находился ваш блог.

# Сначала выполните это:
original_embeds = TopicEmbed.where("embed_url LIKE ?", "%old.domain.com%")

# Затем:
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 "Удаление записи TopicEmbed: #{new_embed.id}, Тема: #{new_embed.topic_id}"
      new_embed.destroy
      puts "Обновление записи TopicEmbed: #{original_embed.id}, Новый embed_url: #{new_embed_url}"
      original_embed.update(embed_url: new_embed_url)
    end
  end
end

Чтобы запустить скрипт, откройте консоль Rails вашего сайта, скопируйте первую строку скрипта в консоль и выполните её. Это присвоит переменной original_embeds массив записей TopicEmbed. После этого вы можете скопировать остальную часть скрипта в консоль и запустить его.

Для безопасности перед запуском скрипта создайте резервную копию базы данных вашего сайта. Также рекомендуется выполнить тестовый прогон скрипта, который не вносит никаких изменений. Для этого используйте следующий код:

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 "(Тестовый прогон) Удаление записи TopicEmbed: #{new_embed.id}, Тема: #{new_embed.topic_id}"
      #new_embed.destroy
      puts "(Тестовый прогон) Обновление записи TopicEmbed: #{original_embed.id}, Новый embed_url: #{new_embed_url}"
      #original_embed.update(embed_url: new_embed_url)
    end
  end
end

Убедитесь, что вывод выглядит разумным, прежде чем раскомментировать строки, которые вносят фактические изменения в вашу базу данных.

Что делает скрипт:

  • переменная original_embeds получает все записи TopicEmbed, соответствующие старому домену вашего блога

  • для каждой записи из original_embeds скрипт пытается найти тему с дублирующимся заголовком (новый дублирующийся встраиваемый элемент)

  • если найдена дублирующаяся тема и для неё найдена запись TopicEmbed, эта запись удаляется, а значение её свойства embed_url переносится в старую запись TopicEmbed.

Настоятельно рекомендую сначала выполнить тестовый прогон (используя второй скрипт из этого сообщения), прежде чем запускать скрипт, который вносит реальные изменения. Если тестовый прогон выдаст какие-либо ошибки, вам нужно будет выяснить их причину. Просматривая код сейчас, я вижу возможную проблему: она может возникнуть, если на вашем сайте Discourse есть тема с заголовком, дублирующим заголовок встраиваемой темы, но у которой нет связанной записи TopicEmbed. Если это так, эту ситуацию можно будет исправить.

Привет, Саймон,

Это действительно полезно. Спасибо.

В моём случае всё ещё проще, так как блог ещё не был перенесён, и у меня нет дубликатов. Думаю, мне нужно лишь обновить существующие записи встраивания, указав новый URL.

Я никогда раньше не использовал Ruby, но на основе вашего примера я набросал скрипт ниже. Помимо обновления встраиваний тем, я также расширил его для обновления текста и ссылок в соответствующих постах.

Не могли бы вы быстро взглянуть, чтобы убедиться, что я на правильном пути? Я запустил его с закомментированными обновлениями, и похоже, что всё отображается правильно.

(кстати: какой обычно способ запуска таких скриптов? Я редактирую их в текстовом редакторе, а затем вставляю в консоль)

Брэд

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

Для справки: вышеуказанное сработало отлично. Вот полный процесс, которому я следовал:

  1. Перевёл Discourse в режим только для чтения
  2. Создал резервную копию
  3. Запустил указанный выше скрипт
  4. Проверил, что страницы Discourse обновлены корректно
  5. Остановил старый блог и запустил новый
  6. Настроил перенаправление со старого сайта блога на новый
  7. Отключил режим только для чтения в Discourse
  8. Перенастроил встраивание Discourse, чтобы запретить старый домен и разрешить новый
  9. Настроил встраивание на новом блоге.

Большое спасибо @simon за помощь в этом. :+1: