From 3b6b48bc8b44268bb6273ea15811934bb7654ec7 Mon Sep 17 00:00:00 2001 From: Adam Bachman <13002+abachman@users.noreply.github.com> Date: Sat, 29 Aug 2026 16:43:49 -0400 Subject: [PATCH 1/6] change game_attempts.token to text and allow null --- .../20260829203815_allow_null_game_attempt_token.rb | 9 +++++++++ db/schema.rb | 4 ++-- 2 files changed, 11 insertions(+), 2 deletions(-) create mode 100644 db/migrate/20260829203815_allow_null_game_attempt_token.rb diff --git a/db/migrate/20260829203815_allow_null_game_attempt_token.rb b/db/migrate/20260829203815_allow_null_game_attempt_token.rb new file mode 100644 index 0000000..2f49a8d --- /dev/null +++ b/db/migrate/20260829203815_allow_null_game_attempt_token.rb @@ -0,0 +1,9 @@ +class AllowNullGameAttemptToken < ActiveRecord::Migration[8.1] + def up + change_column :game_attempts, :token, :text, null: true + end + + def down + change_column :game_attempts, :token, :string, null: false + end +end diff --git a/db/schema.rb b/db/schema.rb index a58913e..ef656fe 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[8.1].define(version: 2026_08_29_190944) do +ActiveRecord::Schema[8.1].define(version: 2026_08_29_203815) do create_table "classroom_modules", force: :cascade do |t| t.integer "classroom_program_id", null: false t.integer "content_module_id", null: false @@ -73,7 +73,7 @@ t.integer "score" t.datetime "started_at" t.integer "student_id", null: false - t.string "token", null: false + t.text "token" t.datetime "updated_at", null: false t.index ["game_id"], name: "index_game_attempts_on_game_id" t.index ["student_id"], name: "index_game_attempts_on_student_id" From e9936805f59c407128e5fcdf995619ba1fb4ab50 Mon Sep 17 00:00:00 2001 From: Adam Bachman <13002+abachman@users.noreply.github.com> Date: Sat, 29 Aug 2026 19:01:22 -0400 Subject: [PATCH 2/6] we actually do want game_attempts to have tokens, and we don't need a #show action --- .../20260829203815_allow_null_game_attempt_token.rb | 9 --------- db/schema.rb | 4 ++-- 2 files changed, 2 insertions(+), 11 deletions(-) delete mode 100644 db/migrate/20260829203815_allow_null_game_attempt_token.rb diff --git a/db/migrate/20260829203815_allow_null_game_attempt_token.rb b/db/migrate/20260829203815_allow_null_game_attempt_token.rb deleted file mode 100644 index 2f49a8d..0000000 --- a/db/migrate/20260829203815_allow_null_game_attempt_token.rb +++ /dev/null @@ -1,9 +0,0 @@ -class AllowNullGameAttemptToken < ActiveRecord::Migration[8.1] - def up - change_column :game_attempts, :token, :text, null: true - end - - def down - change_column :game_attempts, :token, :string, null: false - end -end diff --git a/db/schema.rb b/db/schema.rb index ef656fe..a58913e 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[8.1].define(version: 2026_08_29_203815) do +ActiveRecord::Schema[8.1].define(version: 2026_08_29_190944) do create_table "classroom_modules", force: :cascade do |t| t.integer "classroom_program_id", null: false t.integer "content_module_id", null: false @@ -73,7 +73,7 @@ t.integer "score" t.datetime "started_at" t.integer "student_id", null: false - t.text "token" + t.string "token", null: false t.datetime "updated_at", null: false t.index ["game_id"], name: "index_game_attempts_on_game_id" t.index ["student_id"], name: "index_game_attempts_on_student_id" From 1705027bf149f96087e64d5e03082df2693ab14d Mon Sep 17 00:00:00 2001 From: Adam Bachman <13002+abachman@users.noreply.github.com> Date: Sat, 29 Aug 2026 19:04:20 -0400 Subject: [PATCH 3/6] drop score from game attempt fixtures --- test/fixtures/game_attempts.yml | 2 -- 1 file changed, 2 deletions(-) diff --git a/test/fixtures/game_attempts.yml b/test/fixtures/game_attempts.yml index 8db4e1f..8e0dd1f 100644 --- a/test/fixtures/game_attempts.yml +++ b/test/fixtures/game_attempts.yml @@ -1,7 +1,6 @@ # Read about fixtures at https://api.rubyonrails.org/classes/ActiveRecord/FixtureSet.html one: - score: 1 outcome: completed started_at: 2026-08-29 11:53:38 finished_at: 2026-08-29 11:53:38 @@ -10,7 +9,6 @@ one: token: onetoken two: - score: 1 outcome: expired started_at: 2026-08-29 11:53:38 finished_at: 2026-08-29 11:53:38 From 0ba30e84c66c26e9d394c0b712b3a8d6b604b68a Mon Sep 17 00:00:00 2001 From: Adam Bachman <13002+abachman@users.noreply.github.com> Date: Sun, 30 Aug 2026 10:25:08 -0400 Subject: [PATCH 4/6] [WIP] playing fake games --- app/controllers/game_landing_controller.rb | 21 ++++++ app/javascript/controllers/quiz_controller.js | 73 +++++++++++++++++++ app/views/game_landing/embed.html.erb | 7 ++ app/views/game_landing/show.html.erb | 7 ++ app/views/layouts/embed.html.erb | 16 ++++ config/routes.rb | 6 ++ .../game_landing_controller_test.rb | 33 +++++++++ 7 files changed, 163 insertions(+) create mode 100644 app/controllers/game_landing_controller.rb create mode 100644 app/javascript/controllers/quiz_controller.js create mode 100644 app/views/game_landing/embed.html.erb create mode 100644 app/views/game_landing/show.html.erb create mode 100644 app/views/layouts/embed.html.erb create mode 100644 test/controllers/game_landing_controller_test.rb diff --git a/app/controllers/game_landing_controller.rb b/app/controllers/game_landing_controller.rb new file mode 100644 index 0000000..682c5b4 --- /dev/null +++ b/app/controllers/game_landing_controller.rb @@ -0,0 +1,21 @@ +class GameLandingController < ApplicationController + include StudentAuthentication + + layout "embed", only: :embed + + def show + @game = Game.find(params[:id]) + @game_attempt_token = GameAttempt.generate_token(student_id: current_student.id, game_id: @game.id) + + logger.info("game attempt token: #{{game_attempt_token: @game_attempt_token, student_id: current_student.id, game_id: @game.id}}") + end + + def embed + @game = Game.find(params[:id]) + end + + private + + def current_student = Current.student + helper_method :current_student +end diff --git a/app/javascript/controllers/quiz_controller.js b/app/javascript/controllers/quiz_controller.js new file mode 100644 index 0000000..5acdf8c --- /dev/null +++ b/app/javascript/controllers/quiz_controller.js @@ -0,0 +1,73 @@ +import { Controller } from "@hotwired/stimulus" + +const QUESTIONS = [ + { text: "The sky is blue.", answer: true }, + { text: "Fish can breathe air out of water.", answer: false }, + { text: "The earth orbits the sun.", answer: true } +] + +export default class extends Controller { + static targets = ["root"] + static values = { startUrl: String, finishUrl: String } + + connect() { + this.token = new URLSearchParams(window.location.search).get("token") + this.questionIndex = 0 + this.correctCount = 0 + this.started = false + this.renderQuestion() + } + + renderQuestion() { + const question = QUESTIONS[this.questionIndex] + this.rootTarget.innerHTML = ` +
${question.text}
+You scored ${this.correctCount} out of ${QUESTIONS.length}.
` + } + + async post(url, extraParams = {}) { + const csrfToken = document.querySelector("meta[name='csrf-token']")?.content + + await fetch(url, { + method: "POST", + headers: { + "Content-Type": "application/json", + "X-CSRF-Token": csrfToken + }, + body: JSON.stringify({ token: this.token, ...extraParams }) + }) + } +} diff --git a/app/views/game_landing/embed.html.erb b/app/views/game_landing/embed.html.erb new file mode 100644 index 0000000..bbc39d5 --- /dev/null +++ b/app/views/game_landing/embed.html.erb @@ -0,0 +1,7 @@ +<%= tag.div data: { + controller: "quiz", + quiz_start_url_value: start_game_attempts_path, + quiz_finish_url_value: finish_game_attempts_path + } do %> + +<% end %> diff --git a/app/views/game_landing/show.html.erb b/app/views/game_landing/show.html.erb new file mode 100644 index 0000000..78de03c --- /dev/null +++ b/app/views/game_landing/show.html.erb @@ -0,0 +1,7 @@ +<% content_for(:title, @game.title) %> + +