From 6ff07733fa828ff4b1c6a1ae13e2599526a7324e Mon Sep 17 00:00:00 2001 From: Sean Dickinson Date: Tue, 21 Apr 2026 19:43:36 -0400 Subject: [PATCH 1/9] mark fork for cherry pick From a6fe2849cc7fc0bd0ef9ab0688df92387c634640 Mon Sep 17 00:00:00 2001 From: Sean Dickinson Date: Tue, 21 Apr 2026 20:28:51 -0400 Subject: [PATCH 2/9] feat: student crud --- app/controllers/students_controller.rb | 75 ++++++++++++++++++++ app/models/school.rb | 1 + app/models/student.rb | 7 ++ app/views/schools/index.html.erb | 4 +- app/views/students/_form.html.erb | 42 +++++++++++ app/views/students/_student.html.erb | 27 +++++++ app/views/students/edit.html.erb | 12 ++++ app/views/students/index.html.erb | 34 +++++++++ app/views/students/new.html.erb | 11 +++ app/views/students/show.html.erb | 10 +++ config/routes.rb | 4 +- db/migrate/20260421234927_create_students.rb | 14 ++++ db/schema.rb | 15 +++- test/controllers/students_controller_test.rb | 50 +++++++++++++ test/fixtures/students.yml | 15 ++++ test/models/student_test.rb | 7 ++ 16 files changed, 324 insertions(+), 4 deletions(-) create mode 100644 app/controllers/students_controller.rb create mode 100644 app/models/student.rb create mode 100644 app/views/students/_form.html.erb create mode 100644 app/views/students/_student.html.erb create mode 100644 app/views/students/edit.html.erb create mode 100644 app/views/students/index.html.erb create mode 100644 app/views/students/new.html.erb create mode 100644 app/views/students/show.html.erb create mode 100644 db/migrate/20260421234927_create_students.rb create mode 100644 test/controllers/students_controller_test.rb create mode 100644 test/fixtures/students.yml create mode 100644 test/models/student_test.rb diff --git a/app/controllers/students_controller.rb b/app/controllers/students_controller.rb new file mode 100644 index 0000000..9ce0047 --- /dev/null +++ b/app/controllers/students_controller.rb @@ -0,0 +1,75 @@ +class StudentsController < ApplicationController + before_action :set_school, only: %i[ index new create ] + before_action :set_student, only: %i[ show edit update destroy ] + + # GET /students or /students.json + def index + @students = @school.students.all + end + + # GET /students/1 or /students/1.json + def show + end + + # GET /students/new + def new + @student = @school.students.build + end + + # GET /students/1/edit + def edit + end + + # POST /students or /students.json + def create + @student = @school.students.build(student_params) + + respond_to do |format| + if @student.save + format.html { redirect_to @student, notice: "Student was successfully created." } + format.json { render :show, status: :created, location: @student } + else + format.html { render :new, status: :unprocessable_entity } + format.json { render json: @student.errors, status: :unprocessable_entity } + end + end + end + + # PATCH/PUT /students/1 or /students/1.json + def update + respond_to do |format| + if @student.update(student_params) + format.html { redirect_to @student, notice: "Student was successfully updated.", status: :see_other } + format.json { render :show, status: :ok, location: @student } + else + format.html { render :edit, status: :unprocessable_entity } + format.json { render json: @student.errors, status: :unprocessable_entity } + end + end + end + + # DELETE /students/1 or /students/1.json + def destroy + @student.destroy! + + respond_to do |format| + format.html { redirect_to school_students_path(@student.school_id), notice: "Student was successfully destroyed.", status: :see_other } + format.json { head :no_content } + end + end + + private + # Use callbacks to share common setup or constraints between actions. + def set_student + @student = Student.find(params.expect(:id)) + end + + def set_school + @school = School.find(params.expect(:school_id)) + end + + # Only allow a list of trusted parameters through. + def student_params + params.expect(student: [ :first_name, :last_name, :email, :grade_level, :gender ]) + end +end diff --git a/app/models/school.rb b/app/models/school.rb index ea2efb1..e05b6b4 100644 --- a/app/models/school.rb +++ b/app/models/school.rb @@ -1,3 +1,4 @@ class School < ApplicationRecord + has_many :students, dependent: :destroy validates :name, presence: true end diff --git a/app/models/student.rb b/app/models/student.rb new file mode 100644 index 0000000..031257f --- /dev/null +++ b/app/models/student.rb @@ -0,0 +1,7 @@ +class Student < ApplicationRecord + belongs_to :school + + enum :gender, %i[male female other].index_by(&:itself) + + validates :first_name, :last_name, :grade_level, presence: true +end diff --git a/app/views/schools/index.html.erb b/app/views/schools/index.html.erb index 4aeb8f0..20efb7e 100644 --- a/app/views/schools/index.html.erb +++ b/app/views/schools/index.html.erb @@ -9,7 +9,7 @@ + \ No newline at end of file diff --git a/app/views/students/_form.html.erb b/app/views/students/_form.html.erb new file mode 100644 index 0000000..a5c6bed --- /dev/null +++ b/app/views/students/_form.html.erb @@ -0,0 +1,42 @@ +<%= form_with(model: [@school, student]) do |form| %> + <% if student.errors.any? %> +
+

