Discourse Retort

Ну что ж, это наконец произошло: я не смог обновить Discourse из-за плагина retort.

Вот ошибка миграции базы данных, которую я получил:

could not create unique index "index_post_details_on_post_id_and_key_ccnew_ccnew"                                                 DETAIL:  Key (post_id, key)=(30297, +1|retort) is duplicated.

Я использовал этот скрипт как основу для своего собственного кода миграции. Вот что я сделал:

  • Чтобы снова запустить Discourse, мне пришлось переопределить параметр “version” в шаблоне .yml, указав коммит примерно двухнедельной давности из репозитория Discourse.
  • Пересобрал образ, добавив плагин reactions, чтобы вернуть сайт в строй.
  • Настроил плагин reactions с тем же набором реакций, что и у retort. Я не использую ни одной реакции, которую можно было бы интерпретировать как «лайк».
  • Немного модифицировал и использовал скрипт от @mcdanlj со следующими шагами (так как я хотел мигрировать все retorts, и у меня уже было соответствие 1-к-1 между retorts и reactions):
  • Выполните ./launcher enter app.
  • Выполните rails c.
  • Вставьте следующий код (кажется, что консоль Rails возвращает код с неверными переносами строк; я добавил двойные переносы, но это не сильно изменило вывод. Однако, если у кого-то возникнет ошибка синтаксиса при использовании следующего кода, добавьте дополнительную пустую строку после каждой строки):
def migrateRetortToReactions()
  retort = "retort".freeze
  emojiType = "emoji".freeze
  usermap = Hash.new { |hash, username| hash[username] = User.find_by_username(username) }
  postmap = Hash.new { |hash, post_id| hash[post_id] = Post.find(post_id) }
  likeType = PostActionType.where(name_key: "like").pluck(:id).first
  PostDetail.where(extra: retort).each do |pd|
    begin
      p = postmap[pd.post_id]
    rescue
      # PostDetail не согласован относительно удаления
      $stderr.puts sprintf("Could not find post for %d: %s / %s", pd.post_id, pd.key, pd.value)
      next
    end

    emoji = pd.key.split('|').first
    users = JSON.parse(pd.value)
    users.each do |user|
      u = usermap[user]
      next if u.nil? # изменилось имя пользователя или он был удалён, оставив сиротские Retorts
      e = emoji
      r = DiscourseReactions::Reaction.where(post_id: p.id, reaction_type: emojiType, reaction_value: e).first_or_create
      ru = DiscourseReactions::ReactionUser.where(user_id: u.id, post_id: p.id).first
      next unless ru.nil?
      $stderr.puts sprintf("Converting Retort %s to Reaction %s for user %s in %s", emoji, e, user, p.url)
      DiscourseReactions::ReactionUser.create(reaction_id: r.id, user_id: u.id, post_id: p.id, created_at: pd.created_at)
    end
  end
end
  • На этом этапе я сделал резервную копию сайта на всякий случай.
  • Затем выполнил migrateRetortToReactions, что должно занять некоторое время. У меня не возникло никаких проблем. После выполнения в консоли отображаются все изменённые объекты, поэтому нажмите q, чтобы выйти.
  • Теперь на сайте данные должны быть мигрированы корректно.
  • В качестве последнего шага необходимо выполнить: PostDetail.where(extra: "retort").destroy_all, что удалит все данные retort.
  • После этого я смог пересобрать свой сайт с последней версией Discourse и без плагина retort.

В целом, миграция не так уж сложна, но была довольно пугающей. Как уже обсуждалось ранее, это перезаписывает лайки реакциями на постах, где один и тот же пользователь оставил и лайки, и retorts.

6 лайков