diff --git a/app/controllers/test/images_controller.rb b/app/controllers/test/images_controller.rb
new file mode 100644
index 0000000..aebeba8
--- /dev/null
+++ b/app/controllers/test/images_controller.rb
@@ -0,0 +1,25 @@
+class Test::ImagesController < ApplicationController
+ def index
+ @images = Image.all
+ @image = Image.new
+ end
+
+ def create
+ @image = Image.new(image_params)
+
+ if @image.save
+ respond_to do |format|
+ format.turbo_stream
+ format.html { redirect_to test_images_path }
+ end
+ else
+ render :index, status: :unprocessable_entity
+ end
+ end
+
+ private
+
+ def image_params
+ params.require(:image).permit(:title, :file)
+ end
+end
diff --git a/app/helpers/test/images_helper.rb b/app/helpers/test/images_helper.rb
new file mode 100644
index 0000000..53c4ea6
--- /dev/null
+++ b/app/helpers/test/images_helper.rb
@@ -0,0 +1,2 @@
+module Test::ImagesHelper
+end
diff --git a/app/models/image.rb b/app/models/image.rb
new file mode 100644
index 0000000..d6ecd36
--- /dev/null
+++ b/app/models/image.rb
@@ -0,0 +1,5 @@
+class Image < ApplicationRecord
+ has_one_attached :file
+
+ validates :title, :file, presence: true
+end
diff --git a/app/views/test/images/_image.html.erb b/app/views/test/images/_image.html.erb
new file mode 100644
index 0000000..1ea09c3
--- /dev/null
+++ b/app/views/test/images/_image.html.erb
@@ -0,0 +1,6 @@
+
+
<%= image.title %>
+ <% if image.file.attached? %>
+ <%= image_tag image.file, width: 300 %>
+ <% end %>
+
diff --git a/app/views/test/images/create.turbo_stream.erb b/app/views/test/images/create.turbo_stream.erb
new file mode 100644
index 0000000..43b7640
--- /dev/null
+++ b/app/views/test/images/create.turbo_stream.erb
@@ -0,0 +1 @@
+<%= turbo_stream.prepend "images", partial: "test/images/image", locals: { image: @image } %>
diff --git a/app/views/test/images/index.html.erb b/app/views/test/images/index.html.erb
new file mode 100644
index 0000000..ac76716
--- /dev/null
+++ b/app/views/test/images/index.html.erb
@@ -0,0 +1,20 @@
+Image Upload (Test)
+
+<%= form_with model: @image, url: test_images_path, data: { turbo_stream: true } do |form| %>
+ <%= form.label :title %>
+ <%= form.text_field :title %>
+
+ <%= form.label :file %>
+ <%= form.file_field :file %>
+
+ <%= form.submit "Upload" %>
+<% end %>
+
+
+
+Uploaded Images
+
+ <%= turbo_frame_tag "images" do %>
+ <%= render @images %>
+ <% end %>
+
diff --git a/config/routes.rb b/config/routes.rb
index 167b8ab..558a2cf 100644
--- a/config/routes.rb
+++ b/config/routes.rb
@@ -1,4 +1,11 @@
Rails.application.routes.draw do
+ namespace :test do
+ resources :images
+ get "images/index"
+ get "images/new"
+ get "images/create"
+ get "images/show"
+ end
resources :notes
# Define your application routes per the DSL in https://guides.rubyonrails.org/routing.html
diff --git a/db/migrate/20250507082715_create_active_storage_tables.active_storage.rb b/db/migrate/20250507082715_create_active_storage_tables.active_storage.rb
new file mode 100644
index 0000000..6bd8bd0
--- /dev/null
+++ b/db/migrate/20250507082715_create_active_storage_tables.active_storage.rb
@@ -0,0 +1,57 @@
+# This migration comes from active_storage (originally 20170806125915)
+class CreateActiveStorageTables < ActiveRecord::Migration[7.0]
+ def change
+ # Use Active Record's configured type for primary and foreign keys
+ primary_key_type, foreign_key_type = primary_and_foreign_key_types
+
+ create_table :active_storage_blobs, id: primary_key_type do |t|
+ t.string :key, null: false
+ t.string :filename, null: false
+ t.string :content_type
+ t.text :metadata
+ t.string :service_name, null: false
+ t.bigint :byte_size, null: false
+ t.string :checksum
+
+ if connection.supports_datetime_with_precision?
+ t.datetime :created_at, precision: 6, null: false
+ else
+ t.datetime :created_at, null: false
+ end
+
+ t.index [ :key ], unique: true
+ end
+
+ create_table :active_storage_attachments, id: primary_key_type do |t|
+ t.string :name, null: false
+ t.references :record, null: false, polymorphic: true, index: false, type: foreign_key_type
+ t.references :blob, null: false, type: foreign_key_type
+
+ if connection.supports_datetime_with_precision?
+ t.datetime :created_at, precision: 6, null: false
+ else
+ t.datetime :created_at, null: false
+ end
+
+ t.index [ :record_type, :record_id, :name, :blob_id ], name: :index_active_storage_attachments_uniqueness, unique: true
+ t.foreign_key :active_storage_blobs, column: :blob_id
+ end
+
+ create_table :active_storage_variant_records, id: primary_key_type do |t|
+ t.belongs_to :blob, null: false, index: false, type: foreign_key_type
+ t.string :variation_digest, null: false
+
+ t.index [ :blob_id, :variation_digest ], name: :index_active_storage_variant_records_uniqueness, unique: true
+ t.foreign_key :active_storage_blobs, column: :blob_id
+ end
+ end
+
+ private
+ def primary_and_foreign_key_types
+ config = Rails.configuration.generators
+ setting = config.options[config.orm][:primary_key_type]
+ primary_key_type = setting || :primary_key
+ foreign_key_type = setting || :bigint
+ [ primary_key_type, foreign_key_type ]
+ end
+end
diff --git a/db/migrate/20250507082751_create_images.rb b/db/migrate/20250507082751_create_images.rb
new file mode 100644
index 0000000..163e6d4
--- /dev/null
+++ b/db/migrate/20250507082751_create_images.rb
@@ -0,0 +1,9 @@
+class CreateImages < ActiveRecord::Migration[8.0]
+ def change
+ create_table :images do |t|
+ t.string :title
+
+ t.timestamps
+ end
+ end
+end
diff --git a/db/schema.rb b/db/schema.rb
index db88925..ed9b460 100644
--- a/db/schema.rb
+++ b/db/schema.rb
@@ -10,11 +10,48 @@
#
# It's strongly recommended that you check this file into your version control system.
-ActiveRecord::Schema[8.0].define(version: 2025_05_06_085403) do
+ActiveRecord::Schema[8.0].define(version: 2025_05_07_082751) do
+ create_table "active_storage_attachments", force: :cascade do |t|
+ t.string "name", null: false
+ t.string "record_type", null: false
+ t.bigint "record_id", null: false
+ t.bigint "blob_id", null: false
+ t.datetime "created_at", null: false
+ t.index ["blob_id"], name: "index_active_storage_attachments_on_blob_id"
+ t.index ["record_type", "record_id", "name", "blob_id"], name: "index_active_storage_attachments_uniqueness", unique: true
+ end
+
+ create_table "active_storage_blobs", force: :cascade do |t|
+ t.string "key", null: false
+ t.string "filename", null: false
+ t.string "content_type"
+ t.text "metadata"
+ t.string "service_name", null: false
+ t.bigint "byte_size", null: false
+ t.string "checksum"
+ t.datetime "created_at", null: false
+ t.index ["key"], name: "index_active_storage_blobs_on_key", unique: true
+ end
+
+ create_table "active_storage_variant_records", force: :cascade do |t|
+ t.bigint "blob_id", null: false
+ t.string "variation_digest", null: false
+ t.index ["blob_id", "variation_digest"], name: "index_active_storage_variant_records_uniqueness", unique: true
+ end
+
+ create_table "images", force: :cascade do |t|
+ t.string "title"
+ t.datetime "created_at", null: false
+ t.datetime "updated_at", null: false
+ end
+
create_table "notes", force: :cascade do |t|
t.string "title"
t.text "body"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
+
+ 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"
end
diff --git a/test/controllers/test/images_controller_test.rb b/test/controllers/test/images_controller_test.rb
new file mode 100644
index 0000000..4a9a08d
--- /dev/null
+++ b/test/controllers/test/images_controller_test.rb
@@ -0,0 +1,23 @@
+require "test_helper"
+
+class Test::ImagesControllerTest < ActionDispatch::IntegrationTest
+ test "should get index" do
+ get test_images_index_url
+ assert_response :success
+ end
+
+ test "should get new" do
+ get test_images_new_url
+ assert_response :success
+ end
+
+ test "should get create" do
+ get test_images_create_url
+ assert_response :success
+ end
+
+ test "should get show" do
+ get test_images_show_url
+ assert_response :success
+ end
+end
diff --git a/test/fixtures/images.yml b/test/fixtures/images.yml
new file mode 100644
index 0000000..64d88ef
--- /dev/null
+++ b/test/fixtures/images.yml
@@ -0,0 +1,7 @@
+# Read about fixtures at https://api.rubyonrails.org/classes/ActiveRecord/FixtureSet.html
+
+one:
+ title: MyString
+
+two:
+ title: MyString
diff --git a/test/models/image_test.rb b/test/models/image_test.rb
new file mode 100644
index 0000000..8650df9
--- /dev/null
+++ b/test/models/image_test.rb
@@ -0,0 +1,7 @@
+require "test_helper"
+
+class ImageTest < ActiveSupport::TestCase
+ # test "the truth" do
+ # assert true
+ # end
+end