Skip to content

HOLD: Add admin CRUD for forms (wait for the other forms pr to see if needed)#1366

Draft
maebeale wants to merge 13 commits intomaebeale/shared-form-builderfrom
maebeale/admin-forms-crud
Draft

HOLD: Add admin CRUD for forms (wait for the other forms pr to see if needed)#1366
maebeale wants to merge 13 commits intomaebeale/shared-form-builderfrom
maebeale/admin-forms-crud

Conversation

@maebeale
Copy link
Collaborator

@maebeale maebeale commented Mar 8, 2026

Summary

  • Adds full admin CRUD for Forms (index, show, new, edit, destroy) with admin-only authorization
  • New form creation uses an interstitial page to pick a builder type (short registration, extended registration, scholarship, or blank generic), then redirects to the edit page for customization
  • Edit page supports changing form title, editing question labels per-form, toggling required/status, adding/removing fields via cocoon, and cloning questions from other forms via a searchable Turbo Frame question library picker
  • Adds Forms card to admin home page, :forms theme color, and request + policy specs

Test plan

  • Visit /forms as admin — see index listing all forms
  • Click "New Form" — see builder interstitial with 4 options
  • Select each builder type — form created, redirected to edit with correct template fields
  • On edit: change form name, save — verify title updated (especially check event registration form dropdown)
  • On edit: change a question label, save — verify label changed on just this form
  • On edit: remove a field, save — verify field deleted
  • On edit: add blank field, fill in details, save — verify new field added
  • On edit: use question library picker to add questions from other forms — verify fields cloned
  • Visit show page — verify fields display grouped by section with linked events
  • Non-admin user cannot access any forms routes
  • Run bundle exec rspec spec/requests/forms_spec.rb spec/policies/form_policy_spec.rb

🤖 Generated with Claude Code

maebeale and others added 13 commits March 1, 2026 14:49
…ion forms

- Add confirm email field with server-side match validation
- Group email, confirm email, and email type in one row
- Label as "Email" on short forms, "Primary Email" when secondary exists
- Add address type (Home/Work) on same row as street address
- Add consent and training interest questions (appear on all forms)
- Skip storing confirmation field value in user form submissions

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Short, Extended, and Scholarship form builders now inherit from a common
base class that provides shared helpers (add_header, add_field) and
reusable field sections (basic contact, scholarship, consent). This
eliminates duplication and ensures changes to shared fields propagate
to all form types.

Also fixes three bugs:
- Email confirmation key mismatch (primary_email_confirmation → confirm_email)
  so validation now works for extended forms
- workshop_settings → workshop_environments so professional tags get assigned
- confirm_email responses no longer stored redundantly in PersonForm

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
)

Previously the form submission icon on the manage registrations and
event registrations index pages only checked the single form tagged
as "registration" role. If an event's registration form was swapped,
people who submitted the old form lost their green icon. Now both
pages check across all forms linked to the event via event_forms.

Also fixes N+1 queries on the event registrations index by batch-
loading form submissions upfront.

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
* Fix delete registration button and return_to routing

The delete button on the registration edit form wasn't working because
data-turbo="false" on the parent form disabled Turbo for the delete link
which relies on turbo_method: :delete. Added turbo: true override.

All CRUD actions (create, update, delete) now respect return_to param so
admins are redirected back to the page they came from — manage registrants
or registrations index — instead of always landing on the index or ticket.

Also adds event registration seed data with various scenarios and a system
spec for the delete button.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* Fix request specs for return_to routing changes

Update tests to pass return_to param explicitly since create no longer
infers destination from event_id presence.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
* Use rhino_description for registration confirmation email details

The email was showing the plain-text description column (lorem ipsum
placeholder) instead of the actual event details from rhino_description,
which is the same content used in calendar events.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* Add EventMailer spec covering confirmation and cancellation emails

Tests that rhino_description content appears in the confirmation email
body, and verifies basic rendering for both mailer actions.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* Remove cancelled email tests from EventMailer spec

Cancellation email doesn't reference description, so no test needed.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* Fix rubocop empty line at block body end

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
* Add direct organization associations to event registrations

Registrations now have their own many-to-many relationship with
organizations via a join table, decoupled from the registrant's
affiliations. Active orgs are snapshotted at registration time,
and admins can add/remove orgs from the registration edit page
using toggleable chips and a Stimulus controller.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* Register people with multiple affiliations in seeds

Ensures Mariana Johnson (3 affiliations), Samuel Smith, Lisa
Williamson, Kim Davidson, and Sarah Davis (2 each) are registered
to events so their organizations get snapshotted via the
after_create callback.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
A RecordNotUnique error (duplicate action_text_rich_texts entry) was
surfacing as a 500 in production during workshop updates, likely from
a race condition (e.g. double form submission). The transaction rescue
blocks only caught RecordInvalid and RecordNotSaved, letting the
uniqueness violation propagate uncaught.

Added RecordNotUnique to rescue clauses in all 10 controllers that
save models with has_rich_text fields, so duplicate-key errors roll
back gracefully and re-render the form instead of crashing.

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
* Prevent deletion of users with associated records