<%= pluralize(student.errors.count, "error") %> prohibited this student from being saved:

+ +
    + <% student.errors.each do |error| %> +
  • <%= error.full_message %>
  • + <% end %> +
+
+ <% end %> + +
+ <%= form.label :first_name, style: "display: block" %> + <%= form.text_field :first_name %> +
+ +
+ <%= form.label :last_name, style: "display: block" %> + <%= form.text_field :last_name %> +
+ +
+ <%= form.label :email, style: "display: block" %> + <%= form.text_field :email %> +
+ +
+ <%= form.label :grade_level, style: "display: block" %> + <%= form.number_field :grade_level %> +
+ +
+ <%= form.label :gender, style: "display: block" %> + <%= form.text_field :gender %> +
+ +
+ <%= form.submit %> +
+<% end %> diff --git a/app/views/students/_student.html.erb b/app/views/students/_student.html.erb new file mode 100644 index 0000000..f106eba --- /dev/null +++ b/app/views/students/_student.html.erb @@ -0,0 +1,27 @@ +
+
+ First name: + <%= student.first_name %> +
+ +
+ Last name: + <%= student.last_name %> +
+ +
+ Email: + <%= student.email %> +
+ +
+ Grade level: + <%= student.grade_level %> +
+ +
+ Gender: + <%= student.gender %> +
+ +
diff --git a/app/views/students/edit.html.erb b/app/views/students/edit.html.erb new file mode 100644 index 0000000..c1f5297 --- /dev/null +++ b/app/views/students/edit.html.erb @@ -0,0 +1,12 @@ +<% content_for :title, "Editing student" %> + +

Editing student

+ +<%= render "form", student: @student %> + +
+ +
+ <%= link_to "Show this student", @student %> | + <%= link_to "Back to students", school_students_path(@student.school_id) %> +
diff --git a/app/views/students/index.html.erb b/app/views/students/index.html.erb new file mode 100644 index 0000000..377877f --- /dev/null +++ b/app/views/students/index.html.erb @@ -0,0 +1,34 @@ +

<%= notice %>

+ +<% content_for :title, [@school.name, "Students"].join(" - ") %> + +

Students for <%= @school.name %>

+ + + + + + + + + + + + + + + <% @students.each do |student| %> + + + + + + + +
First nameLast nameEmailGrade levelGenderActions
<%= student.first_name %><%= student.last_name %><%= student.email %><%= student.grade_level %><%= student.gender %> + <%= link_to "Edit", edit_student_path(student) %> | + <%= button_to "Delete", student, method: :delete, data: { confirm: "Are you sure?" } %> + <% end %> +
+ +<%= link_to "New student", new_school_student_path(@school) %> diff --git a/app/views/students/new.html.erb b/app/views/students/new.html.erb new file mode 100644 index 0000000..18675c4 --- /dev/null +++ b/app/views/students/new.html.erb @@ -0,0 +1,11 @@ +<% content_for :title, "New student" %> + +

New student

+ +<%= render "form", student: @student %> + +
+ +
+ <%= link_to "Back to students", school_students_path(@student.school_id) %> +
diff --git a/app/views/students/show.html.erb b/app/views/students/show.html.erb new file mode 100644 index 0000000..89f99f4 --- /dev/null +++ b/app/views/students/show.html.erb @@ -0,0 +1,10 @@ +

<%= notice %>

