From d635f52d861900b73604b9a379e61439ea385af2 Mon Sep 17 00:00:00 2001 From: Erin Bond Date: Mon, 22 Jun 2026 08:14:42 -0600 Subject: [PATCH] Add scrapbook_entries table migration Extracted from #72964 (Student Scrapbook V1) so the schema change can land independently of the feature code. Creates the scrapbook_entries table that backs per-user scrapbook entries, keyed either by (script_id, level_id) for in-curriculum levels or by channel_id for standalone projects. Co-Authored-By: Claude Opus 4.8 (1M context) --- ...20260513120000_create_scrapbook_entries.rb | 24 +++++++++++++++++++ dashboard/db/schema.rb | 16 +++++++++++++ 2 files changed, 40 insertions(+) create mode 100644 dashboard/db/migrate/20260513120000_create_scrapbook_entries.rb diff --git a/dashboard/db/migrate/20260513120000_create_scrapbook_entries.rb b/dashboard/db/migrate/20260513120000_create_scrapbook_entries.rb new file mode 100644 index 0000000000000..5ea21155a5bf5 --- /dev/null +++ b/dashboard/db/migrate/20260513120000_create_scrapbook_entries.rb @@ -0,0 +1,24 @@ +class CreateScrapbookEntries < ActiveRecord::Migration[7.0] + def change + create_table :scrapbook_entries do |t| + t.references :user, null: false, foreign_key: true, type: :integer + # An entry is keyed either by (script_id, level_id) for in-curriculum + # levels, or by channel_id for standalone projects. Both keyings are + # nullable; the model enforces that exactly one is present. + t.integer :script_id + t.integer :level_id + t.string :channel_id + # Image bytes live in S3; these columns hold only the bare filename + # reference (see Scrapbook::ImageStore). + t.string :before_asset_url + t.string :after_asset_url + t.text :entry_text + t.timestamps + end + # MySQL treats NULL as distinct, so each unique index only constrains rows + # whose key columns are non-NULL: the script_level rows ignore the channel + # index and vice versa. + add_index :scrapbook_entries, [:user_id, :script_id, :level_id], unique: true + add_index :scrapbook_entries, [:user_id, :channel_id], unique: true + end +end diff --git a/dashboard/db/schema.rb b/dashboard/db/schema.rb index bdd6c8efd5dc0..ae8156e399cae 100644 --- a/dashboard/db/schema.rb +++ b/dashboard/db/schema.rb @@ -2203,6 +2203,21 @@ t.index ["zip"], name: "index_schools_on_zip" end + create_table "scrapbook_entries", charset: "utf8mb4", collation: "utf8mb4_unicode_ci", force: :cascade do |t| + t.integer "user_id", null: false + t.integer "script_id" + t.integer "level_id" + t.string "channel_id" + t.string "before_asset_url" + t.string "after_asset_url" + t.text "entry_text" + t.datetime "created_at", null: false + t.datetime "updated_at", null: false + t.index ["user_id", "channel_id"], name: "index_scrapbook_entries_on_user_id_and_channel_id", unique: true + t.index ["user_id", "script_id", "level_id"], name: "index_scrapbook_entries_on_user_id_and_script_id_and_level_id", unique: true + t.index ["user_id"], name: "index_scrapbook_entries_on_user_id" + end + create_table "script_levels", id: :integer, charset: "utf8mb3", collation: "utf8mb3_unicode_ci", force: :cascade do |t| t.integer "script_id", null: false t.integer "chapter" @@ -2969,6 +2984,7 @@ add_foreign_key "school_infos", "schools" add_foreign_key "school_stats_by_years", "schools" add_foreign_key "schools", "school_districts" + add_foreign_key "scrapbook_entries", "users" add_foreign_key "scripts", "unit_groups", column: "original_unit_group_id" add_foreign_key "section_instructors", "users", column: "instructor_id" add_foreign_key "section_instructors", "users", column: "invited_by_id"