Users who have created reports, workshop logs, resources, workshops,
stories, or ideas can no longer be deleted. The delete button is hidden
in the UI and the controller rescues InvalidForeignKey as a safety net.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* Fix report factory in deletable? test to include workshop

The report factory doesn't include a workshop association, but the
Report model requires one. Pass it explicitly in the test.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
* Remove dead assets/form partial reference from workshop edit

The partial was removed in a previous revert but the render call
was left behind, causing a MissingTemplate error on ?admin=true.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* Fix workshop form admin fields layout and conditional author name

Stack admin fields vertically instead of horizontally to prevent
label truncation and field overlap. Only show Author's name field
when the value is present and ?admin=true.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* Move workshop created date under Workshop Idea parent

Relocate the date field from the bottom of the form into the
admin grid column alongside Workshop Idea parent. Rename label
from "Date created" to "Workshop created" with consistent sizing.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* Remove full_name fill from create workshop test

The Author's name field is now conditionally shown only when
the value is present and ?admin=true, so it won't appear on
the new workshop form.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
* Allow workshop logs without workshop_id when external title present

Workshop logs can now be submitted with an external_workshop_title
instead of requiring a workshop_id. This supports users logging
workshops that don't exist in the system.

- Make workshop association optional on Report
- Add migration to remove NOT NULL constraint on reports.workshop_id
- Add custom validation requiring either workshop_id or external_workshop_title

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* Show external workshop title on workshop log show page

Display external_workshop_title in heading and Workshop field when
no workshop record is associated. When both are present, show the
external title inline next to the workshop chip.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* Add tests for external workshop title on workshop logs

- Model spec: validate workshop_id or external_workshop_title required
- Request spec: create workshop log with external title and no workshop
- System spec: display external title in heading and Workshop field

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* Fix CI failures in workshop log tests

- Check workshop.present? instead of workshop_id.present? so
  validation works with both build (in-memory) and create (persisted)
- Use specific Capybara selector to avoid ambiguous div matches

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
…1297)

* Use OuterJoin in RichTextSearchable so records without rich text still appear

InnerJoin was filtering out records that had no action_text_rich_texts
entry, causing them to disappear from search results entirely.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* Update SearchCop configs to search rich text content

- Resource: enable rich text search (was commented out), remove native body
- Story: add grouped default attributes so rich text + title both searched
- Tutorial: add rich text search, split multi-word search terms for
  independent matching, search both native body and rhino_body
- WorkshopVariation: add RichTextSearchable, replace native body search
  with rich text search, use rhino_body in description method

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* Use rhino rich text fields instead of native columns in decorators

- StoryDecorator: use rhino_body.to_plain_text in detail
- TutorialDecorator: use rhino_body in display_text and detail
- ResourceDecorator: use rhino_body in detail, truncated_text,
  flex_text, display_text, and html
- WorkshopDecorator: prepend rhino_ prefix in spanish_field_values,
  use rhino fields in html_content and html_objective

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* Use rhino rich text fields instead of native columns in views

- Story shares: use rhino_body.to_plain_text instead of strip_tags(body)
- Tutorial partial: display rhino_body instead of body.html_safe
- Workshop variations index: use rhino_body.to_plain_text instead of body

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* Update tutorial specs to use rhino_body for test data

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* Fix tutorial view spec to include rhino_body for rendered output

The show view now renders rhino_body instead of native body, so the
test data needs to populate the rich text field.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
* Restrict person edit/update to admin only

- Remove owner? from edit? and update? in PersonPolicy
- Hide "My profile" menu link unless admin manage
- Update policy spec to expect owner cannot edit

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* Add admin-only styling and permission gates to person views

- Gate People and Edit links with policy checks and admin-only styling
- Show email with admin-only styling when profile_show_email is off
- Remove comments section from person show (keep in edit form only)
- Add admin-only styling to comments section on person edit form

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* Add request specs for person show authorization and profile flags

- Test edit/update blocked for owners, allowed for admin
- Test show page gated content (Edit link, email, Submitted content, Comments)
- Test all 16 profile flags for visibility on own and admin-viewed profiles
- Test email admin-only styling when profile_show_email is off

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* Fix navbar avatar system test for admin-only person edit

The test was using a regular user to edit a person record, which is
now restricted to admins only.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Admins can now manage forms through a dedicated UI:
- Index lists all forms with field counts, linked events, and type badges
- New form flow: interstitial page to select builder type (short/extended
  registration, scholarship, or blank generic), then redirect to edit
- Edit page supports inline editing of form name and question labels,
  toggling required/status, adding/removing fields via cocoon, and
  cloning questions from other forms via a searchable Turbo Frame picker
- Show page displays fields grouped by section with linked events

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@maebeale maebeale changed the title Add admin CRUD for forms HOLD: Add admin CRUD for forms (wait for the other forms pr to see if needed) Mar 10, 2026
@maebeale maebeale force-pushed the maebeale/shared-form-builder branch from 385b205 to bc71308 Compare March 11, 2026 13:01
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant