diff --git a/Gemfile b/Gemfile
index 79802f3d..5ea6f9ba 100644
--- a/Gemfile
+++ b/Gemfile
@@ -1,5 +1,4 @@
source "https://rubygems.org"
-ruby "3.3.4"
# Bundle edge Rails instead: gem "rails", github: "rails/rails", branch: "main"
gem "rails", "~> 7.2.1"
diff --git a/Gemfile.lock b/Gemfile.lock
index 79eeeb21..32da4b67 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -176,7 +176,9 @@ GEM
zeitwerk (~> 2.6)
erubi (1.13.0)
execjs (2.9.1)
- ffi (1.17.0)
+ ffi (1.17.0-aarch64-linux-gnu)
+ ffi (1.17.0-arm64-darwin)
+ ffi (1.17.0-x86_64-darwin)
ffi (1.17.0-x86_64-linux-gnu)
flay (2.13.3)
erubi (~> 1.10)
@@ -224,7 +226,6 @@ GEM
marcel (1.0.4)
matrix (0.4.2)
mini_mime (1.1.5)
- mini_portile2 (2.8.7)
minitest (5.25.1)
msgpack (1.7.2)
multi_test (1.1.0)
@@ -400,8 +401,7 @@ GEM
actionpack (>= 6.1)
activesupport (>= 6.1)
sprockets (>= 3.0.0)
- sqlite3 (2.0.4)
- mini_portile2 (~> 2.8.0)
+ sqlite3 (2.0.4-aarch64-linux-gnu)
sqlite3 (2.0.4-arm64-darwin)
sqlite3 (2.0.4-x86_64-darwin)
sqlite3 (2.0.4-x86_64-linux-gnu)
@@ -478,8 +478,5 @@ DEPENDENCIES
tzinfo-data
uglifier
-RUBY VERSION
- ruby 3.3.4p94
-
BUNDLED WITH
2.5.18
diff --git a/app/assets/stylesheets/games.css b/app/assets/stylesheets/games.css
new file mode 100644
index 00000000..b126a87e
--- /dev/null
+++ b/app/assets/stylesheets/games.css
@@ -0,0 +1,98 @@
+/* app/assets/stylesheets/pages.css */
+
+.container {
+ padding: 20px;
+}
+
+.header {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+}
+
+h2 {
+ font-size: 24px;
+}
+
+.btn-login {
+ background-color: #4caf50;
+ color: white;
+ padding: 10px 20px;
+ text-align: center;
+ border: none;
+ border-radius: 5px;
+ cursor: pointer;
+}
+
+.btn-admin {
+ background-color: red;
+}
+
+.dropdown {
+ position: relative;
+ display: inline-block;
+}
+
+.dropbtn {
+ background-color: #4caf50;
+ color: white;
+ padding: 10px 20px;
+ font-size: 16px;
+ border: none;
+ cursor: pointer;
+ border-radius: 5px;
+}
+
+.dropdown-content {
+ display: none;
+ position: absolute;
+ background-color: #f9f9f9;
+ min-width: 160px;
+ box-shadow: 0px 8px 16px 0px rgba(0, 0, 0, 0.2);
+ z-index: 1;
+}
+
+.dropdown-content a {
+ color: black;
+ padding: 12px 16px;
+ text-decoration: none;
+ display: block;
+}
+
+.dropdown-content a:hover {
+ background-color: #f1f1f1;
+}
+
+.dropdown:hover .dropdown-content {
+ display: block;
+}
+
+.dropdown:hover .dropbtn {
+ background-color: #3e8e41;
+}
+
+.game-list {
+ display: grid;
+ grid-template-columns: repeat(3, 1fr);
+ gap: 20px;
+ margin-top: 20px;
+ max-width: 1600px;
+ margin: 0 auto;
+}
+
+.game-item {
+ padding: 15px;
+ border: 1px solid #ddd;
+ text-align: center;
+ border-radius: 8px;
+}
+
+.btn-play {
+ background-color: #4caf50;
+ color: white;
+ padding: 10px 20px;
+ text-align: center;
+ border: none;
+ border-radius: 5px;
+ cursor: pointer;
+}
diff --git a/app/controllers/games_controller.rb b/app/controllers/games_controller.rb
new file mode 100644
index 00000000..63dddf2f
--- /dev/null
+++ b/app/controllers/games_controller.rb
@@ -0,0 +1,75 @@
+class GamesController < ApplicationController
+ before_action :set_game, only: %i[ show edit update destroy ]
+
+ # GET /games or /games.json
+ def index
+ @games = Game.all
+ end
+
+ # GET /games/1 or /games/1.json
+ def show
+ @game = Game.find(params[:id])
+ redirect_to send(@game.game_path)
+ end
+
+ def demo_game
+ end
+
+ # GET /games/new
+ def new
+ @game = Game.new
+ end
+
+ # GET /games/1/edit
+ def edit
+ end
+
+ # POST /games or /games.json
+ def create
+ @game = Game.new(game_params)
+
+ respond_to do |format|
+ if @game.save
+ format.html { redirect_to @game, notice: "Game was successfully created." }
+ format.json { render :show, status: :created, location: @game }
+ else
+ format.html { render :new, status: :unprocessable_entity }
+ format.json { render json: @game.errors, status: :unprocessable_entity }
+ end
+ end
+ end
+
+ # PATCH/PUT /games/1 or /games/1.json
+ def update
+ respond_to do |format|
+ if @game.update(game_params)
+ format.html { redirect_to @game, notice: "Game was successfully updated." }
+ format.json { render :show, status: :ok, location: @game }
+ else
+ format.html { render :edit, status: :unprocessable_entity }
+ format.json { render json: @game.errors, status: :unprocessable_entity }
+ end
+ end
+ end
+
+ # DELETE /games/1 or /games/1.json
+ def destroy
+ @game.destroy!
+
+ respond_to do |format|
+ format.html { redirect_to games_path, status: :see_other, notice: "Game was successfully destroyed." }
+ format.json { head :no_content }
+ end
+ end
+
+ private
+ # Use callbacks to share common setup or constraints between actions.
+ def set_game
+ @game = Game.find(params[:id])
+ end
+
+ # Only allow a list of trusted parameters through.
+ def game_params
+ params.require(:game).permit(:name, :game_path)
+ end
+end
diff --git a/app/helpers/games_helper.rb b/app/helpers/games_helper.rb
new file mode 100644
index 00000000..2ef8c1f4
--- /dev/null
+++ b/app/helpers/games_helper.rb
@@ -0,0 +1,2 @@
+module GamesHelper
+end
diff --git a/app/models/game.rb b/app/models/game.rb
new file mode 100644
index 00000000..a58d4f13
--- /dev/null
+++ b/app/models/game.rb
@@ -0,0 +1,3 @@
+class Game < ApplicationRecord
+ validates :name, presence: true
+end
\ No newline at end of file
diff --git a/app/views/games/_form.html.erb b/app/views/games/_form.html.erb
new file mode 100644
index 00000000..e9f5d203
--- /dev/null
+++ b/app/views/games/_form.html.erb
@@ -0,0 +1,27 @@
+<%= form_with(model: game) do |form| %>
+ <% if game.errors.any? %>
+
+
<%= pluralize(game.errors.count, "error") %> prohibited this game from being saved:
+
+
+ <% game.errors.each do |error| %>
+ - <%= error.full_message %>
+ <% end %>
+
+
+ <% end %>
+
+
+ <%= form.label :name, style: "display: block" %>
+ <%= form.text_field :name %>
+
+
+
+ <%= form.label :game_path, style: "display: block" %>
+ <%= form.text_field :game_path %>
+
+
+
+ <%= form.submit %>
+
+<% end %>
diff --git a/app/views/games/_game.html.erb b/app/views/games/_game.html.erb
new file mode 100644
index 00000000..5bd20154
--- /dev/null
+++ b/app/views/games/_game.html.erb
@@ -0,0 +1,12 @@
+
+
+ Name:
+ <%= game.name %>
+
+
+
+ Game path:
+ <%= game.game_path %>
+
+
+
diff --git a/app/views/games/_game.json.jbuilder b/app/views/games/_game.json.jbuilder
new file mode 100644
index 00000000..d8eea494
--- /dev/null
+++ b/app/views/games/_game.json.jbuilder
@@ -0,0 +1,2 @@
+json.extract! game, :id, :name, :game_path, :created_at, :updated_at
+json.url game_url(game, format: :json)
diff --git a/app/views/games/_games.html.erb b/app/views/games/_games.html.erb
new file mode 100644
index 00000000..83e94078
--- /dev/null
+++ b/app/views/games/_games.html.erb
@@ -0,0 +1,14 @@
+<%= notice %>
+<% content_for :title, "Games" %>
+
+Games
+
+
+ <% @games.each do |game| %>
+
+
<%= game.name %>
+ <%= link_to 'Play', game_path(game), class: 'btn btn-play' %>
+
+ <% end %>
+
+
\ No newline at end of file
diff --git a/app/views/games/demo_game.html.erb b/app/views/games/demo_game.html.erb
new file mode 100644
index 00000000..a73fa041
--- /dev/null
+++ b/app/views/games/demo_game.html.erb
@@ -0,0 +1,5 @@
+<%= notice %>
+
+
+ Demo Game Page
+
diff --git a/app/views/games/edit.html.erb b/app/views/games/edit.html.erb
new file mode 100644
index 00000000..287b0a9f
--- /dev/null
+++ b/app/views/games/edit.html.erb
@@ -0,0 +1,12 @@
+<% content_for :title, "Editing game" %>
+
+Editing game
+
+<%= render "form", game: @game %>
+
+
+
+
+ <%= link_to "Show this game", @game %> |
+ <%= link_to "Back to games", games_path %>
+
diff --git a/app/views/games/index.html.erb b/app/views/games/index.html.erb
new file mode 100644
index 00000000..98a709b9
--- /dev/null
+++ b/app/views/games/index.html.erb
@@ -0,0 +1,32 @@
+
+
+
+
+
+
+<%= render "games" %>
\ No newline at end of file
diff --git a/app/views/games/index.json.jbuilder b/app/views/games/index.json.jbuilder
new file mode 100644
index 00000000..e6305a05
--- /dev/null
+++ b/app/views/games/index.json.jbuilder
@@ -0,0 +1 @@
+json.array! @games, partial: "games/game", as: :game
diff --git a/app/views/games/new.html.erb b/app/views/games/new.html.erb
new file mode 100644
index 00000000..47228e5d
--- /dev/null
+++ b/app/views/games/new.html.erb
@@ -0,0 +1,11 @@
+<% content_for :title, "New game" %>
+
+
New game
+
+<%= render "form", game: @game %>
+
+
+
+
+ <%= link_to "Back to games", games_path %>
+
diff --git a/app/views/games/show.html.erb b/app/views/games/show.html.erb
new file mode 100644
index 00000000..0ac3785d
--- /dev/null
+++ b/app/views/games/show.html.erb
@@ -0,0 +1,8 @@
+
<%= notice %>
+
+
+ <%= link_to "Edit this game", edit_game_path(@game) %> |
+ <%= link_to "Back to games", games_path %>
+
+ <%= button_to "Destroy this game", @game, method: :delete %>
+
diff --git a/app/views/games/show.json.jbuilder b/app/views/games/show.json.jbuilder
new file mode 100644
index 00000000..c04bffe0
--- /dev/null
+++ b/app/views/games/show.json.jbuilder
@@ -0,0 +1 @@
+json.partial! "games/game", game: @game
diff --git a/config/routes.rb b/config/routes.rb
index e1e77031..8391605a 100644
--- a/config/routes.rb
+++ b/config/routes.rb
@@ -1,7 +1,11 @@
Rails.application.routes.draw do
- # Define your application routes per the DSL in https://guides.rubyonrails.org/routing.html
+ resources :games
+ root :to => redirect('/games')
- # Reveal health status on /up that returns 200 if the app boots with no exceptions, otherwise 500.
- # Can be used by load balancers and uptime monitors to verify that the app is live.
get "up" => "rails/health#show", as: :rails_health_check
+
+ ## stub paths to demo game landing page
+ get '/spellingbee/:id', to: 'games#demo_game', as: 'spellingbee'
+ get '/wordle/:id', to: 'games#demo_game', as: 'wordle'
+ get '/letterboxed/:id', to: 'games#demo_game', as: 'letterboxed'
end
diff --git a/db/migrate/20241002002856_create_games.rb b/db/migrate/20241002002856_create_games.rb
new file mode 100644
index 00000000..f07419e5
--- /dev/null
+++ b/db/migrate/20241002002856_create_games.rb
@@ -0,0 +1,9 @@
+class CreateGames < ActiveRecord::Migration[7.2]
+ def change
+ create_table :games do |t|
+ t.string 'name'
+ t.string 'game_path'
+ t.timestamps
+ end
+ end
+end
diff --git a/db/schema.rb b/db/schema.rb
new file mode 100644
index 00000000..d43b0b5c
--- /dev/null
+++ b/db/schema.rb
@@ -0,0 +1,20 @@
+# This file is auto-generated from the current state of the database. Instead
+# of editing this file, please use the migrations feature of Active Record to
+# incrementally modify your database, and then regenerate this schema definition.
+#
+# This file is the source Rails uses to define your schema when running `bin/rails
+# db:schema:load`. When creating a new database, `bin/rails db:schema:load` tends to
+# be faster and is potentially less error prone than running all of your
+# migrations from scratch. Old migrations may fail to apply correctly if those
+# migrations use external dependencies or application code.
+#
+# It's strongly recommended that you check this file into your version control system.
+
+ActiveRecord::Schema[7.2].define(version: 2024_10_02_002856) do
+ create_table "games", force: :cascade do |t|
+ t.string "name"
+ t.string "game_path"
+ t.datetime "created_at", null: false
+ t.datetime "updated_at", null: false
+ end
+end
diff --git a/db/seeds.rb b/db/seeds.rb
index 4fbd6ed9..75227866 100644
--- a/db/seeds.rb
+++ b/db/seeds.rb
@@ -7,3 +7,13 @@
# ["Action", "Comedy", "Drama", "Horror"].each do |genre_name|
# MovieGenre.find_or_create_by!(name: genre_name)
# end
+
+initial_games = [
+ {:name => 'Spelling Bee', :game_path => 'spellingbee_path'},
+ {:name => 'Wordle', :game_path => 'wordle_path'},
+ {:name => 'Letter Boxed', :game_path => 'letterboxed_path'}
+]
+
+initial_games.each do |game|
+ Game.find_or_create_by!(game)
+end
diff --git a/features/.DS_Store b/features/.DS_Store
new file mode 100644
index 00000000..c5cf507b
Binary files /dev/null and b/features/.DS_Store differ
diff --git a/test/controllers/games_controller_test.rb b/test/controllers/games_controller_test.rb
new file mode 100644
index 00000000..90bfc200
--- /dev/null
+++ b/test/controllers/games_controller_test.rb
@@ -0,0 +1,48 @@
+require "test_helper"
+
+class GamesControllerTest < ActionDispatch::IntegrationTest
+ setup do
+ @game = games(:one)
+ end
+
+ test "should get index" do
+ get games_url
+ assert_response :success
+ end
+
+ test "should get new" do
+ get new_game_url
+ assert_response :success
+ end
+
+ test "should create game" do
+ assert_difference("Game.count") do
+ post games_url, params: { game: { game_path: @game.game_path, name: @game.name } }
+ end
+
+ assert_redirected_to game_url(Game.last)
+ end
+
+ test "should show game" do
+ get game_url(@game)
+ assert_response :success
+ end
+
+ test "should get edit" do
+ get edit_game_url(@game)
+ assert_response :success
+ end
+
+ test "should update game" do
+ patch game_url(@game), params: { game: { game_path: @game.game_path, name: @game.name } }
+ assert_redirected_to game_url(@game)
+ end
+
+ test "should destroy game" do
+ assert_difference("Game.count", -1) do
+ delete game_url(@game)
+ end
+
+ assert_redirected_to games_url
+ end
+end
diff --git a/test/controllers/pages_controller_test.rb b/test/controllers/pages_controller_test.rb
new file mode 100644
index 00000000..d975bb19
--- /dev/null
+++ b/test/controllers/pages_controller_test.rb
@@ -0,0 +1,8 @@
+require "test_helper"
+
+class PagesControllerTest < ActionDispatch::IntegrationTest
+ test "should get index" do
+ get pages_index_url
+ assert_response :success
+ end
+end
diff --git a/test/fixtures/games.yml b/test/fixtures/games.yml
new file mode 100644
index 00000000..382f6d84
--- /dev/null
+++ b/test/fixtures/games.yml
@@ -0,0 +1,9 @@
+# Read about fixtures at https://api.rubyonrails.org/classes/ActiveRecord/FixtureSet.html
+
+one:
+ name: MyString
+ description: MyText
+
+two:
+ name: MyString
+ description: MyText
diff --git a/test/models/game_test.rb b/test/models/game_test.rb
new file mode 100644
index 00000000..6628fae0
--- /dev/null
+++ b/test/models/game_test.rb
@@ -0,0 +1,7 @@
+require "test_helper"
+
+class GameTest < ActiveSupport::TestCase
+ # test "the truth" do
+ # assert true
+ # end
+end
diff --git a/test/system/games_test.rb b/test/system/games_test.rb
new file mode 100644
index 00000000..1b7d1439
--- /dev/null
+++ b/test/system/games_test.rb
@@ -0,0 +1,43 @@
+require "application_system_test_case"
+
+class GamesTest < ApplicationSystemTestCase
+ setup do
+ @game = games(:one)
+ end
+
+ test "visiting the index" do
+ visit games_url
+ assert_selector "h1", text: "Games"
+ end
+
+ test "should create game" do
+ visit games_url
+ click_on "New game"
+
+ fill_in "Game path", with: @game.game_path
+ fill_in "Name", with: @game.name
+ click_on "Create Game"
+
+ assert_text "Game was successfully created"
+ click_on "Back"
+ end
+
+ test "should update Game" do
+ visit game_url(@game)
+ click_on "Edit this game", match: :first
+
+ fill_in "Game path", with: @game.game_path
+ fill_in "Name", with: @game.name
+ click_on "Update Game"
+
+ assert_text "Game was successfully updated"
+ click_on "Back"
+ end
+
+ test "should destroy Game" do
+ visit game_url(@game)
+ click_on "Destroy this game", match: :first
+
+ assert_text "Game was successfully destroyed"
+ end
+end