diff --git a/app/models/character.rb b/app/models/character.rb new file mode 100644 index 0000000..9e0ca3f --- /dev/null +++ b/app/models/character.rb @@ -0,0 +1,10 @@ +# frozen_string_literal: true + +class Character < ApplicationRecord + belongs_to :table, optional: true + belongs_to :game_system + belongs_to :user + + validates :name, presence: true, + length: { maximum: 200 } +end diff --git a/app/models/game_system.rb b/app/models/game_system.rb index aa3a12a..f1d2519 100644 --- a/app/models/game_system.rb +++ b/app/models/game_system.rb @@ -1,6 +1,9 @@ # frozen_string_literal: true class GameSystem < ApplicationRecord + has_many :characters, dependent: :restrict_with_error + has_many :tables, dependent: :restrict_with_error + validates :name, presence: true, uniqueness: true, length: { maximum: 100 } diff --git a/app/models/table.rb b/app/models/table.rb index c06b28e..f109678 100644 --- a/app/models/table.rb +++ b/app/models/table.rb @@ -3,6 +3,7 @@ class Table < ApplicationRecord belongs_to :owner, class_name: "User" belongs_to :game_system + has_many :characters, dependent: :nullify has_many :players, dependent: :destroy has_many :table_invites, dependent: :destroy has_many :users, through: :players diff --git a/app/models/user.rb b/app/models/user.rb index 14d76f7..1413f73 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -5,6 +5,7 @@ class User < ApplicationRecord deletable_attachments :avatar has_and_belongs_to_many :site_roles + has_many :characters, dependent: :destroy has_many :owned_tables, foreign_key: :owner_id, class_name: "Table" has_many :players, dependent: :destroy has_many :tables, through: :players diff --git a/db/migrate/20240605143732_create_characters.rb b/db/migrate/20240605143732_create_characters.rb new file mode 100644 index 0000000..32af570 --- /dev/null +++ b/db/migrate/20240605143732_create_characters.rb @@ -0,0 +1,16 @@ +# frozen_string_literal: true + +class CreateCharacters < ActiveRecord::Migration[7.1] + def change + create_table :characters do |t| + t.string :name, null: false + t.belongs_to :table, null: true, foreign_key: true + t.belongs_to :game_system, null: false, foreign_key: true + t.belongs_to :user, null: false, foreign_key: true + + t.timestamps + end + + add_check_constraint :characters, "length(name) <= 200", name: "chk_character_name_max_length" + end +end diff --git a/db/schema.rb b/db/schema.rb index 91dc70d..217ec72 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -10,7 +10,7 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema[7.1].define(version: 2024_06_05_132327) do +ActiveRecord::Schema[7.1].define(version: 2024_06_05_143732) do # These are extensions that must be enabled in order to support this database enable_extension "plpgsql" @@ -52,6 +52,19 @@ ActiveRecord::Schema[7.1].define(version: 2024_06_05_132327) do t.index ["blob_id", "variation_digest"], name: "index_active_storage_variant_records_uniqueness", unique: true end + create_table "characters", force: :cascade do |t| + t.string "name", null: false + t.bigint "table_id" + t.bigint "game_system_id", null: false + t.bigint "user_id", null: false + t.datetime "created_at", null: false + t.datetime "updated_at", null: false + t.index ["game_system_id"], name: "index_characters_on_game_system_id" + t.index ["table_id"], name: "index_characters_on_table_id" + t.index ["user_id"], name: "index_characters_on_user_id" + t.check_constraint "length(name::text) <= 200", name: "chk_character_name_max_length" + end + create_table "game_systems", force: :cascade do |t| t.string "name", null: false t.datetime "created_at", null: false @@ -232,6 +245,9 @@ ActiveRecord::Schema[7.1].define(version: 2024_06_05_132327) 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 "characters", "game_systems" + add_foreign_key "characters", "tables" + add_foreign_key "characters", "users" add_foreign_key "players", "tables" add_foreign_key "players", "users" add_foreign_key "solid_queue_blocked_executions", "solid_queue_jobs", column: "job_id", on_delete: :cascade diff --git a/test/fixtures/characters.yml b/test/fixtures/characters.yml new file mode 100644 index 0000000..07de6ce --- /dev/null +++ b/test/fixtures/characters.yml @@ -0,0 +1,5 @@ +nardren: + name: Nardren Rockseeker + table: dnd_table + game_system: dnd + user: trevor diff --git a/test/fixtures/game_systems.yml b/test/fixtures/game_systems.yml index ca79d64..159dc96 100644 --- a/test/fixtures/game_systems.yml +++ b/test/fixtures/game_systems.yml @@ -3,3 +3,6 @@ troika: dnd: name: Dungeons & Dragons + +dragonbane: + name: Dragonbane diff --git a/test/fixtures/tables.yml b/test/fixtures/tables.yml index fe72901..44e5cab 100644 --- a/test/fixtures/tables.yml +++ b/test/fixtures/tables.yml @@ -16,3 +16,8 @@ gimlis_table: <<: *DEFAULTS name: Gimli's Table owner: gimli + +dnd_table: + <<: *DEFAULTS + name: The Dungeon Master's Table + game_system: dnd diff --git a/test/integration/admin_game_systems_integration_test.rb b/test/integration/admin_game_systems_integration_test.rb index 763468b..bdb3f87 100644 --- a/test/integration/admin_game_systems_integration_test.rb +++ b/test/integration/admin_game_systems_integration_test.rb @@ -59,7 +59,7 @@ class AdminGameSystemsIntegrationTest < ActionDispatch::IntegrationTest test "destroy should destroy game system" do sign_in users(:admin) assert_difference "GameSystem.count", -1 do - delete admin_game_system_path(game_systems(:dnd)) + delete admin_game_system_path(game_systems(:dragonbane)) end assert_redirected_to admin_game_systems_path end diff --git a/test/models/character_test.rb b/test/models/character_test.rb new file mode 100644 index 0000000..e862004 --- /dev/null +++ b/test/models/character_test.rb @@ -0,0 +1,9 @@ +# frozen_string_literal: true + +require "test_helper" + +class CharacterTest < ActiveSupport::TestCase + test "name must exist" do + assert_must_exist(characters(:nardren), :name) + end +end diff --git a/test/models/game_system_test.rb b/test/models/game_system_test.rb index 59267fa..bc88908 100644 --- a/test/models/game_system_test.rb +++ b/test/models/game_system_test.rb @@ -6,4 +6,28 @@ class GameSystemTest < ActiveSupport::TestCase test "name must exist" do assert_must_exist(game_systems(:troika), :name) end + + test "cannot delete games with characters" do + game = game_systems(:dnd) + game.tables.destroy_all + assert_no_difference("GameSystem.count") do + game_systems(:dnd).destroy + end + game.characters.destroy_all + assert_difference("GameSystem.count", -1) do + game_systems(:dnd).destroy + end + end + + test "cannot delete games with tables" do + game = game_systems(:dnd) + game.characters.destroy_all + assert_no_difference("GameSystem.count") do + game_systems(:dnd).destroy + end + game.tables.destroy_all + assert_difference("GameSystem.count", -1) do + game_systems(:dnd).destroy + end + end end