+ +<%= render @student %> + +
+ <%= link_to "Edit this student", edit_student_path(@student) %> | + <%= link_to "Back to students", school_students_path(@student.school_id) %> + + <%= button_to "Destroy this student", @student, method: :delete %> +
diff --git a/config/routes.rb b/config/routes.rb index 0282416..608cfc5 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -2,7 +2,9 @@ resource :session resources :passwords, param: :token scope :admin do - resources :schools + resources :schools do + resources :students, shallow: true + end end root to: "schools#index" diff --git a/db/migrate/20260421234927_create_students.rb b/db/migrate/20260421234927_create_students.rb new file mode 100644 index 0000000..aa5baa7 --- /dev/null +++ b/db/migrate/20260421234927_create_students.rb @@ -0,0 +1,14 @@ +class CreateStudents < ActiveRecord::Migration[8.1] + def change + create_table :students do |t| + t.string :first_name, null: false + t.string :last_name, null: false + t.string :email + t.integer :grade_level, null: false + t.string :gender + t.belongs_to :school, null: false, foreign_key: true + + t.timestamps + end + end +end diff --git a/db/schema.rb b/db/schema.rb index 1736a01..e8cf50e 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_04_18_182356) do +ActiveRecord::Schema[8.1].define(version: 2026_04_21_234927) do create_table "schools", force: :cascade do |t| t.datetime "created_at", null: false t.string "name" @@ -26,6 +26,18 @@ t.index ["user_id"], name: "index_sessions_on_user_id" end + create_table "students", force: :cascade do |t| + t.datetime "created_at", null: false + t.string "email" + t.string "first_name", null: false + t.string "gender" + t.integer "grade_level", null: false + t.string "last_name", null: false + t.integer "school_id", null: false + t.datetime "updated_at", null: false + t.index ["school_id"], name: "index_students_on_school_id" + end + create_table "users", force: :cascade do |t| t.datetime "created_at", null: false t.string "email_address", null: false @@ -36,4 +48,5 @@ end add_foreign_key "sessions", "users" + add_foreign_key "students", "schools" end diff --git a/test/controllers/students_controller_test.rb b/test/controllers/students_controller_test.rb new file mode 100644 index 0000000..49c3fa0 --- /dev/null +++ b/test/controllers/students_controller_test.rb @@ -0,0 +1,50 @@ +require "test_helper" + +class StudentsControllerTest < ActionDispatch::IntegrationTest + setup do + @school = schools(:one) + @student = students(:ada) + sign_in_as users(:admin) + end + + test "should get index" do + get school_students_url(@school) + assert_response :success + end + + test "should get new" do + get new_school_student_url(@school) + assert_response :success + end + + test "should create student" do + assert_difference("Student.count") do + post school_students_url(@school), params: { student: { email: @student.email, first_name: @student.first_name, gender: @student.gender, grade_level: @student.grade_level, last_name: @student.last_name, school_id: @student.school_id } } + end + + assert_redirected_to student_url(Student.last) + end + + test "should show student" do + get student_url(@student) + assert_response :success + end + + test "should get edit" do + get edit_student_url(@student) + assert_response :success + end + + test "should update student" do + patch student_url(@student), params: { student: { email: @student.email, first_name: @student.first_name, gender: @student.gender, grade_level: @student.grade_level, last_name: @student.last_name, school_id: @student.school_id } } + assert_redirected_to student_url(@student) + end + + test "should destroy student" do + assert_difference("Student.count", -1) do + delete student_url(@student) + end + + assert_redirected_to school_students_url(@school) + end +end diff --git a/test/fixtures/students.yml b/test/fixtures/students.yml new file mode 100644 index 0000000..b6b8a60 --- /dev/null +++ b/test/fixtures/students.yml @@ -0,0 +1,15 @@ +ada: + first_name: Ada + last_name: Lovelace + email: + grade_level: 5 + gender: + school: one + +grace: + first_name: Grace + last_name: Hopper + email: ghopper@example.com + grade_level: 6 + gender: female + school: two diff --git a/test/models/student_test.rb b/test/models/student_test.rb new file mode 100644 index 0000000..88b348f --- /dev/null +++ b/test/models/student_test.rb @@ -0,0 +1,7 @@ +require "test_helper" + +class StudentTest < ActiveSupport::TestCase + # test "the truth" do + # assert true + # end +end From a9c2a80b4f760d9dd8b99c8222849df379e52e91 Mon Sep 17 00:00:00 2001 From: Sean Dickinson Date: Tue, 21 Apr 2026 20:28:58 -0400 Subject: [PATCH 3/9] feat: student seeds --- Gemfile | 1 + Gemfile.lock | 4 ++++ db/seeds.rb | 24 +++++++++++++++++++++++- 3 files changed, 28 insertions(+), 1 deletion(-) diff --git a/Gemfile b/Gemfile index e19ab8d..eceefaa 100644 --- a/Gemfile +++ b/Gemfile @@ -66,3 +66,4 @@ group :test do end gem "tailwindcss-rails", "~> 4.4" +gem "faker", "~> 3.8", group: :development diff --git a/Gemfile.lock b/Gemfile.lock index 4f6b1a9..0d25d35 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -114,6 +114,8 @@ GEM erubi (1.13.1) et-orbi (1.4.0) tzinfo + faker (3.8.0) + i18n (>= 1.8.11, < 2) ffi (1.17.4-aarch64-linux-gnu) ffi (1.17.4-aarch64-linux-musl) ffi (1.17.4-arm-linux-gnu) @@ -405,6 +407,7 @@ DEPENDENCIES bundler-audit capybara debug + faker (~> 3.8) image_processing (~> 1.2) importmap-rails jbuilder @@ -461,6 +464,7 @@ CHECKSUMS erb (6.0.3) sha256=e43685a8a0a0ea6a924871b2162e8953ef73147ce46b75b36d1f6774fd286e91 erubi (1.13.1) sha256=a082103b0885dbc5ecf1172fede897f9ebdb745a4b97a5e8dc63953db1ee4ad9 et-orbi (1.4.0) sha256=6c7e3c90779821f9e3b324c5e96fda9767f72995d6ae435b96678a4f3e2de8bc + faker (3.8.0) sha256=c147b308df73a90f27a4fc84f18d4c22ef0ad9c2a64b2b61c86fd0ca71753efc ffi (1.17.4-aarch64-linux-gnu) sha256=b208f06f91ffd8f5e1193da3cae3d2ccfc27fc36fba577baf698d26d91c080df ffi (1.17.4-aarch64-linux-musl) sha256=9286b7a615f2676245283aef0a0a3b475ae3aae2bb5448baace630bb77b91f39 ffi (1.17.4-arm-linux-gnu) sha256=d6dbddf7cb77bf955411af5f187a65b8cd378cb003c15c05697f5feee1cb1564 diff --git a/db/seeds.rb b/db/seeds.rb index 1611db1..9c601be 100644 --- a/db/seeds.rb +++ b/db/seeds.rb @@ -5,4 +5,26 @@ user.password = "password" end -School.find_or_create_by!(name: "Example School") +school = School.find_or_create_by!(name: "Example School") + +def maybe(&block) + return unless Faker::Boolean.boolean + + block.call +end + +def build_student_attrs(overrides = {}) + { + first_name: Faker::Name.first_name, + last_name: Faker::Name.last_name, + email: maybe { Faker::Internet.email(domain: 'example.com') }, + gender: maybe { Student.genders.keys.sample } + }.merge(overrides) +end + +# randomly sample 3 grade levels and create 10 students for each grade level +grades = (1..12).to_a.sample(3) +grades.each do |grade| + students = 10.times.map { build_student_attrs(grade_level: grade) } + school.students.create!(students) +end From 764b237de3ffde08e54215829d4025beb5f606c1 Mon Sep 17 00:00:00 2001 From: Sean Dickinson Date: Wed, 22 Apr 2026 20:19:04 -0400 Subject: [PATCH 4/9] feat: style --- app/assets/stylesheets/admin.css | 18 ++++++++++++++++++ app/assets/stylesheets/application.css | 8 ++++++++ app/assets/stylesheets/buttons.css | 22 ++++++++++++++++++++++ app/assets/stylesheets/variables.css | 6 ++++++ app/views/layouts/application.html.erb | 1 + app/views/students/index.html.erb | 10 ++++++---- 6 files changed, 61 insertions(+), 4 deletions(-) create mode 100644 app/assets/stylesheets/admin.css create mode 100644 app/assets/stylesheets/buttons.css create mode 100644 app/assets/stylesheets/variables.css diff --git a/app/assets/stylesheets/admin.css b/app/assets/stylesheets/admin.css new file mode 100644 index 0000000..21045be --- /dev/null +++ b/app/assets/stylesheets/admin.css @@ -0,0 +1,18 @@ +.admin { + & .index-table { + width: 100%; + border-collapse: collapse; + + & th, & td { + border: 1px solid gray; + padding: 0.5rem; + text-align: center; + } + + & td .actions { + display: flex; + justify-content: center; + gap: 0.25rem; + } + } +} \ No newline at end of file diff --git a/app/assets/stylesheets/application.css b/app/assets/stylesheets/application.css index fe93333..6f7d58c 100644 --- a/app/assets/stylesheets/application.css +++ b/app/assets/stylesheets/application.css @@ -8,3 +8,11 @@ * * Consider organizing styles into separate files for maintainability. */ + +@import "./variables.css"; +@import "./admin.css"; +@import "./buttons.css"; + +*, ::before, ::after { + box-sizing: border-box; +} diff --git a/app/assets/stylesheets/buttons.css b/app/assets/stylesheets/buttons.css new file mode 100644 index 0000000..e40cb10 --- /dev/null +++ b/app/assets/stylesheets/buttons.css @@ -0,0 +1,22 @@ +button, .btn, input[type="submit"] { + display: inline-block; + padding: .325rem .75rem; + margin-bottom: 0; + font-weight: normal; + font-family: Verdana, sans-serif; + font-size: var(--base-font-size); + text-align: center; + white-space: nowrap; + vertical-align: middle; + cursor: pointer; + background-image: none; + border: 1px solid transparent; + border-radius: .25rem; + background: var(--primary-color); + color: var(--white); + text-decoration: none; + + &.btn--danger { + background: var(--danger-color); + } +} \ No newline at end of file diff --git a/app/assets/stylesheets/variables.css b/app/assets/stylesheets/variables.css new file mode 100644 index 0000000..f4f492f --- /dev/null +++ b/app/assets/stylesheets/variables.css @@ -0,0 +1,6 @@ +:root { + --primary-color: #71beb7; + --white: #fff; + --danger-color: #e74c3c; + --base-font-size: 16px; +} \ No newline at end of file diff --git a/app/views/layouts/application.html.erb b/app/views/layouts/application.html.erb index 2ebff44..2b6d948 100644 --- a/app/views/layouts/application.html.erb +++ b/app/views/layouts/application.html.erb @@ -28,4 +28,5 @@ <%= yield %> + diff --git a/app/views/students/index.html.erb b/app/views/students/index.html.erb index 377877f..0627eb9 100644 --- a/app/views/students/index.html.erb +++ b/app/views/students/index.html.erb @@ -1,10 +1,10 @@

