mirror of
https://github.com/discourse/discourse.git
synced 2026-08-07 13:19:19 +08:00
Previously, flag names with no ASCII word characters (e.g. Chinese) all normalized to the same `name_key` of `custom_`, because `set_name_key` stripped non-`\w` characters and Ruby's `\w` is ASCII-only. The flag system keys lookups by `name_key` (the `disabled_flag_types` enum, the frontend `actionByName` map), so once two flags shared a key, disabling one of them flipped `can_act` for the whole group and hid every other flag that shared it. This makes `name_key` reliably unique: - `set_name_key` falls back to `custom_flag` when the slug is empty and appends a counter (`_2`, `_3`, ...) on collision, so distinct names always produce distinct keys. It now only re-derives the key when the name actually changes, keeping it stable across other saves. - A post-deploy migration backfills existing duplicate keys and adds the unique index on `flags.name_key` that the original `create_flags` migration intended (`unique: true` is a no-op in `create_table`). https://meta.discourse.org/t/405254
22 lines
509 B
Ruby
Vendored
22 lines
509 B
Ruby
Vendored
# frozen_string_literal: true
|
|
|
|
class EnsureUniqueFlagNameKeys < ActiveRecord::Migration[8.0]
|
|
def up
|
|
execute(<<~SQL)
|
|
UPDATE flags
|
|
SET name_key = name_key || '_' || id
|
|
WHERE name_key IS NOT NULL
|
|
AND id <> (
|
|
SELECT MIN(other.id)
|
|
FROM flags other
|
|
WHERE other.name_key = flags.name_key
|
|
)
|
|
SQL
|
|
|
|
add_index :flags, :name_key, unique: true, if_not_exists: true
|
|
end
|
|
|
|
def down
|
|
remove_index :flags, :name_key, if_exists: true
|
|
end
|
|
end
|