add summon series lookup table

This commit is contained in:
Justin Edmund 2025-12-14 11:58:22 -08:00
parent e7e9bd0f86
commit 3b5b8412d3
6 changed files with 182 additions and 0 deletions

View file

@ -0,0 +1,22 @@
# frozen_string_literal: true
module Api
module V1
class SummonSeriesBlueprint < ApiBlueprint
field :name do |ss|
{
en: ss.name_en,
ja: ss.name_jp
}
end
fields :slug, :order
view :full do
field :summon_count do |ss|
ss.summons.count
end
end
end
end
end

View file

@ -0,0 +1,72 @@
# frozen_string_literal: true
module Api
module V1
class SummonSeriesController < Api::V1::ApiController
before_action :set_summon_series, only: %i[show update destroy]
before_action :ensure_editor_role, only: %i[create update destroy]
# GET /summon_series
def index
summon_series = SummonSeries.ordered
render json: SummonSeriesBlueprint.render(summon_series)
end
# GET /summon_series/:id
def show
render json: SummonSeriesBlueprint.render(@summon_series, view: :full)
end
# POST /summon_series
def create
summon_series = SummonSeries.new(summon_series_params)
if summon_series.save
render json: SummonSeriesBlueprint.render(summon_series, view: :full), status: :created
else
render_validation_error_response(summon_series)
end
end
# PATCH/PUT /summon_series/:id
def update
if @summon_series.update(summon_series_params)
render json: SummonSeriesBlueprint.render(@summon_series, view: :full)
else
render_validation_error_response(@summon_series)
end
end
# DELETE /summon_series/:id
def destroy
if @summon_series.summons.exists?
render json: ErrorBlueprint.render(nil, error: {
message: 'Cannot delete series with associated summons',
code: 'has_dependencies'
}), status: :unprocessable_entity
else
@summon_series.destroy!
head :no_content
end
end
private
def set_summon_series
# Support lookup by slug or UUID
@summon_series = SummonSeries.find_by(slug: params[:id]) || SummonSeries.find(params[:id])
end
def ensure_editor_role
return if current_user&.role && current_user.role >= 7
Rails.logger.warn "[SUMMON_SERIES] Unauthorized access attempt by user #{current_user&.id}"
render json: { error: 'Unauthorized - Editor role required' }, status: :unauthorized
end
def summon_series_params
params.require(:summon_series).permit(:name_en, :name_jp, :slug, :order)
end
end
end
end

View file

@ -0,0 +1,23 @@
# frozen_string_literal: true
class SummonSeries < ApplicationRecord
has_many :summons, dependent: :restrict_with_error
validates :name_en, presence: true
validates :name_jp, presence: true
validates :slug, presence: true, uniqueness: true
validates :order, numericality: { only_integer: true }
scope :ordered, -> { order(:order) }
# Slug constants for commonly referenced series
PROVIDENCE = 'providence'
GENESIS = 'genesis'
MAGNA = 'magna'
OPTIMUS = 'optimus'
ARCARUM = 'arcarum'
def blueprint
SummonSeriesBlueprint
end
end

View file

@ -0,0 +1,41 @@
# frozen_string_literal: true
class CreateSummonSeriesRecords < ActiveRecord::Migration[8.0]
def up
summon_series_data = [
{ order: 0, slug: 'providence', name_en: 'Providence Series', name_jp: 'プロヴィデンスシリーズ' },
{ order: 1, slug: 'genesis', name_en: 'Genesis Series', name_jp: 'ジェネシスシリーズ' },
{ order: 2, slug: 'magna', name_en: 'Magna Series', name_jp: 'マグナシリーズ' },
{ order: 3, slug: 'optimus', name_en: 'Optimus Series', name_jp: 'オプティマスシリーズ' },
{ order: 4, slug: 'demi-optimus', name_en: 'Demi Optimus Series', name_jp: 'オプティマス・ディヴィジョン' },
{ order: 5, slug: 'archangel', name_en: 'Archangel Series', name_jp: '天司シリーズ' },
{ order: 6, slug: 'arcarum', name_en: 'Arcarum Series', name_jp: 'アーカルムシリーズ' },
{ order: 7, slug: 'epic', name_en: 'Epic Series', name_jp: 'エピックシリーズ' },
{ order: 8, slug: 'carbuncle', name_en: 'Carbuncle Series', name_jp: 'カーバンクルシリーズ' },
{ order: 9, slug: 'dynamis', name_en: 'Dynamis Series', name_jp: 'デュナミスシリーズ' },
{ order: 10, slug: 'cryptid', name_en: 'Cryptid Series', name_jp: 'UMAシリーズ' },
{ order: 11, slug: 'six-dragons', name_en: 'Six Dragons', name_jp: '六竜シリーズ' },
{ order: 12, slug: 'bellum', name_en: 'Bellum Series', name_jp: 'ベルムシリーズ' },
{ order: 13, slug: 'crest', name_en: 'Crest Series', name_jp: 'クレストシリーズ' },
{ order: 14, slug: 'robur', name_en: 'Robur Series', name_jp: 'ロブルシリーズ' },
{ order: 15, slug: 'summer', name_en: 'Summer', name_jp: '水着' },
{ order: 16, slug: 'yukata', name_en: 'Yukata', name_jp: '浴衣' },
{ order: 17, slug: 'holiday', name_en: 'Holiday', name_jp: 'クリスマス' },
{ order: 18, slug: 'collab', name_en: 'Collab', name_jp: 'コラボ' }
]
puts 'Creating summon series records...'
summon_series_data.each do |data|
ss = SummonSeries.find_or_initialize_by(slug: data[:slug])
ss.assign_attributes(data)
ss.save!
puts " #{ss.slug}: #{ss.name_en}"
end
puts "\nCreated #{SummonSeries.count} summon series records"
end
def down
SummonSeries.delete_all
end
end

View file

@ -0,0 +1,15 @@
# frozen_string_literal: true
class CreateSummonSeries < ActiveRecord::Migration[8.0]
def change
create_table :summon_series, id: :uuid do |t|
t.string :name_en, null: false
t.string :name_jp, null: false
t.string :slug, null: false
t.integer :order, default: 0, null: false
end
add_index :summon_series, :slug, unique: true
add_index :summon_series, :order
end
end

View file

@ -0,0 +1,9 @@
# frozen_string_literal: true
class AddSummonSeriesIdToSummons < ActiveRecord::Migration[8.0]
def change
add_column :summons, :summon_series_id, :uuid
add_index :summons, :summon_series_id
add_foreign_key :summons, :summon_series
end
end