Skip to content

HOLD: Uniform public form lanes: /events/:id/forms/:role with standalone scholarship/CE/general#1599

Open
maebeale wants to merge 11 commits into
mainfrom
maebeale/scholarship-registration-url-params
Open

HOLD: Uniform public form lanes: /events/:id/forms/:role with standalone scholarship/CE/general#1599
maebeale wants to merge 11 commits into
mainfrom
maebeale/scholarship-registration-url-params

Conversation

@maebeale

@maebeale maebeale commented Jun 8, 2026

Copy link
Copy Markdown
Collaborator

What is the goal of this PR and why is this important?

  • Give every public event form a single, uniform, shareable URL: /events/:id/forms/<role>/new. The lane is visible in the path, so each entry point is unambiguous (clean analytics) and links are easy to share.
  • Let scholarship and CE forms be accessed directly, not only bundled into a registration, and add a general public form lane.

URL scheme

Lane URL Renders / does
registration /events/:id/forms/registration/new registration form → creates a registration
scholarship /events/:id/forms/scholarship/new registration + scholarship (primary scholarship link)
scholarship_questions /events/:id/forms/scholarship_questions/new?reg=SLUG scholarship questions only → attaches to an existing registration, sets scholarship_requested
ce_questions /events/:id/forms/ce_questions/new?reg=SLUG CE questions only → attaches to an existing registration, sets ce_credit_requested
general /events/:id/forms/general/new general form → recorded as a FormSubmission
bulk_payment /events/:id/forms/bulk_payment/new main's BulkPaymentsController (uniform URL, own controller)

How

  • One param'd route set (forms/:form_role new/create/show) → Events::PublicFormsController. A LANES config maps each lane to its form(s), heading, and behavior mode (:register / :addon / :submission).
  • :addon lanes (scholarship_questions, ce_questions) resolve the existing registration by slug (?reg=) or the signed-in person's active registration; no registration → redirect with a "register first" notice.
  • Bulk payment is mounted at the uniform forms/bulk_payment path but still routes to its own shipped controller — no change to that flow.
  • EventForm::ROLES gains general; route helpers are now new_event_form_path(event, role) / event_form_path(event, role); all call sites + the admin Form-actions menu updated.

Verification

  • ai/lint clean. Green: public_forms routing/system/request, bulk_payments, events, event_registrations, scholarships, event/event_form models, page_bg view spec, events_show.

🤖 Generated with Claude Code

@maebeale maebeale marked this pull request as ready for review June 8, 2026 15:31

def form_variant
VARIANTS.include?(params[:form_variant]) ? params[:form_variant] : "registration"
end

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🤖 From Claude: form_variant is whitelisted against VARIANTS and falls back to "registration", so an unknown variant in the URL degrades to the default flow rather than blowing up the path helpers below.

params[:scholarship_requested] != "false"
else
params[:scholarship_requested] == "true"
end

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🤖 From Claude: Scholarship default differs by variant: the scholarship_form flow opts in unless scholarship_requested=false, while other flows opt in only when explicitly =true. This preserves the existing query-param behavior for the registration flow.

Comment thread config/routes.rb
@@ -130,7 +130,15 @@
post :send_reminder
end
resource :registrations, only: %i[ create destroy ], module: :events, as: :registrant_registration

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🤖 From Claude: The registrant_registration resource stays separate from the three new public *_form resources — the routing spec asserts POST /events/:id/registrations still hits events/registrations#create and does not collide.

@maebeale maebeale force-pushed the maebeale/scholarship-registration-url-params branch from 77281d5 to 8690d67 Compare June 13, 2026 00:34
@maebeale maebeale changed the title Rename public_registration to public_forms with variant-aware routing Add role-based public form lanes (public_forms) with variant-aware routing Jun 13, 2026
Comment thread config/routes.rb Outdated
end
resource :registrations, only: %i[ create destroy ], module: :events, as: :registrant_registration
resource :public_registration, only: [ :new, :create, :show ], module: :events
resource :bulk_payment, only: [ :new, :create, :show ], module: :events

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🤖 From Claude: Kept main's dedicated bulk_payment resource (→ Events::BulkPaymentsController, the real multi-attendee flow) alongside the role loop. The loop also generates a bulk_payment_form lane through public_forms, but that's a registration-form-backed placeholder at a different path — the two coexist and the admin menu surfaces the real one.

