Compare commits

...

4 Commits

Author SHA1 Message Date
Trevor Vallender 3881248603 update todos 2024-05-28 20:41:14 +01:00
Trevor Vallender 26f42fc232 Generate table slug and UUID 2024-05-28 20:40:51 +01:00
Trevor Vallender c6072a4cb7 Add unique table names per-user 2024-05-28 20:22:08 +01:00
Trevor Vallender 3ce9081996 CRUD actions for tables 2024-05-28 20:16:43 +01:00
19 changed files with 255 additions and 12 deletions

View File

@ -6,6 +6,7 @@ body {
font-size: 1.1em;
margin: 0 auto;
max-width: 80em;
padding: 1em;
}
main {

View File

@ -1,6 +1,60 @@
# frozen_string_literal: true
class TablesController < ApplicationController
before_action :set_table, only: [ :show, :edit, :update, :destroy ]
def index
@tables = Current.user.tables
end
def show
end
def new
@table = Table.new
end
def create
@table = Current.user.tables.new(table_params)
if @table.save
redirect_to @table, notice: t(".success", name: @table.name)
else
flash.now[:alert] = t(".error")
render :new, status: :unprocessable_entity
end
end
def edit
end
def update
if @table.update(table_params)
redirect_to @table, notice: t(".success", name: @table.name)
else
flash.now[:alert] = t(".error")
render :edit, status: :unprocessable_entity
end
end
def destroy
if @table.destroy
redirect_to tables_path, notice: t(".success", name: @table.name)
else
flash[:alert] = t(".error", name: @table.name)
redirect_to tables_path
end
end
private
def set_table
@table = Current.user.tables.find(params[:id])
end
def table_params
params.require(:table).permit(
:name,
:game_system_id,
)
end
end

View File

@ -5,8 +5,23 @@ class Table < ApplicationRecord
belongs_to :game_system
validates :name, presence: true,
length: { maximum: 100 }
length: { maximum: 100 },
uniqueness: { scope: :owner_id, message: I18n.t("errors.unique_table_name") }
validates :slug, presence: true,
length: { maximum: 100 },
uniqueness: true
validates :uuid, presence: true
before_validation :generate_uuid, if: :new_record?
before_validation :generate_slug
def generate_uuid
self.uuid = SecureRandom.uuid
end
def generate_slug
return if slug.present?
self.slug = "#{name.parameterize}-#{uuid}"
end
end

View File

@ -2,6 +2,7 @@
class User < ApplicationRecord
has_and_belongs_to_many :site_roles
has_many :tables, foreign_key: :owner_id
has_secure_password
generates_token_for :password_reset, expires_in: 4.hours do

View File

@ -18,6 +18,7 @@
<nav>
<ul>
<% if logged_in? %>
<li><%= link_to t(".tables"), tables_path %></li>
<li><%= link_to t("log_out"), logout_path, data: {turbo_method: :delete} %></li>
<% if Current.user.admin? %>
<li><%= link_to t("administration"), admin_index_path %></li>

View File

@ -0,0 +1,11 @@
<%# locals: (table:, button_text:) -%>
<%= form_with model: @table do |f| %>
<%= f.label :name %>
<%= f.text_field :name %>
<%= f.label :game_system_id %>
<%= f.collection_select :game_system_id, GameSystem.all, :id, :name %>
<%= f.submit button_text %>
<% end %>

View File

@ -0,0 +1,5 @@
<%# locals: (table:) -%>
<div id="<%= dom_id(table) %>" class="table">
<h4><%= link_to table.name, table %></h4>
</div>

View File

@ -0,0 +1,8 @@
<% content_for :title, t(".edit_table", name: @table.name) %>
<h2><%= t(".edit_table", name: @table.name) %></h2>
<%= link_to t(".delete_table", name: @table.name), table_path(@table),
data: { turbo_method: :delete, turbo_confirm: t(".delete_table_confirmation", name: @table.name) } %>
<%= render partial: "tables/form",
locals: { table: @table, button_text: t(".update_table") } %>

View File

@ -1 +1,10 @@
<p>Hello</p>
<% content_for :title, t(".tables") %>
<%= link_to t(".new_table"), new_table_path %>
<h2>Your tables</h2>
<% if @tables.any? %>
<%= render @tables %>
<% else %>
<p>You have no tables.</p>
<% end %>

View File

@ -0,0 +1,6 @@
<% content_for :title, t(".new_table") %>
<h2><%= t(".new_table") %></h2>
<%= render partial: "tables/form",
locals: { table: @table, button_text: t(".create_table") } %>

View File

@ -0,0 +1,12 @@
<% content_for :title, @table.name %>
<h2><%= @table.name %></h2>
<%= link_to t(".edit_table"), edit_table_path(@table) %>
<dl>
<dt><%= t(".game_system") %>:</dt>
<dd><%= @table.game_system.name %></dd>
<dt><%= t(".owner") %>:</dt>
<dd><%= @table.owner.username %></dd>
</dl>

View File

@ -7,10 +7,14 @@ en:
not_authenticated: You need to log in to access this page.
edit: Edit
delete: Delete
errors:
unique_table_name: you already have a table with that name
layouts:
admin:
dashboard: Dashboard
game_systems: Game Systems
application:
tables: Tables
mailer:
greeting: "Hello, %{name}"
sign_off: |
@ -56,6 +60,31 @@ en:
destroy:
log_out: Log out
success: "You have signed out."
tables:
index:
new_table: Create a table
tables: Tables
show:
edit_table: Edit table
game_system: Game system
owner: Owner
new:
new_table: New table
create_table: Create table
create:
success: Your table “%{name}” has been created.
error: Failed to create table
edit:
delete_table: Delete %{name}
delete_table_confirmation: Are you sure you want to delete %{name}?
edit_table: Edit %{name}
update_table: Update table
update:
success: Updated table “%{name}”.
error: Failed to update table.
destroy:
success: Deleted table “%{name}”.
error: Failed to delete table.
users:
validations:
email_format: "must be a valid email address"

View File

@ -12,7 +12,7 @@ Rails.application.routes.draw do
resources :account_verifications, only: [ :show ]
resources :sessions, only: [ :new, :create, :destroy ]
resources :tables, only: [ :index ]
resources :tables
resources :admin, only: [ :index ]
namespace :admin do

View File

@ -0,0 +1,7 @@
# frozen_string_literal: true
class AddUuidToTables < ActiveRecord::Migration[7.1]
def change
add_column :tables, :uuid, :uuid, null: false
end
end

3
db/schema.rb generated
View File

@ -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_05_28_103921) do
ActiveRecord::Schema[7.1].define(version: 2024_05_28_192517) do
# These are extensions that must be enabled in order to support this database
enable_extension "plpgsql"
@ -42,6 +42,7 @@ ActiveRecord::Schema[7.1].define(version: 2024_05_28_103921) do
t.bigint "game_system_id", null: false
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.uuid "uuid", null: false
t.index ["game_system_id"], name: "index_tables_on_game_system_id"
t.index ["owner_id"], name: "index_tables_on_owner_id"
t.index ["slug"], name: "index_tables_on_slug", unique: true

