From 761bb8daeac35cbfca95461f534af2a67d2fa186 Mon Sep 17 00:00:00 2001 From: Malaber Date: Thu, 16 Apr 2026 13:02:40 +0200 Subject: [PATCH] Simplify default beamer handling --- app/controllers/beamers_controller.rb | 4 +- app/models/beamer.rb | 3 +- app/models/tournament.rb | 7 ++++ app/serializers/beamer_serializer.rb | 2 +- ...102000_backfill_default_beamers_by_name.rb | 40 +++++++++++++++++++ spec/controllers/beamers_controller_spec.rb | 10 ++--- .../tournaments_controller_spec.rb | 8 ++++ spec/factories/beamers.rb | 2 - spec/models/beamer_spec.rb | 13 ------ spec/models/tournament_spec.rb | 8 ++++ 10 files changed, 72 insertions(+), 25 deletions(-) create mode 100644 db/migrate/20260416102000_backfill_default_beamers_by_name.rb diff --git a/app/controllers/beamers_controller.rb b/app/controllers/beamers_controller.rb index 9e36187..7dba9a3 100644 --- a/app/controllers/beamers_controller.rb +++ b/app/controllers/beamers_controller.rb @@ -20,7 +20,7 @@ class BeamersController < ApplicationController # GET /tournaments/:tournament_id/beamers/by_name?name=beamername def by_name beamer = @tournament.beamers.find_by(name: params[:name]) - beamer ||= @tournament.beamers.default_beamer.first + beamer ||= @tournament.beamers.find_by(name: Beamer::DEFAULT_NAME) if beamer render json: beamer else @@ -64,6 +64,6 @@ class BeamersController < ApplicationController end def beamer_params - params.permit(:name, :display_state, :is_default, :qr_code_url, :logo_url) + params.permit(:name, :display_state, :qr_code_url, :logo_url) end end diff --git a/app/models/beamer.rb b/app/models/beamer.rb index e168f1c..180f915 100644 --- a/app/models/beamer.rb +++ b/app/models/beamer.rb @@ -1,6 +1,7 @@ # frozen_string_literal: true class Beamer < ApplicationRecord + DEFAULT_NAME = 'default' DISPLAY_STATES = %w[ matches_all matches_in_progress matches_upcoming matches_not_started matches_finished groups between_games during_game @@ -11,7 +12,5 @@ class Beamer < ApplicationRecord validates :name, presence: true, uniqueness: { scope: :tournament_id } validates :display_state, presence: true, inclusion: { in: DISPLAY_STATES } - scope :default_beamer, -> { where(is_default: true) } - delegate :owner, to: :tournament end diff --git a/app/models/tournament.rb b/app/models/tournament.rb index 4a00ce0..af67d0c 100644 --- a/app/models/tournament.rb +++ b/app/models/tournament.rb @@ -16,6 +16,7 @@ class Tournament < ApplicationRecord alias_attribute :owner, :user after_initialize :generate_code + after_create_commit :ensure_default_beamer! def matches [stages.map(&:matches), stages.map { |s| s.groups.map(&:matches) }].flatten @@ -50,4 +51,10 @@ class Tournament < ApplicationRecord errors.add(:playoff_teams_amount, 'playoff_teams_amount needs to be a positive power of two') end + + def ensure_default_beamer! + beamers.find_or_create_by!(name: Beamer::DEFAULT_NAME) do |beamer| + beamer.display_state = 'matches_all' + end + end end diff --git a/app/serializers/beamer_serializer.rb b/app/serializers/beamer_serializer.rb index 62d9fc6..ca15284 100644 --- a/app/serializers/beamer_serializer.rb +++ b/app/serializers/beamer_serializer.rb @@ -1,5 +1,5 @@ # frozen_string_literal: true class BeamerSerializer < ApplicationSerializer - attributes :name, :display_state, :is_default, :qr_code_url, :logo_url + attributes :name, :display_state, :qr_code_url, :logo_url end diff --git a/db/migrate/20260416102000_backfill_default_beamers_by_name.rb b/db/migrate/20260416102000_backfill_default_beamers_by_name.rb new file mode 100644 index 0000000..fc885c3 --- /dev/null +++ b/db/migrate/20260416102000_backfill_default_beamers_by_name.rb @@ -0,0 +1,40 @@ +# frozen_string_literal: true + +class BackfillDefaultBeamersByName < ActiveRecord::Migration[7.0] + DEFAULT_BEAMER_NAME = 'default' + + class MigrationTournament < ApplicationRecord + self.table_name = 'tournaments' + end + + class MigrationBeamer < ApplicationRecord + self.table_name = 'beamers' + end + + def up + MigrationTournament.find_each do |tournament| + beamers = MigrationBeamer.where(tournament_id: tournament.id) + next if beamers.exists?(name: DEFAULT_BEAMER_NAME) + + legacy_default = beamers.find_by(is_default: true) + + if legacy_default + legacy_default.update_columns(name: DEFAULT_BEAMER_NAME) + else + MigrationBeamer.create!( + tournament_id: tournament.id, + name: DEFAULT_BEAMER_NAME, + display_state: 'matches_all' + ) + end + end + end + + def down + MigrationBeamer.where(name: DEFAULT_BEAMER_NAME).where.not(tournament_id: nil).find_each do |beamer| + next unless MigrationBeamer.where(tournament_id: beamer.tournament_id).count == 1 + + beamer.delete + end + end +end diff --git a/spec/controllers/beamers_controller_spec.rb b/spec/controllers/beamers_controller_spec.rb index 470f59c..1cdbe92 100644 --- a/spec/controllers/beamers_controller_spec.rb +++ b/spec/controllers/beamers_controller_spec.rb @@ -6,8 +6,8 @@ RSpec.describe BeamersController, type: :controller do before do @tournament = create(:tournament) @owner = @tournament.owner + @default_beamer = @tournament.beamers.find_by!(name: Beamer::DEFAULT_NAME) @beamer = create(:beamer, tournament: @tournament) - @default_beamer = create(:default_beamer, tournament: @tournament) end describe 'GET #index' do @@ -47,18 +47,18 @@ RSpec.describe BeamersController, type: :controller do expect(response).to be_successful body = deserialize_response response expect(body[:name]).to eq(@default_beamer.name) - expect(body[:is_default]).to be true end it 'falls back to default beamer when name param is missing' do get :by_name, params: { tournament_id: @tournament.to_param } expect(response).to be_successful body = deserialize_response response - expect(body[:is_default]).to be true + expect(body[:name]).to eq(Beamer::DEFAULT_NAME) end - it 'returns 404 when no beamers exist at all' do + it 'returns 404 when all beamers were deleted' do empty_tournament = create(:tournament) + empty_tournament.beamers.destroy_all get :by_name, params: { tournament_id: empty_tournament.to_param, name: 'anything' } expect(response).to have_http_status(:not_found) end @@ -66,7 +66,7 @@ RSpec.describe BeamersController, type: :controller do describe 'POST #create' do let(:valid_params) do - { name: 'new-beamer', display_state: 'groups', is_default: false } + { name: 'new-beamer', display_state: 'groups' } end context 'as owner' do diff --git a/spec/controllers/tournaments_controller_spec.rb b/spec/controllers/tournaments_controller_spec.rb index 08772f8..7e51682 100644 --- a/spec/controllers/tournaments_controller_spec.rb +++ b/spec/controllers/tournaments_controller_spec.rb @@ -259,6 +259,14 @@ RSpec.describe TournamentsController, type: :controller do expect(included_teams).to match_array(@teams) end + it 'creates a default beamer automatically' do + post :create, params: create_playoff_tournament_data + body = deserialize_response response + tournament = Tournament.find(body[:id]) + + expect(tournament.beamers.pluck(:name)).to include(Beamer::DEFAULT_NAME) + end + context 'with parameter group_stage=true' do before do post :create, params: create_group_tournament_data diff --git a/spec/factories/beamers.rb b/spec/factories/beamers.rb index e4dfa4e..8b7e315 100644 --- a/spec/factories/beamers.rb +++ b/spec/factories/beamers.rb @@ -4,12 +4,10 @@ FactoryBot.define do factory :beamer do sequence(:name) { |n| "beamer-#{n}" } display_state { 'matches_all' } - is_default { false } tournament factory :default_beamer do name { 'default' } - is_default { true } end end end diff --git a/spec/models/beamer_spec.rb b/spec/models/beamer_spec.rb index a842190..34d77d1 100644 --- a/spec/models/beamer_spec.rb +++ b/spec/models/beamer_spec.rb @@ -36,19 +36,6 @@ RSpec.describe Beamer, type: :model do it { should belong_to :tournament } end - describe 'scopes' do - describe '.default_beamer' do - it 'returns only default beamers' do - tournament = create(:tournament) - default = create(:default_beamer, tournament: tournament) - create(:beamer, tournament: tournament) - - result = tournament.beamers.default_beamer - expect(result).to contain_exactly(default) - end - end - end - describe '#owner' do it 'delegates to tournament' do beamer = create(:beamer) diff --git a/spec/models/tournament_spec.rb b/spec/models/tournament_spec.rb index fde092b..62fc7a4 100644 --- a/spec/models/tournament_spec.rb +++ b/spec/models/tournament_spec.rb @@ -32,6 +32,14 @@ RSpec.describe Tournament, type: :model do it { should have_many :beamers } end + describe 'default beamer' do + it 'creates a default beamer automatically' do + tournament = create(:tournament) + + expect(tournament.beamers.pluck(:name)).to include(Beamer::DEFAULT_NAME) + end + end + describe '#matches' do context 'group stage tournament' do before do