@maebeale maebeale changed the title Add role-based public form lanes (public_forms) with variant-aware routing Uniform public form lanes: /events/:id/forms/:role with standalone scholarship/CE/general Jun 13, 2026
@maebeale maebeale force-pushed the maebeale/scholarship-registration-url-params branch from 8ed614d to 9217f36 Compare June 13, 2026 14:02
maebeale and others added 11 commits June 13, 2026 10:17
The single public_registration resource conflated three distinct
public-facing flows (registration, scholarship application, bulk
payment). Splitting it into registration_form/scholarship_form/
bulk_payment_form resources that share one PublicFormsController lets
each flow have its own URL while a form_variant default drives the
heading, paths, and scholarship behavior — making the variant explicit
in the URL instead of inferred from query params alone.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Add bulk_payment and ce_credit as event-form roles and drive the public
form endpoints, controller variant whitelist, and Event#*_form accessors
off EventForm::ROLES so the role list lives in exactly one place. Routes
and per-role scopes/accessors are now generated from ROLES, and the
controller's "form_variant" concept is renamed to "form_role" to match
the model's vocabulary. No behavior change to the existing registration
and scholarship flows.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
ce_credit is now a first-class EventForm role, so surface its preview
link alongside the other lanes and cover its heading/endpoint in the
system spec for parity with the registration/scholarship/bulk_payment
lanes.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The rebase onto main resolved a modify/delete on the old public
registration system spec; port main's scholarship-form-header test into
the public_forms spec so that coverage isn't lost. Rename the public
registration request spec to match the renamed Events::PublicForms
controller.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
… lanes

Collapse the per-role *_form resources into one uniform route set —
/events/:id/forms/:form_role/new — served by Events::PublicFormsController,
so every public form lane shares the same simplest URL. Bulk payment lives
under the same forms/ path but keeps its own BulkPaymentsController.

A LANES config drives each lane's presentation + behavior:
- registration: registration form
- scholarship: registration + scholarship combined (the primary scholarship link)
- scholarship_questions / ce_questions: standalone questions that attach to the
  person's existing registration (via ?reg=slug or their active registration),
  setting scholarship_requested / ce_credit_requested
- general: standalone form recorded as a FormSubmission

This gives scholarship (and CE) forms a direct entry point instead of only
riding on a registration, and adds a general public form lane. EventForm::ROLES
gains "general"; route helpers move to new_event_form_path(event, role).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Add request specs verifying the addon lane attaches answers to an
existing registration, sets scholarship_requested without creating a new
registration, redirects to the ticket, requires a registration to attach
to, and re-renders on validation errors.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The registration submission view was reachable through an events route
(/events/:id/forms/registration?reg=SLUG). Since the registration slug is
globally unique and already identifies its event, expose the view as a
clean top-level /submission/:slug route, parallel to the existing
/registration/:slug ticket. Drops the event-nested public_forms#show
route and the person_id fallback (every registration gets a slug on
create); admin "view submission" links now use submission_path(slug).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Only registration links were shared before the public-form routes moved,
so keep those old URLs working with redirects:
- /events/:id/public_registration?reg=SLUG -> /submission/SLUG
- /events/:id/public_registration/new      -> /events/:id/forms/registration/new (query preserved)
- /events/:id/public_registration (no slug) -> the registration form
A POST shim keeps any stale registration form able to submit. Scholarship
and bulk-payment legacy routes aren't needed (no such links went out).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
A test added on main (#1641) exercised the public form via the old
new_event_public_registration_path helper; update it to the new
new_event_form_path(event, "registration") after the rebase.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
CI scan_ruby failed on newly-published advisories CVE-2026-47240/47241/
47242 (Net::IMAP command injection / DoS) in net-imap 0.6.4. Conservative
bump to the patched 0.6.4.1.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The #1621 stripe-link tests came in via rebase still using the removed
multiple_choice_radio enum value, the old event_public_registration_path
helper, and the pre-move /bulk_payment location. Update them to
single_select_radio, event_form_path(event, "registration"), and the
/forms/bulk_payment path.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@maebeale maebeale force-pushed the maebeale/scholarship-registration-url-params branch from 8f7fd93 to 35165b7 Compare June 13, 2026 14:23
@maebeale maebeale changed the title Uniform public form lanes: /events/:id/forms/:role with standalone scholarship/CE/general HOLD: Uniform public form lanes: /events/:id/forms/:role with standalone scholarship/CE/general Jun 13, 2026
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