<%= notice %>

-<% content_for :title, [@school.name, "Students"].join(" - ") %> +<% content_for :title, [ @school.name, "Students" ].join(" - ") %>

Students for <%= @school.name %>

- +
@@ -25,8 +25,10 @@
<%= student.grade_level %> <%= student.gender %> - <%= link_to "Edit", edit_student_path(student) %> | - <%= button_to "Delete", student, method: :delete, data: { confirm: "Are you sure?" } %> +
+ <%= link_to "Edit", edit_student_path(student), class: "btn" %> + <%= button_to "Delete", student, method: :delete, data: { confirm: "Are you sure?" }, class: "btn btn--danger" %> +
<% end %>
From 05175eeafea4f2c36fc381c8940309423d59ed07 Mon Sep 17 00:00:00 2001 From: Sean Dickinson Date: Wed, 22 Apr 2026 20:26:53 -0400 Subject: [PATCH 5/9] feat: more styling --- app/assets/stylesheets/admin.css | 9 +++++++++ app/views/students/index.html.erb | 8 ++++---- 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/app/assets/stylesheets/admin.css b/app/assets/stylesheets/admin.css index 21045be..42b8561 100644 --- a/app/assets/stylesheets/admin.css +++ b/app/assets/stylesheets/admin.css @@ -1,4 +1,13 @@ .admin { + & .index-header { + display: flex; + justify-content: space-between; + align-items: center; + padding: 1rem; + & h1 { + margin: 0; + } + } & .index-table { width: 100%; border-collapse: collapse; diff --git a/app/views/students/index.html.erb b/app/views/students/index.html.erb index 0627eb9..08e985f 100644 --- a/app/views/students/index.html.erb +++ b/app/views/students/index.html.erb @@ -1,8 +1,10 @@

<%= notice %>

<% content_for :title, [ @school.name, "Students" ].join(" - ") %> - -

Students for <%= @school.name %>

+
+

Students for <%= @school.name %>

+ <%= link_to "New student", new_school_student_path(@school), class: "btn" %> +
@@ -32,5 +34,3 @@ <% end %>
- -<%= link_to "New student", new_school_student_path(@school) %> From 9b874c0448553df2c3011a7492e7f10f18af1c39 Mon Sep 17 00:00:00 2001 From: Sean Dickinson Date: Sat, 25 Apr 2026 19:35:11 -0400 Subject: [PATCH 6/9] fix: remove styling --- app/assets/stylesheets/admin.css | 27 -------------------------- app/assets/stylesheets/application.css | 8 -------- app/assets/stylesheets/buttons.css | 22 --------------------- app/assets/stylesheets/variables.css | 6 ------ 4 files changed, 63 deletions(-) delete mode 100644 app/assets/stylesheets/admin.css delete mode 100644 app/assets/stylesheets/buttons.css delete mode 100644 app/assets/stylesheets/variables.css diff --git a/app/assets/stylesheets/admin.css b/app/assets/stylesheets/admin.css deleted file mode 100644 index 42b8561..0000000 --- a/app/assets/stylesheets/admin.css +++ /dev/null @@ -1,27 +0,0 @@ -.admin { - & .index-header { - display: flex; - justify-content: space-between; - align-items: center; - padding: 1rem; - & h1 { - margin: 0; - } - } - & .index-table { - width: 100%; - border-collapse: collapse; - - & th, & td { - border: 1px solid gray; - padding: 0.5rem; - text-align: center; - } - - & td .actions { - display: flex; - justify-content: center; - gap: 0.25rem; - } - } -} \ No newline at end of file diff --git a/app/assets/stylesheets/application.css b/app/assets/stylesheets/application.css index 6f7d58c..fe93333 100644 --- a/app/assets/stylesheets/application.css +++ b/app/assets/stylesheets/application.css @@ -8,11 +8,3 @@ * * Consider organizing styles into separate files for maintainability. */ - -@import "./variables.css"; -@import "./admin.css"; -@import "./buttons.css"; - -*, ::before, ::after { - box-sizing: border-box; -} diff --git a/app/assets/stylesheets/buttons.css b/app/assets/stylesheets/buttons.css deleted file mode 100644 index e40cb10..0000000 --- a/app/assets/stylesheets/buttons.css +++ /dev/null @@ -1,22 +0,0 @@ -button, .btn, input[type="submit"] { - display: inline-block; - padding: .325rem .75rem; - margin-bottom: 0; - font-weight: normal; - font-family: Verdana, sans-serif; - font-size: var(--base-font-size); - text-align: center; - white-space: nowrap; - vertical-align: middle; - cursor: pointer; - background-image: none; - border: 1px solid transparent; - border-radius: .25rem; - background: var(--primary-color); - color: var(--white); - text-decoration: none; - - &.btn--danger { - background: var(--danger-color); - } -} \ No newline at end of file diff --git a/app/assets/stylesheets/variables.css b/app/assets/stylesheets/variables.css deleted file mode 100644 index f4f492f..0000000 --- a/app/assets/stylesheets/variables.css +++ /dev/null @@ -1,6 +0,0 @@ -:root { - --primary-color: #71beb7; - --white: #fff; - --danger-color: #e74c3c; - --base-font-size: 16px; -} \ No newline at end of file From 09f0094b0fa683927679787e80fe53fd4208dc05 Mon Sep 17 00:00:00 2001 From: Sean Dickinson Date: Sat, 25 Apr 2026 19:58:05 -0400 Subject: [PATCH 7/9] feat: forms --- app/views/layouts/application.html.erb | 2 +- app/views/passwords/edit.html.erb | 28 +++++++++++---------- app/views/passwords/new.html.erb | 26 +++++++++++--------- app/views/schools/_form.html.erb | 30 +++++++++++------------ app/views/schools/edit.html.erb | 25 ++++++++++--------- app/views/schools/new.html.erb | 23 ++++++++++------- app/views/sessions/new.html.erb | 32 ++++++++++++------------ app/views/students/_form.html.erb | 34 +++++++++----------------- app/views/students/edit.html.erb | 26 +++++++++++--------- app/views/students/index.html.erb | 17 +++++++------ app/views/students/new.html.erb | 24 +++++++++++------- 11 files changed, 140 insertions(+), 127 deletions(-) diff --git a/app/views/layouts/application.html.erb b/app/views/layouts/application.html.erb index 2b6d948..cb63b8d 100644 --- a/app/views/layouts/application.html.erb +++ b/app/views/layouts/application.html.erb @@ -24,7 +24,7 @@ -
+
<%= yield %>
diff --git a/app/views/passwords/edit.html.erb b/app/views/passwords/edit.html.erb index 51fe3d0..17a1e94 100644 --- a/app/views/passwords/edit.html.erb +++ b/app/views/passwords/edit.html.erb @@ -1,16 +1,18 @@ <%= tag.div(flash[:alert], style: "color:red") if flash[:alert] %> -
+
+
-
-

- Update your password -

- <%= form_with url: password_path(params[:token]), method: :put do |form| %> -
- <%= form.password_field :password, required: true, autocomplete: "new-password", placeholder: "Enter new password", maxlength: 72, class: "input w-full" %> - <%= form.password_field :password_confirmation, required: true, autocomplete: "new-password", placeholder: "Repeat new password", maxlength: 72, class: "input w-full" %> - <%= form.submit "Save", class: "btn btn-primary w-full" %> -
- <% end %> +
+

+ Update your password +

+ <%= form_with url: password_path(params[:token]), method: :put do |form| %> +
+ <%= form.password_field :password, required: true, autocomplete: "new-password", placeholder: "Enter new password", maxlength: 72, class: "input w-full" %> + <%= form.password_field :password_confirmation, required: true, autocomplete: "new-password", placeholder: "Repeat new password", maxlength: 72, class: "input w-full" %> + <%= form.submit "Save", class: "btn btn-primary w-full" %> +
+ <% end %> +
-
+
diff --git a/app/views/passwords/new.html.erb b/app/views/passwords/new.html.erb index a4737dd..b3cdbc5 100644 --- a/app/views/passwords/new.html.erb +++ b/app/views/passwords/new.html.erb @@ -1,16 +1,18 @@ <%= tag.div(flash[:alert], style: "color:red") if flash[:alert] %> -
+
+
-
-

- Forgot your password? -

- <%= form_with url: passwords_path do |form| %> -
- <%= form.email_field :email_address, required: true, autofocus: true, autocomplete: "username", placeholder: "Enter your email address", value: params[:email_address], class: "input w-full" %> -
- <%= form.submit "Email reset instructions", class: "btn btn-primary w-full" %> - <% end %> +
+

+ Forgot your password? +

+ <%= form_with url: passwords_path do |form| %> +
+ <%= form.email_field :email_address, required: true, autofocus: true, autocomplete: "username", placeholder: "Enter your email address", value: params[:email_address], class: "input w-full" %> +
+ <%= form.submit "Email reset instructions", class: "btn btn-primary w-full" %> + <% end %> +
-
+
diff --git a/app/views/schools/_form.html.erb b/app/views/schools/_form.html.erb index 5ce0e89..15b9200 100644 --- a/app/views/schools/_form.html.erb +++ b/app/views/schools/_form.html.erb @@ -1,22 +1,20 @@ <%= form_with(model: school) do |form| %> - <% if school.errors.any? %> -
-

<%= pluralize(school.errors.count, "error") %> prohibited this school from being saved:

+
+ <% if school.errors.any? %> +
+

<%= pluralize(school.errors.count, "error") %> prohibited this school from being saved:

-
    - <% school.errors.each do |error| %> -
  • <%= error.full_message %>
  • - <% end %> -
-
- <% end %> +
    + <% school.errors.each do |error| %> +
  • <%= error.full_message %>
  • + <% end %> +
+
+ <% end %> -
- <%= form.label :name, style: "display: block" %> - <%= form.text_field :name %> -
+ <%= form.label :name, class: "label" %> + <%= form.text_field :name, class: "input w-full" %> -
- <%= form.submit %> + <%= form.submit class: "btn btn-primary w-full" %>
<% end %> diff --git a/app/views/schools/edit.html.erb b/app/views/schools/edit.html.erb index cecb32c..1bbd16f 100644 --- a/app/views/schools/edit.html.erb +++ b/app/views/schools/edit.html.erb @@ -1,12 +1,15 @@ <% content_for :title, "Editing school" %> - -

Editing school

- -<%= render "form", school: @school %> - -
- -
- <%= link_to "Show this school", @school %> | - <%= link_to "Back to schools", schools_path %> -
+ +
+
+
+

Edit School

+ <%= render "form", school: @school %> +
+
+
diff --git a/app/views/schools/new.html.erb b/app/views/schools/new.html.erb index 6d47afe..2d8a0b1 100644 --- a/app/views/schools/new.html.erb +++ b/app/views/schools/new.html.erb @@ -1,11 +1,16 @@ <% content_for :title, "New school" %> -

New school

- -<%= render "form", school: @school %> - -
- -
- <%= link_to "Back to schools", schools_path %> -
+ +
+
+
+

New School

+ <%= render "form", school: @school %> +
+
+
\ No newline at end of file diff --git a/app/views/sessions/new.html.erb b/app/views/sessions/new.html.erb index fc563d9..eca0e13 100644 --- a/app/views/sessions/new.html.erb +++ b/app/views/sessions/new.html.erb @@ -1,22 +1,24 @@ <%= tag.div(flash[:alert], style: "color:red") if flash[:alert] %> <%= tag.div(flash[:notice], style: "color:green") if flash[:notice] %> -
+
+
-
-

- Login -

- <%= form_with url: session_path do |form| %> -
+
+

+ Login +

+ <%= form_with url: session_path do |form| %> +
- <%= form.email_field :email_address, required: true, autofocus: true, autocomplete: "username", placeholder: "Enter your email address", value: params[:email_address], class: "input w-full" %> - <%= form.password_field :password, required: true, autocomplete: "current-password", placeholder: "Enter your password", maxlength: 72, class: "input w-full" %> -
- <%= form.submit "Sign in", class: "btn btn-primary w-full" %> - <%= link_to "Forgot password?", new_password_path, class: "btn btn-link" %> + <%= form.email_field :email_address, required: true, autofocus: true, autocomplete: "username", placeholder: "Enter your email address", value: params[:email_address], class: "input w-full" %> + <%= form.password_field :password, required: true, autocomplete: "current-password", placeholder: "Enter your password", maxlength: 72, class: "input w-full" %> +
+ <%= form.submit "Sign in", class: "btn btn-primary w-full" %> + <%= link_to "Forgot password?", new_password_path, class: "btn btn-link" %> +
-
- <% end %> + <% end %> +
-
+
diff --git a/app/views/students/_form.html.erb b/app/views/students/_form.html.erb index a5c6bed..4c9654c 100644 --- a/app/views/students/_form.html.erb +++ b/app/views/students/_form.html.erb @@ -1,4 +1,5 @@ <%= form_with(model: [@school, student]) do |form| %> +
<% if student.errors.any? %>

<%= pluralize(student.errors.count, "error") %> prohibited this student from being saved:

@@ -11,32 +12,21 @@
<% end %> -
- <%= form.label :first_name, style: "display: block" %> - <%= form.text_field :first_name %> -
+ <%= form.label :first_name, class: "label" %> + <%= form.text_field :first_name, class: "input w-full" %> -
- <%= form.label :last_name, style: "display: block" %> - <%= form.text_field :last_name %> -
+ <%= form.label :last_name, class: "label" %> + <%= form.text_field :last_name, class: "input w-full" %> -
- <%= form.label :email, style: "display: block" %> - <%= form.text_field :email %> -
+ <%= form.label :email, class: "label" %> + <%= form.text_field :email, class: "input w-full" %> -
- <%= form.label :grade_level, style: "display: block" %> - <%= form.number_field :grade_level %> -
+ <%= form.label :grade_level, class: "label" %> + <%= form.number_field :grade_level, class: "input w-full" %> -
- <%= form.label :gender, style: "display: block" %> - <%= form.text_field :gender %> -
+ <%= form.label :gender, class: "label" %> + <%= form.text_field :gender, class: "input w-full" %> -
- <%= form.submit %> + <%= form.submit class: "btn btn-primary" %>
<% end %> diff --git a/app/views/students/edit.html.erb b/app/views/students/edit.html.erb index c1f5297..76317ac 100644 --- a/app/views/students/edit.html.erb +++ b/app/views/students/edit.html.erb @@ -1,12 +1,16 @@ <% content_for :title, "Editing student" %> - -

Editing student

- -<%= render "form", student: @student %> - -
- -
- <%= link_to "Show this student", @student %> | - <%= link_to "Back to students", school_students_path(@student.school_id) %> -
+ +
+
+
+

Editing Student

+ <%= render "form", student: @student %> +
+
+
diff --git a/app/views/students/index.html.erb b/app/views/students/index.html.erb index 08e985f..d38a5cf 100644 --- a/app/views/students/index.html.erb +++ b/app/views/students/index.html.erb @@ -1,12 +1,12 @@

<%= notice %>

<% content_for :title, [ @school.name, "Students" ].join(" - ") %> -
-

Students for <%= @school.name %>

- <%= link_to "New student", new_school_student_path(@school), class: "btn" %> +
+

Students for <%= @school.name %>

+ <%= link_to "New student", new_school_student_path(@school), class: "btn btn-primary" %>
- - +
+
@@ -27,10 +27,11 @@
<%= student.grade_level %> <%= student.gender %> -
- <%= link_to "Edit", edit_student_path(student), class: "btn" %> - <%= button_to "Delete", student, method: :delete, data: { confirm: "Are you sure?" }, class: "btn btn--danger" %> +
+ <%= link_to "Edit", edit_student_path(student), class: "btn btn-primary" %> + <%= button_to "Delete", student, method: :delete, data: { 'turbo-confirm': "Are you sure?" }, class: "btn btn-error" %>
<% end %>
+
diff --git a/app/views/students/new.html.erb b/app/views/students/new.html.erb index 18675c4..a250adf 100644 --- a/app/views/students/new.html.erb +++ b/app/views/students/new.html.erb @@ -1,11 +1,17 @@ <% content_for :title, "New student" %> -

New student

- -<%= render "form", student: @student %> - -
- -
- <%= link_to "Back to students", school_students_path(@student.school_id) %> -
+ +
+
+
+

New Student

+ <%= render "form", student: @student %> +
+
+
\ No newline at end of file From e02fd880352120325c7adba780c461d71a1e2c74 Mon Sep 17 00:00:00 2001 From: Sean Dickinson Date: Sun, 26 Apr 2026 13:21:50 -0400 Subject: [PATCH 8/9] fix: add breadcrumbs --- app/views/students/index.html.erb | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/app/views/students/index.html.erb b/app/views/students/index.html.erb index d38a5cf..3fa0122 100644 --- a/app/views/students/index.html.erb +++ b/app/views/students/index.html.erb @@ -1,6 +1,14 @@

<%= notice %>

<% content_for :title, [ @school.name, "Students" ].join(" - ") %> + + +

Students for <%= @school.name %>

<%= link_to "New student", new_school_student_path(@school), class: "btn btn-primary" %> From b788afa996f8bef4c4e2852d301968db004fd941 Mon Sep 17 00:00:00 2001 From: Sean Dickinson Date: Sun, 26 Apr 2026 13:26:35 -0400 Subject: [PATCH 9/9] fix: remove local ci seed test --- config/ci.rb | 1 - 1 file changed, 1 deletion(-) diff --git a/config/ci.rb b/config/ci.rb index 1712cc1..8b43ccf 100644 --- a/config/ci.rb +++ b/config/ci.rb @@ -9,7 +9,6 @@ step "Security: Importmap vulnerability audit", "bin/importmap audit" step "Security: Brakeman code analysis", "bin/brakeman --quiet --no-pager --exit-on-warn --exit-on-error" step "Tests: Rails", "bin/rails test" - step "Tests: Seeds", "env RAILS_ENV=test bin/rails db:seed:replant" # Optional: Run system tests # step "Tests: System", "bin/rails test:system"