View File

@ -0,0 +1,68 @@
# frozen_string_literal: true
require "test_helper"
class TablesControllerTest < ActionDispatch::IntegrationTest
test "should get index" do
sign_in users(:trevor)
get tables_url
assert_response :success
end
test "should get show" do
sign_in users(:trevor)
get table_url(tables(:table))
assert_response :success
end
test "should get new" do
sign_in users(:trevor)
get new_table_url
assert_response :success
end
test "should create table" do
sign_in users(:trevor)
assert_changes("Table.count", +1) do
post(tables_url, params: { table: table_params })
end
assert_redirected_to table_path(Table.last)
end
test "should alert to invalid table" do
sign_in users(:trevor)
assert_no_changes("Table.count") do
post(tables_url, params: { table: { name: "new_table" } })
end
assert_response :unprocessable_entity
end
test "should get edit" do
sign_in users(:trevor)
get edit_table_url(tables(:table))
assert_response :success
end
test "should update table" do
sign_in users(:trevor)
patch table_url(tables(:table)), params: { table: { name: "new name" } }
assert_redirected_to table_path(tables(:table))
end
test "should destroy table" do
sign_in users(:trevor)
assert_difference("Table.count", -1) do
delete table_url(tables(:table))
end
assert_redirected_to tables_url
end
private
def table_params
{
name: "A new table",
game_system_id: game_systems(:dnd).id,
}
end
end

View File

@ -1,11 +1,14 @@
table:
name: My Table
slug: my-table
DEFAULTS: &DEFAULTS
owner: trevor
uuid: <%= SecureRandom.uuid %>
slug: $LABEL
table:
<<: *DEFAULTS
name: My Table
game_system: troika
table_two:
my_table_two:
<<: *DEFAULTS
name: My Other Table
slug: my-other-table
owner: trevor
game_system: troika

View File

@ -7,8 +7,8 @@ class TableTest < ActiveSupport::TestCase
assert_must_exist(tables(:table), "name")
end
test "slug must exist" do
assert_must_exist(tables(:table), "slug")
test "uuid must exist" do
assert_must_exist(tables(:table), "uuid")
end
test "slug must be unique" do
@ -17,4 +17,12 @@ class TableTest < ActiveSupport::TestCase
table1.slug = table2.slug
assert_not table1.valid?
end
test "creating adds UUID and slug" do
table = Table.create(name: "New table", game_system: GameSystem.first, owner: User.first)
table.reload
assert_not_nil table.uuid
assert_not_nil table.slug
assert table.slug.start_with?("new-table")
end
end

4
todo.md Normal file
View File

@ -0,0 +1,4 @@
- Ensure form errors/flash show correctly
- Add players to tables
- Add characters to users/tables
- Character sheets/prototypes