Add contestant categories to contests
This commit is contained in:
parent
ee476ab81b
commit
502649620b
37
app/controllers/categories_controller.rb
Normal file
37
app/controllers/categories_controller.rb
Normal file
@ -0,0 +1,37 @@
|
||||
class CategoriesController < ApplicationController
|
||||
before_action :set_contest
|
||||
before_action :set_category, only: %i[ destroy]
|
||||
|
||||
def create
|
||||
authorize @contest
|
||||
|
||||
@category = Category.new(category_params)
|
||||
@category.contest_id = @contest.id
|
||||
if @category.save
|
||||
redirect_to edit_contest_path(@contest), notice: t("categories.new.notice")
|
||||
else
|
||||
redirect_to edit_contest_path(@contest), notice: t("categories.new.error")
|
||||
end
|
||||
end
|
||||
|
||||
def destroy
|
||||
authorize @contest
|
||||
|
||||
@category.destroy
|
||||
redirect_to edit_contest_path(@contest), notice: t("categories.destroy.notice")
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def set_contest
|
||||
@contest = Contest.find(params[:contest_id])
|
||||
end
|
||||
|
||||
def set_category
|
||||
@category = Category.find(params[:id])
|
||||
end
|
||||
|
||||
def category_params
|
||||
params.expect(category: [ :name ])
|
||||
end
|
||||
end
|
24
app/models/category.rb
Normal file
24
app/models/category.rb
Normal file
@ -0,0 +1,24 @@
|
||||
# == Schema Information
|
||||
#
|
||||
# Table name: categories
|
||||
#
|
||||
# id :integer not null, primary key
|
||||
# name :string
|
||||
# created_at :datetime not null
|
||||
# updated_at :datetime not null
|
||||
# contest_id :integer not null
|
||||
#
|
||||
# Indexes
|
||||
#
|
||||
# index_categories_on_contest_id (contest_id)
|
||||
#
|
||||
# Foreign Keys
|
||||
#
|
||||
# contest_id (contest_id => contests.id)
|
||||
#
|
||||
class Category < ApplicationRecord
|
||||
belongs_to :contest
|
||||
has_and_belongs_to_many :contestants
|
||||
|
||||
validates :name, presence: true
|
||||
end
|
@ -26,6 +26,7 @@ class Contest < ApplicationRecord
|
||||
extend FriendlyId
|
||||
|
||||
belongs_to :user
|
||||
has_many :categories
|
||||
has_many :completions, dependent: :destroy
|
||||
has_many :contestants, dependent: :destroy
|
||||
has_many :puzzles, dependent: :destroy
|
||||
|
@ -22,6 +22,7 @@
|
||||
class Contestant < ApplicationRecord
|
||||
belongs_to :contest
|
||||
has_many :completions, dependent: :destroy
|
||||
has_and_belongs_to_many :categories
|
||||
|
||||
before_validation :initialize_time_seconds_if_empty
|
||||
|
||||
|
@ -1,3 +1,4 @@
|
||||
h4.mt-5 = t("contests.form.general")
|
||||
= form_with model: contest do |form|
|
||||
.row.mb-3
|
||||
.col
|
||||
@ -20,7 +21,7 @@
|
||||
= form.check_box :team, class: "form-check-input"
|
||||
= form.label :team
|
||||
.form-text = t("activerecord.attributes.contest.team_description")
|
||||
.row.mb-3
|
||||
.row.mb-3 style="display: none"
|
||||
.col
|
||||
.form-check.form-switch
|
||||
= form.check_box :allow_registration, class: "form-check-input"
|
||||
@ -28,4 +29,37 @@
|
||||
.form-text = t("activerecord.attributes.contest.allow_registration_description")
|
||||
.row
|
||||
.col
|
||||
= form.submit submit_text, class: "btn btn-primary"
|
||||
= form.submit submit_text, class: "btn btn-primary"
|
||||
|
||||
|
||||
h4.mt-5 = t("contests.form.categories")
|
||||
|
||||
= form_with model: Category, url: "/contests/#{@contest.id}/categories" do |form|
|
||||
- if @contest.categories.size > 0
|
||||
.row
|
||||
.col-6
|
||||
table.table.table-striped.table-hover
|
||||
thead
|
||||
tr
|
||||
th
|
||||
= t("activerecord.attributes.category.name")
|
||||
th
|
||||
= t("activerecord.attributes.category.contestant_count")
|
||||
tbody
|
||||
- @contest.categories.each do |category|
|
||||
tr.align-middle scope="row"
|
||||
td
|
||||
= category.name
|
||||
td
|
||||
= category.contestants.size
|
||||
td
|
||||
= link_to t("helpers.buttons.delete"), contest_category_path(@contest, category), data: { turbo_method: :delete }, class: "btn btn-sm btn-danger ms-2"
|
||||
.row.mt-3
|
||||
.col-4
|
||||
.form-floating
|
||||
= form.text_field :name, autocomplete: "off", value: nil, class: "form-control"
|
||||
= form.label :name, class: "required"
|
||||
= t("activerecord.attributes.category.new")
|
||||
.row.mt-3
|
||||
.col
|
||||
= form.submit t("helpers.buttons.add"), class: "btn btn-primary"
|
@ -38,6 +38,10 @@ en:
|
||||
greater_than: "Participant names are required"
|
||||
activerecord:
|
||||
attributes:
|
||||
category:
|
||||
contestant_count: Contestants count
|
||||
new: New category
|
||||
name: Category
|
||||
completion:
|
||||
contestant: Participant
|
||||
display_time: Time
|
||||
@ -116,6 +120,12 @@ en:
|
||||
blank: Your email cannot be empty
|
||||
username:
|
||||
blank: Your username cannot be empty
|
||||
categories:
|
||||
destroy:
|
||||
notice: Category deleted
|
||||
new:
|
||||
error: The category name can't be empty
|
||||
notice: Category added
|
||||
completions:
|
||||
destroy:
|
||||
notice: Completion deleted
|
||||
@ -132,6 +142,9 @@ en:
|
||||
edit:
|
||||
notice: Contest updated
|
||||
title: Edit contest settings
|
||||
form:
|
||||
categories: Participant categories
|
||||
general: General parameters
|
||||
index:
|
||||
title: Welcome %{username}!
|
||||
manage_contests: Manage my contests
|
||||
|
@ -9,6 +9,10 @@ fr:
|
||||
greater_than: "Choisir une colonne pour les noms des participant.e.s est nécessaire"
|
||||
activerecord:
|
||||
attributes:
|
||||
category:
|
||||
contestant_count: Nombre de participant.e.s
|
||||
new: Nouvelle catégorie
|
||||
name: Catégorie
|
||||
completion:
|
||||
contestant_id: Participant.e
|
||||
display_time: Temps
|
||||
@ -87,6 +91,12 @@ fr:
|
||||
blank: L'email est obligatoire
|
||||
username:
|
||||
blank: Le nom d'utilisateur.ice est obligatoire
|
||||
categories:
|
||||
destroy:
|
||||
notice: Catégorie supprimée
|
||||
new:
|
||||
error: Le nom de la catégorie ne peut pas être vide
|
||||
notice: Catégorie ajoutée
|
||||
completions:
|
||||
destroy:
|
||||
notice: Complétion supprimée
|
||||
@ -103,6 +113,9 @@ fr:
|
||||
edit:
|
||||
notice: Concours modifié
|
||||
title: Paramètres du concours
|
||||
form:
|
||||
categories: Catégories de participant.e.s
|
||||
general: Paramètres généraux
|
||||
index:
|
||||
title: Bienvenue %{username} !
|
||||
manage_contests: Mes concours de puzzle
|
||||
|
@ -9,6 +9,7 @@ Rails.application.routes.draw do
|
||||
root "contests#index"
|
||||
|
||||
resources :contests do
|
||||
resources :categories, only: [ :create, :destroy ]
|
||||
resources :completions
|
||||
resources :contestants
|
||||
resources :puzzles
|
||||
|
15
db/migrate/20250714115208_create_categories.rb
Normal file
15
db/migrate/20250714115208_create_categories.rb
Normal file
@ -0,0 +1,15 @@
|
||||
class CreateCategories < ActiveRecord::Migration[8.0]
|
||||
def change
|
||||
create_table :categories do |t|
|
||||
t.string :name
|
||||
t.belongs_to :contest, null: false, foreign_key: true
|
||||
|
||||
t.timestamps
|
||||
end
|
||||
|
||||
create_join_table :categories, :contestants do |t|
|
||||
t.index :category_id
|
||||
t.index :contestant_id
|
||||
end
|
||||
end
|
||||
end
|
18
db/schema.rb
generated
18
db/schema.rb
generated
@ -10,7 +10,7 @@
|
||||
#
|
||||
# It's strongly recommended that you check this file into your version control system.
|
||||
|
||||
ActiveRecord::Schema[8.0].define(version: 2025_06_27_070407) do
|
||||
ActiveRecord::Schema[8.0].define(version: 2025_07_14_115208) do
|
||||
create_table "active_storage_attachments", force: :cascade do |t|
|
||||
t.string "name", null: false
|
||||
t.string "record_type", null: false
|
||||
@ -39,6 +39,21 @@ ActiveRecord::Schema[8.0].define(version: 2025_06_27_070407) do
|
||||
t.index ["blob_id", "variation_digest"], name: "index_active_storage_variant_records_uniqueness", unique: true
|
||||
end
|
||||
|
||||
create_table "categories", force: :cascade do |t|
|
||||
t.string "name"
|
||||
t.integer "contest_id", null: false
|
||||
t.datetime "created_at", null: false
|
||||
t.datetime "updated_at", null: false
|
||||
t.index ["contest_id"], name: "index_categories_on_contest_id"
|
||||
end
|
||||
|
||||
create_table "categories_contestants", id: false, force: :cascade do |t|
|
||||
t.integer "category_id", null: false
|
||||
t.integer "contestant_id", null: false
|
||||
t.index ["category_id"], name: "index_categories_contestants_on_category_id"
|
||||
t.index ["contestant_id"], name: "index_categories_contestants_on_contestant_id"
|
||||
end
|
||||
|
||||
create_table "completions", force: :cascade do |t|
|
||||
t.integer "time_seconds"
|
||||
t.integer "contestant_id", null: false
|
||||
@ -141,6 +156,7 @@ ActiveRecord::Schema[8.0].define(version: 2025_06_27_070407) do
|
||||
|
||||
add_foreign_key "active_storage_attachments", "active_storage_blobs", column: "blob_id"
|
||||
add_foreign_key "active_storage_variant_records", "active_storage_blobs", column: "blob_id"
|
||||
add_foreign_key "categories", "contests"
|
||||
add_foreign_key "completions", "contestants"
|
||||
add_foreign_key "completions", "contests"
|
||||
add_foreign_key "completions", "messages"
|
||||
|
23
spec/factories/categories.rb
Normal file
23
spec/factories/categories.rb
Normal file
@ -0,0 +1,23 @@
|
||||
# == Schema Information
|
||||
#
|
||||
# Table name: categories
|
||||
#
|
||||
# id :integer not null, primary key
|
||||
# name :string
|
||||
# created_at :datetime not null
|
||||
# updated_at :datetime not null
|
||||
# contest_id :integer not null
|
||||
#
|
||||
# Indexes
|
||||
#
|
||||
# index_categories_on_contest_id (contest_id)
|
||||
#
|
||||
# Foreign Keys
|
||||
#
|
||||
# contest_id (contest_id => contests.id)
|
||||
#
|
||||
FactoryBot.define do
|
||||
factory :category do
|
||||
name { "MyString" }
|
||||
end
|
||||
end
|
23
spec/models/category_spec.rb
Normal file
23
spec/models/category_spec.rb
Normal file
@ -0,0 +1,23 @@
|
||||
# == Schema Information
|
||||
#
|
||||
# Table name: categories
|
||||
#
|
||||
# id :integer not null, primary key
|
||||
# name :string
|
||||
# created_at :datetime not null
|
||||
# updated_at :datetime not null
|
||||
# contest_id :integer not null
|
||||
#
|
||||
# Indexes
|
||||
#
|
||||
# index_categories_on_contest_id (contest_id)
|
||||
#
|
||||
# Foreign Keys
|
||||
#
|
||||
# contest_id (contest_id => contests.id)
|
||||
#
|
||||
require 'rails_helper'
|
||||
|
||||
RSpec.describe Category, type: :model do
|
||||
pending "add some examples to (or delete) #{__FILE__}"
|
||||
end
|
Loading…
x
Reference in New Issue
Block a user