Add offline model and "new" form/controller
This commit is contained in:
@@ -1,6 +1,6 @@
|
|||||||
class ContestsController < ApplicationController
|
class ContestsController < ApplicationController
|
||||||
before_action :set_contest, only: %i[ destroy edit show update ]
|
before_action :set_contest, only: %i[ destroy edit show update ]
|
||||||
skip_before_action :require_authentication, only: %i[ scoreboard ]
|
skip_before_action :require_authentication, only: %i[ scoreboard offline_new ]
|
||||||
|
|
||||||
def index
|
def index
|
||||||
authorize :contest
|
authorize :contest
|
||||||
@@ -99,6 +99,21 @@ class ContestsController < ApplicationController
|
|||||||
render :scoreboard
|
render :scoreboard
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def offline_new
|
||||||
|
@contest = Contest.find_by(slug: params[:id])
|
||||||
|
unless @contest && @contest.public
|
||||||
|
skip_authorization
|
||||||
|
not_found and return
|
||||||
|
end
|
||||||
|
authorize :contest
|
||||||
|
|
||||||
|
I18n.locale = @contest.lang
|
||||||
|
|
||||||
|
@title = I18n.t("contests.scoreboard.title", name: @contest.name)
|
||||||
|
|
||||||
|
@offline = Offline.new
|
||||||
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
def set_badges
|
def set_badges
|
||||||
|
|||||||
@@ -31,6 +31,7 @@ class Contest < ApplicationRecord
|
|||||||
has_many :contestants, dependent: :destroy
|
has_many :contestants, dependent: :destroy
|
||||||
has_many :puzzles, dependent: :destroy
|
has_many :puzzles, dependent: :destroy
|
||||||
has_many :messages, dependent: :destroy
|
has_many :messages, dependent: :destroy
|
||||||
|
has_many :offlines, dependent: :destroy
|
||||||
|
|
||||||
friendly_id :name, use: :slugged
|
friendly_id :name, use: :slugged
|
||||||
|
|
||||||
|
|||||||
27
app/models/offline.rb
Normal file
27
app/models/offline.rb
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
# == Schema Information
|
||||||
|
#
|
||||||
|
# Table name: offlines
|
||||||
|
#
|
||||||
|
# id :integer not null, primary key
|
||||||
|
# end_time :datetime
|
||||||
|
# start_time :datetime not null
|
||||||
|
# created_at :datetime not null
|
||||||
|
# updated_at :datetime not null
|
||||||
|
# contest_id :integer not null
|
||||||
|
#
|
||||||
|
# Indexes
|
||||||
|
#
|
||||||
|
# index_offlines_on_contest_id (contest_id)
|
||||||
|
#
|
||||||
|
# Foreign Keys
|
||||||
|
#
|
||||||
|
# contest_id (contest_id => contests.id)
|
||||||
|
#
|
||||||
|
class Offline < ApplicationRecord
|
||||||
|
belongs_to :contest
|
||||||
|
|
||||||
|
has_one_attached :start_image
|
||||||
|
has_one_attached :end_image
|
||||||
|
|
||||||
|
validates :start_time, presence: true
|
||||||
|
end
|
||||||
@@ -47,6 +47,22 @@ class ContestPolicy < ApplicationPolicy
|
|||||||
record.user.id == user.id || user.admin?
|
record.user.id == user.id || user.admin?
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def offline_new?
|
||||||
|
true
|
||||||
|
end
|
||||||
|
|
||||||
|
def offline_create?
|
||||||
|
true
|
||||||
|
end
|
||||||
|
|
||||||
|
def offline_edit?
|
||||||
|
true
|
||||||
|
end
|
||||||
|
|
||||||
|
def offline_update?
|
||||||
|
true
|
||||||
|
end
|
||||||
|
|
||||||
def scoreboard?
|
def scoreboard?
|
||||||
true
|
true
|
||||||
end
|
end
|
||||||
|
|||||||
25
app/views/contests/offline_new.html.slim
Normal file
25
app/views/contests/offline_new.html.slim
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
= form_with model: @offline, url: "/public/#{@contest.id}/offline" do |form|
|
||||||
|
.row.mb-3
|
||||||
|
.col
|
||||||
|
.form-text.mb-1
|
||||||
|
= t("puzzles.image_select")
|
||||||
|
= form.file_field :start_image, accept: "image/*", class: "form-control"
|
||||||
|
.form-text.error-message style="display: none;" id="image-error-message"
|
||||||
|
= t("puzzles.form.file_too_big")
|
||||||
|
javascript:
|
||||||
|
function setMaxUploadSize() {
|
||||||
|
const el = document.querySelector('input[type="file"]');
|
||||||
|
el.onchange = function() {
|
||||||
|
if(this.files[0].size > 2 * 1024 * 1024) {
|
||||||
|
document.getElementById('image-error-message').style.display = 'block';
|
||||||
|
this.value = "";
|
||||||
|
} else {
|
||||||
|
document.getElementById('image-error-message').style.display = 'none';
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
setMaxUploadSize();
|
||||||
|
.row.mt-3
|
||||||
|
.col
|
||||||
|
= form.submit t("helpers.buttons.add"), class: "btn btn-primary"
|
||||||
@@ -32,4 +32,8 @@ Rails.application.routes.draw do
|
|||||||
post "message", to: "messages#create"
|
post "message", to: "messages#create"
|
||||||
|
|
||||||
get "public/:id", to: "contests#scoreboard"
|
get "public/:id", to: "contests#scoreboard"
|
||||||
|
get "public/:id/offline", to: "contests#offline_new"
|
||||||
|
post "public/:id/offline", to: "contests#offline_create"
|
||||||
|
get "public/:id/offline/:offline_id", to: "contests#offline_edit"
|
||||||
|
post "public/:id/offline/:offline_id", to: "contests#offline_update"
|
||||||
end
|
end
|
||||||
|
|||||||
10
db/migrate/20251029155116_create_offlines.rb
Normal file
10
db/migrate/20251029155116_create_offlines.rb
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
class CreateOfflines < ActiveRecord::Migration[8.0]
|
||||||
|
def change
|
||||||
|
create_table :offlines do |t|
|
||||||
|
t.timestamps
|
||||||
|
t.belongs_to :contest, null: false, foreign_key: true
|
||||||
|
t.datetime :start_time, null: false
|
||||||
|
t.datetime :end_time
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
12
db/schema.rb
generated
12
db/schema.rb
generated
@@ -10,7 +10,7 @@
|
|||||||
#
|
#
|
||||||
# It's strongly recommended that you check this file into your version control system.
|
# It's strongly recommended that you check this file into your version control system.
|
||||||
|
|
||||||
ActiveRecord::Schema[8.0].define(version: 2025_10_28_131431) do
|
ActiveRecord::Schema[8.0].define(version: 2025_10_29_155116) do
|
||||||
create_table "active_storage_attachments", force: :cascade do |t|
|
create_table "active_storage_attachments", force: :cascade do |t|
|
||||||
t.string "name", null: false
|
t.string "name", null: false
|
||||||
t.string "record_type", null: false
|
t.string "record_type", null: false
|
||||||
@@ -125,6 +125,15 @@ ActiveRecord::Schema[8.0].define(version: 2025_10_28_131431) do
|
|||||||
t.index ["contest_id"], name: "index_messages_on_contest_id"
|
t.index ["contest_id"], name: "index_messages_on_contest_id"
|
||||||
end
|
end
|
||||||
|
|
||||||
|
create_table "offlines", force: :cascade do |t|
|
||||||
|
t.datetime "created_at", null: false
|
||||||
|
t.datetime "updated_at", null: false
|
||||||
|
t.integer "contest_id", null: false
|
||||||
|
t.datetime "start_time", null: false
|
||||||
|
t.datetime "end_time"
|
||||||
|
t.index ["contest_id"], name: "index_offlines_on_contest_id"
|
||||||
|
end
|
||||||
|
|
||||||
create_table "puzzles", force: :cascade do |t|
|
create_table "puzzles", force: :cascade do |t|
|
||||||
t.string "name"
|
t.string "name"
|
||||||
t.datetime "created_at", null: false
|
t.datetime "created_at", null: false
|
||||||
@@ -165,6 +174,7 @@ ActiveRecord::Schema[8.0].define(version: 2025_10_28_131431) do
|
|||||||
add_foreign_key "contestants", "contests"
|
add_foreign_key "contestants", "contests"
|
||||||
add_foreign_key "contests", "users"
|
add_foreign_key "contests", "users"
|
||||||
add_foreign_key "messages", "contests"
|
add_foreign_key "messages", "contests"
|
||||||
|
add_foreign_key "offlines", "contests"
|
||||||
add_foreign_key "puzzles", "contests"
|
add_foreign_key "puzzles", "contests"
|
||||||
add_foreign_key "sessions", "users"
|
add_foreign_key "sessions", "users"
|
||||||
end
|
end
|
||||||
|
|||||||
24
spec/factories/offlines.rb
Normal file
24
spec/factories/offlines.rb
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
# == Schema Information
|
||||||
|
#
|
||||||
|
# Table name: offlines
|
||||||
|
#
|
||||||
|
# id :integer not null, primary key
|
||||||
|
# end_time :datetime
|
||||||
|
# start_time :datetime not null
|
||||||
|
# created_at :datetime not null
|
||||||
|
# updated_at :datetime not null
|
||||||
|
# contest_id :integer not null
|
||||||
|
#
|
||||||
|
# Indexes
|
||||||
|
#
|
||||||
|
# index_offlines_on_contest_id (contest_id)
|
||||||
|
#
|
||||||
|
# Foreign Keys
|
||||||
|
#
|
||||||
|
# contest_id (contest_id => contests.id)
|
||||||
|
#
|
||||||
|
FactoryBot.define do
|
||||||
|
factory :offline do
|
||||||
|
|
||||||
|
end
|
||||||
|
end
|
||||||
24
spec/models/offline_spec.rb
Normal file
24
spec/models/offline_spec.rb
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
# == Schema Information
|
||||||
|
#
|
||||||
|
# Table name: offlines
|
||||||
|
#
|
||||||
|
# id :integer not null, primary key
|
||||||
|
# end_time :datetime
|
||||||
|
# start_time :datetime not null
|
||||||
|
# created_at :datetime not null
|
||||||
|
# updated_at :datetime not null
|
||||||
|
# contest_id :integer not null
|
||||||
|
#
|
||||||
|
# Indexes
|
||||||
|
#
|
||||||
|
# index_offlines_on_contest_id (contest_id)
|
||||||
|
#
|
||||||
|
# Foreign Keys
|
||||||
|
#
|
||||||
|
# contest_id (contest_id => contests.id)
|
||||||
|
#
|
||||||
|
require 'rails_helper'
|
||||||
|
|
||||||
|
RSpec.describe Offline, type: :model do
|
||||||
|
pending "add some examples to (or delete) #{__FILE__}"
|
||||||
|
end
|
||||||
Reference in New Issue
Block a user