diff --git a/app/blueprints/api/v1/character_blueprint.rb b/app/blueprints/api/v1/character_blueprint.rb index b2556f6..6ce8ef4 100644 --- a/app/blueprints/api/v1/character_blueprint.rb +++ b/app/blueprints/api/v1/character_blueprint.rb @@ -12,12 +12,31 @@ module Api fields :granblue_id, :character_id, :rarity, :element, :gender, :special, :season, - :series, :gacha_available + :gacha_available field :season_name do |c| c.season_name end + field :series do |c| + # Use new lookup table if available + if c.character_series_records.any? + c.character_series_records.ordered.map do |cs| + { + id: cs.id, + slug: cs.slug, + name: { + en: cs.name_en, + ja: cs.name_jp + } + } + end + else + # Legacy fallback - return integer array + c.series + end + end + field :series_names do |c| c.series_names end diff --git a/app/models/character.rb b/app/models/character.rb index b1333ad..3d47110 100644 --- a/app/models/character.rb +++ b/app/models/character.rb @@ -3,6 +3,9 @@ class Character < ApplicationRecord include PgSearch::Model + has_many :character_series_memberships, dependent: :destroy + has_many :character_series_records, through: :character_series_memberships, source: :character_series + multisearchable against: %i[name_en name_jp], additional_attributes: lambda { |character| { @@ -89,9 +92,70 @@ class Character < ApplicationRecord end def series_names - return [] if series.blank? + # Use new lookup table if available + if character_series_records.loaded? ? character_series_records.any? : character_series_records.exists? + character_series_records.ordered.pluck(:name_en) + elsif series.present? + # Legacy fallback + series.filter_map { |s| GranblueEnums::CHARACTER_SERIES.key(s)&.to_s } + else + [] + end + end - series.filter_map { |s| GranblueEnums::CHARACTER_SERIES.key(s)&.to_s } + def series_objects + character_series_records.ordered + end + + def series_slugs + character_series_records.pluck(:slug) + end + + # Mapping from legacy integer values to slugs + LEGACY_SERIES_TO_SLUG = { + 1 => 'standard', + 2 => 'grand', + 3 => 'zodiac', + 4 => 'promo', + 5 => 'collab', + 6 => 'eternal', + 7 => 'evoker', + 8 => 'saint', + 9 => 'fantasy', + 10 => 'summer', + 11 => 'yukata', + 12 => 'valentine', + 13 => 'halloween', + 14 => 'formal', + 15 => 'event' + }.freeze + + # Virtual attribute to set character_series by array of IDs, slugs, or legacy integers + # Supports multiple formats for flexibility during migration + def series=(values) + return if values.blank? + + # Ensure it's an array + values = Array(values) + + values.each do |value| + next if value.blank? + + # Try to find the series record + series_record = if value.is_a?(Integer) + # Legacy integer - convert to slug first + slug = LEGACY_SERIES_TO_SLUG[value] + slug ? CharacterSeries.find_by(slug: slug) : nil + else + # String - try UUID first, then slug + CharacterSeries.find_by(id: value) || CharacterSeries.find_by(slug: value) + end + + next unless series_record + + # Create membership if it doesn't exist + character_series_memberships.find_or_initialize_by(character_series: series_record) + end end private