diff --git a/db/data/20251203183631_create_weapon_series_records.rb b/db/data/20251203183631_create_weapon_series_records.rb new file mode 100644 index 0000000..51188be --- /dev/null +++ b/db/data/20251203183631_create_weapon_series_records.rb @@ -0,0 +1,77 @@ +# frozen_string_literal: true + +class CreateWeaponSeriesRecords < ActiveRecord::Migration[8.0] + def up + # Canonical weapon series data matching the frontend JSON exactly + weapon_series_data = [ + { order: 0, slug: 'gacha', name_en: 'Gacha Weapons', name_jp: 'ガチャ武器' }, + { order: 1, slug: 'seraphic', name_en: 'Seraphic Weapons', name_jp: 'セラフィックウェポン' }, + { order: 2, slug: 'grand', name_en: 'Grand Weapons', name_jp: 'リミテッドシリーズ' }, + { order: 3, slug: 'dark-opus', name_en: 'Dark Opus Weapons', name_jp: '終末の神器', has_weapon_keys: true }, + { order: 4, slug: 'destroyer', name_en: 'Destroyer Weapons', name_jp: '破壊の標', extra: true, has_weapon_keys: true }, + { order: 5, slug: 'draconic', name_en: 'Draconic Weapons', name_jp: 'ドラコニックウェポン・オリジン', has_weapon_keys: true }, + { order: 6, slug: 'draconic-providence', name_en: 'Draconic Weapons Providence', name_jp: 'ドラコニックウェポン', extra: true, has_weapon_keys: true }, + { order: 7, slug: 'new-world-foundation', name_en: 'New World Foundation', name_jp: '新世界の礎', extra: true }, + { order: 8, slug: 'astral', name_en: 'Astral Weapons', name_jp: 'アストラルウェポン' }, + { order: 9, slug: 'ultima', name_en: 'Ultima Weapons', name_jp: 'オメガウェポン', element_changeable: true, has_weapon_keys: true }, + { order: 10, slug: 'bahamut', name_en: 'Bahamut Weapons', name_jp: 'バハムートウェポン', extra: true }, + { order: 11, slug: 'cosmos', name_en: 'Cosmos Weapons', name_jp: 'コスモスシリーズ' }, + { order: 12, slug: 'hollowsky', name_en: 'Hollowsky Weapons', name_jp: '虚ろなる神器' }, + { order: 13, slug: 'omega', name_en: 'Omega Weapons', name_jp: 'マグナシリーズ' }, + { order: 14, slug: 'regalia', name_en: 'Regalia Weapons', name_jp: 'レガリアシリーズ' }, + { order: 15, slug: 'omega-rebirth', name_en: 'Omega Rebirth Weapons', name_jp: 'マグナ・リバースシリーズ' }, + { order: 16, slug: 'malice', name_en: 'Malice Weapons', name_jp: 'マリスシリーズ' }, + { order: 17, slug: 'menace', name_en: 'Menace Weapons', name_jp: 'メネスシリーズ' }, + { order: 18, slug: 'ennead', name_en: 'Ennead Weapons', name_jp: 'エニアドシリーズ' }, + { order: 19, slug: 'ancestral', name_en: 'Ancestral Weapons', name_jp: 'アンセスタルシリーズ' }, + { order: 20, slug: 'revans', name_en: 'Revans Weapons', name_jp: 'レヴァンスウェポン', has_awakening: true }, + { order: 21, slug: 'revenant', name_en: 'Revenant Weapons', name_jp: '天星器', element_changeable: true }, + { order: 22, slug: 'celestial', name_en: 'Celestial Weapons', name_jp: '極星器', extra: true, has_awakening: true }, + { order: 23, slug: 'xeno', name_en: 'Xeno Weapons', name_jp: '六道武器' }, + { order: 24, slug: 'exo', name_en: 'Exo Weapons', name_jp: 'エクスウェポン', has_awakening: true }, + { order: 25, slug: 'beast', name_en: 'Beast Weapons', name_jp: '四象武器' }, + { order: 26, slug: 'proven', name_en: 'Proven Weapons', name_jp: 'ブレイブウェポン', has_awakening: true }, + { order: 27, slug: 'superlative', name_en: 'Superlative Weapons', name_jp: 'スペリオシリーズ', element_changeable: true }, + { order: 28, slug: 'illustrious', name_en: 'Illustrious Weapons', name_jp: 'ルミナスシリーズ' }, + { order: 29, slug: 'vintage', name_en: 'Vintage Weapons', name_jp: 'ヴィンテージシリーズ' }, + { order: 30, slug: 'class-champion', name_en: 'Class Champion Weapons', name_jp: '英雄武器', element_changeable: true, has_weapon_keys: true }, + { order: 31, slug: 'rose', name_en: 'Rose Weapons', name_jp: 'ローズシリーズ' }, + { order: 32, slug: 'primal', name_en: 'Primal Weapons', name_jp: 'プライマルシリーズ' }, + { order: 33, slug: 'olden-primal', name_en: 'Olden Primal Weapons', name_jp: 'オールド・プライマルシリーズ' }, + { order: 34, slug: 'epic', name_en: 'Epic Weapons', name_jp: 'エピックウェポン' }, + { order: 35, slug: 'militis', name_en: 'Militis Weapons', name_jp: 'ミーレスシリーズ', extra: true }, + { order: 36, slug: 'sephira', name_en: 'Sephira Weapons', name_jp: 'セフィラン・オールドウェポン', extra: true }, + { order: 37, slug: 'world', name_en: 'World Weapons', name_jp: 'ワールドシリーズ', extra: true, has_awakening: true }, + { order: 38, slug: 'replica', name_en: 'Replicas', name_jp: '複製品' }, + { order: 39, slug: 'rusted', name_en: 'Rusted Weapons', name_jp: '朽ち果てた武器' }, + { order: 40, slug: 'relic', name_en: 'Relics', name_jp: '依代' }, + { order: 41, slug: 'eternal-splendor', name_en: 'Weapons of Eternal Splendor', name_jp: '十天光輝' }, + { order: 42, slug: 'vyrmament', name_en: 'Vyrmament', name_jp: 'オイラは' }, + { order: 43, slug: 'collab', name_en: 'Collab', name_jp: 'コラボ武器' }, + { order: 44, slug: 'event', name_en: 'Event', name_jp: 'イベント武器' } + ] + + puts "Creating weapon series records..." + weapon_series_data.each do |data| + ws = WeaponSeries.find_or_initialize_by(slug: data[:slug]) + ws.assign_attributes( + name_en: data[:name_en], + name_jp: data[:name_jp], + order: data[:order], + extra: data[:extra] || false, + element_changeable: data[:element_changeable] || false, + has_weapon_keys: data[:has_weapon_keys] || false, + has_awakening: data[:has_awakening] || false, + has_ax_skills: data[:has_ax_skills] || false + ) + ws.save! + puts " #{ws.slug}: #{ws.name_en}" + end + + puts "\nCreated #{WeaponSeries.count} weapon series records" + end + + def down + WeaponSeries.delete_all + end +end diff --git a/db/data/20251203183631_populate_weapon_series_and_migrate.rb b/db/data/20251203183631_populate_weapon_series_and_migrate.rb deleted file mode 100644 index 02315c7..0000000 --- a/db/data/20251203183631_populate_weapon_series_and_migrate.rb +++ /dev/null @@ -1,128 +0,0 @@ -# frozen_string_literal: true - -class PopulateWeaponSeriesAndMigrate < ActiveRecord::Migration[8.0] - def up - # Canonical weapon series data matching the frontend JSON exactly - # legacy_id maps to the current Weapon.series integer column (from SERIES_SLUGS) - weapon_series_data = [ - { legacy_id: 99, order: 0, slug: 'gacha', name_en: 'Gacha Weapons', name_jp: 'ガチャ武器' }, - { legacy_id: 1, order: 1, slug: 'seraphic', name_en: 'Seraphic Weapons', name_jp: 'セラフィックウェポン' }, - { legacy_id: 2, order: 2, slug: 'grand', name_en: 'Grand Weapons', name_jp: 'リミテッドシリーズ' }, - { legacy_id: 3, order: 3, slug: 'dark-opus', name_en: 'Dark Opus Weapons', name_jp: '終末の神器', has_weapon_keys: true }, - { legacy_id: nil, order: 4, slug: 'destroyer', name_en: 'Destroyer Weapons', name_jp: '破壊の標', extra: true, has_weapon_keys: true }, - { legacy_id: 27, order: 5, slug: 'draconic', name_en: 'Draconic Weapons', name_jp: 'ドラコニックウェポン・オリジン', has_weapon_keys: true }, - { legacy_id: 40, order: 6, slug: 'draconic-providence', name_en: 'Draconic Weapons Providence', name_jp: 'ドラコニックウェポン', extra: true, has_weapon_keys: true }, - { legacy_id: 30, order: 7, slug: 'new-world-foundation', name_en: 'New World Foundation', name_jp: '新世界の礎', extra: true }, - { legacy_id: 26, order: 8, slug: 'astral', name_en: 'Astral Weapons', name_jp: 'アストラルウェポン' }, - { legacy_id: 13, order: 9, slug: 'ultima', name_en: 'Ultima Weapons', name_jp: 'オメガウェポン', element_changeable: true, has_weapon_keys: true }, - { legacy_id: 14, order: 10, slug: 'bahamut', name_en: 'Bahamut Weapons', name_jp: 'バハムートウェポン', extra: true }, - { legacy_id: 16, order: 11, slug: 'cosmos', name_en: 'Cosmos Weapons', name_jp: 'コスモスシリーズ' }, - { legacy_id: 10, order: 12, slug: 'hollowsky', name_en: 'Hollowsky Weapons', name_jp: '虚ろなる神器' }, - { legacy_id: 8, order: 13, slug: 'omega', name_en: 'Omega Weapons', name_jp: 'マグナシリーズ' }, - { legacy_id: 7, order: 14, slug: 'regalia', name_en: 'Regalia Weapons', name_jp: 'レガリアシリーズ' }, - { legacy_id: 42, order: 15, slug: 'omega-rebirth', name_en: 'Omega Rebirth Weapons', name_jp: 'マグナ・リバースシリーズ' }, - { legacy_id: 33, order: 16, slug: 'malice', name_en: 'Malice Weapons', name_jp: 'マリスシリーズ' }, - { legacy_id: 34, order: 17, slug: 'menace', name_en: 'Menace Weapons', name_jp: 'メネスシリーズ' }, - { legacy_id: 31, order: 18, slug: 'ennead', name_en: 'Ennead Weapons', name_jp: 'エニアドシリーズ' }, - { legacy_id: 29, order: 19, slug: 'ancestral', name_en: 'Ancestral Weapons', name_jp: 'アンセスタルシリーズ' }, - { legacy_id: 37, order: 20, slug: 'revans', name_en: 'Revans Weapons', name_jp: 'レヴァンスウェポン', has_awakening: true }, - { legacy_id: 4, order: 21, slug: 'revenant', name_en: 'Revenant Weapons', name_jp: '天星器', element_changeable: true }, - { legacy_id: 41, order: 22, slug: 'celestial', name_en: 'Celestial Weapons', name_jp: '極星器', extra: true, has_awakening: true }, - { legacy_id: 11, order: 23, slug: 'xeno', name_en: 'Xeno Weapons', name_jp: '六道武器' }, - { legacy_id: 39, order: 24, slug: 'exo', name_en: 'Exo Weapons', name_jp: 'エクスウェポン', has_awakening: true }, - { legacy_id: 6, order: 25, slug: 'beast', name_en: 'Beast Weapons', name_jp: '四象武器' }, - { legacy_id: 36, order: 26, slug: 'proven', name_en: 'Proven Weapons', name_jp: 'ブレイブウェポン', has_awakening: true }, - { legacy_id: 17, order: 27, slug: 'superlative', name_en: 'Superlative Weapons', name_jp: 'スペリオシリーズ', element_changeable: true }, - { legacy_id: 35, order: 28, slug: 'illustrious', name_en: 'Illustrious Weapons', name_jp: 'ルミナスシリーズ' }, - { legacy_id: 18, order: 29, slug: 'vintage', name_en: 'Vintage Weapons', name_jp: 'ヴィンテージシリーズ' }, - { legacy_id: 19, order: 30, slug: 'class-champion', name_en: 'Class Champion Weapons', name_jp: '英雄武器', element_changeable: true, has_weapon_keys: true }, - { legacy_id: 12, order: 31, slug: 'rose', name_en: 'Rose Weapons', name_jp: 'ローズシリーズ' }, - { legacy_id: 5, order: 32, slug: 'primal', name_en: 'Primal Weapons', name_jp: 'プライマルシリーズ' }, - { legacy_id: 9, order: 33, slug: 'olden-primal', name_en: 'Olden Primal Weapons', name_jp: 'オールド・プライマルシリーズ' }, - { legacy_id: 15, order: 34, slug: 'epic', name_en: 'Epic Weapons', name_jp: 'エピックウェポン' }, - { legacy_id: 32, order: 35, slug: 'militis', name_en: 'Militis Weapons', name_jp: 'ミーレスシリーズ', extra: true }, - { legacy_id: 23, order: 36, slug: 'sephira', name_en: 'Sephira Weapons', name_jp: 'セフィラン・オールドウェポン', extra: true }, - { legacy_id: 38, order: 37, slug: 'world', name_en: 'World Weapons', name_jp: 'ワールドシリーズ', extra: true, has_awakening: true }, - { legacy_id: 20, order: 38, slug: 'replica', name_en: 'Replicas', name_jp: '複製品' }, - { legacy_id: 22, order: 39, slug: 'rusted', name_en: 'Rusted Weapons', name_jp: '朽ち果てた武器' }, - { legacy_id: 21, order: 40, slug: 'relic', name_en: 'Relics', name_jp: '依代' }, - { legacy_id: 28, order: 41, slug: 'eternal-splendor', name_en: 'Weapons of Eternal Splendor', name_jp: '十天光輝' }, - { legacy_id: 24, order: 42, slug: 'vyrmament', name_en: 'Vyrmament', name_jp: 'オイラは' }, - { legacy_id: 43, order: 43, slug: 'collab', name_en: 'Collab', name_jp: 'コラボ武器' }, - { legacy_id: 98, order: 44, slug: 'event', name_en: 'Event', name_jp: 'イベント武器' } - ] - - # Build mapping from legacy series integer to new weapon_series_id - legacy_to_uuid = {} - - puts "Creating/updating weapon series records..." - weapon_series_data.each do |data| - ws = WeaponSeries.find_or_initialize_by(slug: data[:slug]) - ws.assign_attributes( - name_en: data[:name_en], - name_jp: data[:name_jp], - order: data[:order], - extra: data[:extra] || false, - element_changeable: data[:element_changeable] || false, - has_weapon_keys: data[:has_weapon_keys] || false, - has_awakening: data[:has_awakening] || false, - has_ax_skills: data[:has_ax_skills] || false - ) - ws.save! - legacy_to_uuid[data[:legacy_id]] = ws.id if data[:legacy_id].present? - puts " #{ws.slug}: #{ws.name_en}" - end - - puts "\nMigrating weapons to use weapon_series_id..." - migrated = 0 - skipped = 0 - - Weapon.find_each do |weapon| - next if weapon.series.blank? - - weapon_series_id = legacy_to_uuid[weapon.series.to_i] - if weapon_series_id - weapon.update_column(:weapon_series_id, weapon_series_id) - migrated += 1 - else - puts " Warning: No weapon_series found for legacy series #{weapon.series} (weapon: #{weapon.name_en})" - skipped += 1 - end - end - - puts " Migrated #{migrated} weapons, skipped #{skipped}" - - puts "\nMigrating weapon_key series to weapon_key_series join table..." - key_count = 0 - - WeaponKey.find_each do |weapon_key| - next if weapon_key.series.blank? - - weapon_key.series.each do |legacy_series_id| - weapon_series_id = legacy_to_uuid[legacy_series_id.to_i] - next unless weapon_series_id - - # Create join record if it doesn't exist - WeaponKeySeries.find_or_create_by!( - weapon_key_id: weapon_key.id, - weapon_series_id: weapon_series_id - ) - key_count += 1 - end - end - - puts " Created #{key_count} weapon_key_series associations" - puts "\nWeapon series migration complete!" - end - - def down - # Remove all weapon_key_series records - WeaponKeySeries.delete_all - - # Clear weapon_series_id from all weapons - Weapon.update_all(weapon_series_id: nil) - - # Delete all weapon_series records - WeaponSeries.delete_all - end -end diff --git a/db/data/20251203183632_migrate_weapon_key_series.rb b/db/data/20251203183632_migrate_weapon_key_series.rb new file mode 100644 index 0000000..0a7997f --- /dev/null +++ b/db/data/20251203183632_migrate_weapon_key_series.rb @@ -0,0 +1,83 @@ +# frozen_string_literal: true + +class MigrateWeaponKeySeries < ActiveRecord::Migration[8.0] + # Mapping from legacy series integer (WeaponKey.series array values) to WeaponSeries slug + LEGACY_TO_SLUG = { + 1 => 'seraphic', + 2 => 'grand', + 3 => 'dark-opus', + 4 => 'revenant', + 5 => 'primal', + 6 => 'beast', + 7 => 'regalia', + 8 => 'omega', + 9 => 'olden-primal', + 10 => 'hollowsky', + 11 => 'xeno', + 12 => 'rose', + 13 => 'ultima', + 14 => 'bahamut', + 15 => 'epic', + 16 => 'cosmos', + 17 => 'superlative', + 18 => 'vintage', + 19 => 'class-champion', + 20 => 'replica', + 21 => 'relic', + 22 => 'rusted', + 23 => 'sephira', + 24 => 'vyrmament', + 26 => 'astral', + 27 => 'draconic', + 28 => 'eternal-splendor', + 29 => 'ancestral', + 30 => 'new-world-foundation', + 31 => 'ennead', + 32 => 'militis', + 33 => 'malice', + 34 => 'menace', + 35 => 'illustrious', + 36 => 'proven', + 37 => 'revans', + 38 => 'world', + 39 => 'exo', + 40 => 'draconic-providence', + 41 => 'celestial', + 42 => 'omega-rebirth', + 43 => 'collab', + 98 => 'event', + 99 => 'gacha' + }.freeze + + def up + # Build lookup from slug to UUID + slug_to_uuid = WeaponSeries.pluck(:slug, :id).to_h + + puts "Migrating weapon_key series to weapon_key_series join table..." + key_count = 0 + + WeaponKey.find_each do |weapon_key| + next if weapon_key.series.blank? + + weapon_key.series.each do |legacy_series_id| + slug = LEGACY_TO_SLUG[legacy_series_id.to_i] + next unless slug + + weapon_series_id = slug_to_uuid[slug] + next unless weapon_series_id + + WeaponKeySeries.find_or_create_by!( + weapon_key_id: weapon_key.id, + weapon_series_id: weapon_series_id + ) + key_count += 1 + end + end + + puts " Created #{key_count} weapon_key_series associations" + end + + def down + WeaponKeySeries.delete_all + end +end diff --git a/db/data/20251203183633_migrate_weapons_to_weapon_series.rb b/db/data/20251203183633_migrate_weapons_to_weapon_series.rb new file mode 100644 index 0000000..bdd5817 --- /dev/null +++ b/db/data/20251203183633_migrate_weapons_to_weapon_series.rb @@ -0,0 +1,85 @@ +# frozen_string_literal: true + +class MigrateWeaponsToWeaponSeries < ActiveRecord::Migration[8.0] + # Mapping from legacy series integer (Weapon.series column) to WeaponSeries slug + LEGACY_TO_SLUG = { + 0 => 'seraphic', + 1 => 'grand', + 2 => 'dark-opus', + 4 => 'revenant', + 6 => 'primal', + 5 => 'beast', + 7 => 'beast', + 9 => 'omega', + 8 => 'regalia', + 10 => 'primal', + 12 => 'hollowsky', + 13 => 'xeno', + 15 => 'rose', + 17 => 'ultima', + 16 => 'bahamut', + 18 => 'epic', + 20 => 'cosmos', + 22 => 'superlative', + 23 => 'vintage', + 24 => 'class-champion', + 28 => 'sephira', + 14 => 'astral', + 3 => 'draconic', + 21 => 'ancestral', + 29 => 'new-world-foundation', + 19 => 'ennead', + 11 => 'militis', + 26 => 'malice', + 27 => 'menace', + 31 => 'illustrious', + 25 => 'proven', + 30 => 'revans', + 32 => 'world', + 33 => 'exo', + 34 => 'draconic-providence', + 37 => 'celestial', + 41 => 'celestial', + 38 => 'omega-rebirth', + 43 => 'collab', + 35 => 'event', + -1 => 'gacha', + 36 => 'gacha' + }.freeze + + def up + # Build lookup from slug to UUID + slug_to_uuid = WeaponSeries.pluck(:slug, :id).to_h + + puts 'Migrating weapons to use weapon_series_id...' + migrated = 0 + skipped = 0 + + Weapon.find_each do |weapon| + next if weapon.series.blank? + + slug = LEGACY_TO_SLUG[weapon.series.to_i] + unless slug + puts " Warning: No slug mapping for legacy series #{weapon.series} (weapon: #{weapon.name_en})" + skipped += 1 + next + end + + weapon_series_id = slug_to_uuid[slug] + unless weapon_series_id + puts " Warning: No weapon_series found for slug '#{slug}' (weapon: #{weapon.name_en})" + skipped += 1 + next + end + + weapon.update_column(:weapon_series_id, weapon_series_id) + migrated += 1 + end + + puts " Migrated #{migrated} weapons, skipped #{skipped}" + end + + def down + Weapon.update_all(weapon_series_id: nil) + end +end