Public pretty-URL endpoint for standalone forms + form-filterable submissions index - #2237
Merged
Conversation
Collaborator
Author
|
@jmilljr24 they need public forms for collaboration agreement (for reups outside events), annual survey. and could also use them for the immediate need of post-event survey, day-1-survey, day-2-survey until we get those wired up into event edit selections. any concerns w approach taken in this pr w the slug and published boolean? |
maebeale
marked this pull request as ready for review
August 17, 2026 14:56
jmilljr24
approved these changes
Aug 17, 2026
…c forms Foundation for a public pretty-URL endpoint for standalone (event-less) forms. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…missions index Publish an event-less Form at /f/:slug for account-free public filling; view those submissions via the form-filterable /form_submissions index. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…ons in index Adds a dev seed (two published event-less forms with submissions/answers) and marks event-less public submissions with a 'Public form' pill in the index so a blank Event column reads as intentional, not missing. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…nce onto FormSubmission; forms UX polish - Bug: View link inside the submissions results Turbo frame navigated the frame to a frameless show page (Oopsie); break it out with turbo_frame _top. - Move persist_answer + hardened file-upload handling onto FormSubmission; registration, public forms, and bulk payment now share it (mixin removed). - Forms index: event-connected unpublished forms read 'Event form' not 'Not published'; delete link removed; submissions count links back with a Forms eyebrow anchored to the row. - Editor: clarify publish only controls the public link; swap Save/Delete placement and show a reason when a form can't be deleted. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…rt, forged upload) Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Mirror event registration: new form_submission_confirmation(_fyi) notification kinds, NotificationMailer methods + views, job dispatch, and previews. Sent from PublicFormSubmission to the submitter and the AWBW team. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
A form can be both; render a chip for each that applies (rename column to Availability) rather than one-or-the-other. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Adopt SearchFormHelper field/label classes + shared/_search_clear (introduced on main in #2220) so the form filter matches every other index. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
maebeale
force-pushed
the
maebeale/public-form-endpoint
branch
from
August 18, 2026 11:43
d48f616 to
2a40dec
Compare
jmilljr24
reviewed
Aug 18, 2026
| authorize! @form, to: :public_show? | ||
|
|
||
| # Honeypot — a bot that fills the hidden field is silently bounced. | ||
| if params.dig(:public_registration, :website_url).present? |
Collaborator
There was a problem hiding this comment.
Great idea! (and perfect comment).
Any other key we could use instead of website_url? That's a real value we use in other places and could be confusing or conflict at some point.
…ssions Public forms were the only submission path that skipped OtherResponses::CaptureFromSubmission, so a sector question answered "Other: …" never reached the curation queue — it only lived in the form answer, invisible to promotion. The submissions View link carried person_id but not form_id, so arriving from the forms index and clicking back landed on that person's submissions rather than the form-filtered list you came from. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
parameterize strips "!!!" (or any input with no url-safe characters) down to "", which the format validation waves through as blank and the unique index then collides on for the second such form — surfacing to the admin as the baffling "Slug has already been taken". Keep the typed value intact so the format error fires instead, and the admin sees what they entered. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The View link told the detail page it came from the submissions index, but not where that index was itself reached from — so returning from a submission opened via Forms landed on the filtered index with the "← Forms" back link gone. Carry the origin forward on the link and hand it back on the way home. The filter form carries it too, so changing the filter doesn't strip it out of the frame's params and orphan the View links. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This branch adds a controller and a service, and both directory counts were already well behind the tree — the numbers are only useful if they're close. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
🤖 suggested review level: 5 Inspect 🔬 new public unauthenticated endpoint that find-or-creates People + FormSubmissions and sends email; consolidates the answer-persistence used by event registration onto the model
What
Format a public pretty URL (/f/:slug) — anyone can fill it out, no account./form_submissionsindex, now filterable by form and lazy-loaded.Public form endpoint
Formgainsslug(admin-set, URL-normalized, unique) +published;publicly_fillable?(standalone + published + slug) gates the route andFormPolicy#public_show?.PublicFormsController(show/create/thank_you, unauthenticated) with honeypot + required-field validation; reuses the public-registration field partials.PublicFormSubmissionservice: find-or-creates aPersonfrom the form's name/email answers (email + last-name match reuses an existing person), records one-time consent, stores arole: "public"submission, captures "Other" answers, sends notifications."". Truly blank input becomesnilso the unique index tolerates the many forms without a slug; input thatparameterizestrips to nothing ("!!!") is left intact for the format validation to reject, rather than silently blanked into a later "has already been taken" collision.Emails
form_submission_confirmation(to submitter) +form_submission_confirmation_fyi(to admin), withNotificationMailermethods, html/text views, job dispatch, and previews — mirroring the event-registration confirmation/FYI pattern.Answer persistence (consolidation)
persist_answer+ the hardened file-upload path ontoFormSubmission#persist_answer. Event registration, public forms, and bulk payment share it; the interim mixin is gone.Submissions index
form_id, paginates, links from the forms index.turbo_frame: "_top") — previously it navigated the frame to a frameless show page and errored.form_id, so the trip back keeps the form filter instead of dropping to that person's submissions.origin, which the detail page hands back — so the ← Forms eyebrow survives the full Forms → submissions → detail → back round trip instead of vanishing on the return leg. The filter form carries it too, so changing the filter doesn't strip it from the frame's params.Forms index / editor polish
Dev seed
db/seeds/dev/public_forms.rb— two published event-less forms with submissions + answers, wired intodb:seed:dev. Idempotent.Open question
Follow-up
/f/:slugis always open, unlike the event endpoints behindensure_registerable; the honeypot is the only current defence.persist_answeronto the model gave the bulk-payment path a raise it couldn't produce before.BulkPayment#callrescues onlyRecordInvalid, so afile_uploadfield with a forged or stale signed id would 500 rather than re-render. Reachability is narrow today (the bulk-payment view renders no file input), hence a follow-up rather than an inline fix.Tests
public_formsrequest,PublicFormSubmissionservice (incl. notifications + "Other" capture),Formslug/publish + slug-rejection,FormSubmission#persist_answer,FormPolicy#public_show?,NotificationMailerform-submission emails, forms-index public-link column, submissions eyebrow + frame-escape + form-filter + origin round trip.