Переименование тегов в консоли Rails

Продолжение обсуждения из темы Невозможно исправить названия тегов с точками:

Здравствуйте,

Может ли кто-нибудь предоставить проверенное руководство по переименованию тегов в консоли Rails? У меня нет опыта работы с консолью Rails, и я не хочу повредить базу данных…

Подключение к серверу по SSH

cd /var/discourse
./launcher enter app
rails c

t = Tag.find_by_name('oldname')
t.name = 'newname'
t.save

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

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

Честный вопрос — разве переименование тега не подходит для этого?

Например, когда я использую тег chat здесь и, возможно, другие теги в разных темах, а затем вы переименовываете его в #chats. Тогда тег #chat будет указывать на несуществующий тег, поскольку он не был переименован. Таким образом, переименование работает корректно для заголовков тем, но не для комментариев внутри тем, когда люди уже использовали их. Или я что-то упускаю?

Огромное спасибо @RGJ, всё сработало как по маслу :pray: :pray: :pray:

Похоже, нет способа переименовать существующие теги, которые пользователи используют в темах? То есть не теги в заголовках тем, а именно в комментариях.

Используйте на свой страх и риск!

Сделайте это после того, как переименуете #foo в #bar

Post.where("raw like '%#foo%'").each do |p|
  p.raw = p.raw.gsub(/#foo\b/, '#bar')
  p.save!
end

Выглядит круто! Спасибо за предупреждение. Резервные копии снизят риски :nerd_face:.

Для моего понимания: "raw like '%#foo%'" — это строгое совпадение? То есть, что если у вас есть тег #access, который нужно переименовать в #access_granted, совпадет ли "raw like '%#access%'" и с #access, и с #access_granted? Потому что в таком случае существующие комментарии, которые уже используют #access_granted, возможно, будут переименованы в #accessaccess_granted.

Для сравнения с командой grep, переключатель --word-regexp помогает убедиться, что совпадают только целые слова.

Из страницы справки:

Выбирает только те строки, содержащие совпадения, образующие целые слова. Проверка заключается в том, что совпадающая подстрока должна находиться либо в начале строки, либо предшествовать символу, не входящему в состав слова. Аналогично, она должна находиться либо в конце строки, либо следовать за символом, не входящим в состав слова. Символами, входящими в состав слова, являются буквы, цифры и знак подчеркивания.

Работает ли эта команда аналогично? Конечно, я могу узнать это, сделав резервную копию и запустив команду. Но чтобы понять риски, если вы, конечно, это знаете. В противном случае — YOLO.

Конечно, вот перевод текста на русский язык:

"raw like '%#foo%'" действительно не является строгим совпадением, но в этом и нет необходимости. Поскольку запрос LIKE с % очень затратен с точки зрения производительности, я решил не усугублять ситуацию, требуя наличия после него не-буквенно-цифрового символа. Запрос where служит лишь для предварительного отбора — вы могли бы просто использовать Post.all.each, и это тоже сработало бы (хотя и значительно медленнее).

Непосредственная замена выполняется с помощью gsub, а \b гарантирует наличие границы слова после тега, то есть тег заканчивается именно в этом месте.

Таким образом, любые посты, содержащие #access_granted, будут найдены, и внутренний код выполнится, но в таком случае gsub ничего не изменит.

irb(main):010:0> "Tag #access is here".gsub(/#access\b/, "#access_granted")
=> "Tag #access_granted is here"
irb(main):011:0> "Tag #access_granted is here".gsub(/#access\b/, "#access_granted")
=> "Tag #access_granted is here"

Я хочу запустить это сейчас:

Post.where("raw like '%#access%'").each do |p|
  p.raw = p.raw.gsub(/#access\b/, '#strategic_access')
  p.save!
end

Post.where("raw like '%#feedback%'").each do |p|
  p.raw = p.raw.gsub(/#feedback\b/, '#digital_feedback')
  p.save!
end

Но я получаю ошибку bash: syntax error near unexpected token “raw like ‘%#access%’”'иbash: syntax error near unexpected token "raw like '%#feedback%'"'. Прежде чем я начну гадать, нужно ли экранировать символ #?

:point_up: это должно было идти после этого, код следует выполнять внутри rails c

О да, я даже не заметил ошибку в bash. Мне нужно больше спать… Спасибо!!