Communication and Engagement - FreeUKGen/MyopicVicar GitHub Wiki
This domain covers how the public and logged-in users get in touch with the site, and how coordinators respond. It's five resources that look similar on the surface (all have "submit a form, coordinator reviews it" energy) but split into two real groups:
- Threaded, coordinator-routed submissions: Contact-System, Feedback-System, Message-System — these three share one reply/threading mechanism and a lot of copy-pasted behavior.
- Write-once lead capture: Donate-Cta-Feedback, Reminder-To-Donate — simple forms, no reply workflow, no archive/keep state.
- Contact-System — the public "Contact Us" form, with a full submission-to-reply flowchart
-
Feedback-System — general site feedback / bug reports,
Contact's structural twin - Message-System — the shared reply/thread substrate behind Contact and Feedback, plus internal coordinator messaging
- Donate-Cta-Feedback — donate call-to-action feedback (write-once, no reply workflow)
- Reminder-To-Donate — "remind me later" lead capture (write-once, no reply workflow)
flowchart TD
A[Public visitor] --> C[Contact: contacts#create]
B[Logged-in user] --> F[Feedback: feedbacks#create]
C --> C1[Routed by contact_type / role]
F --> F1[Routed by feedback_type / role]
C1 --> U[UseridDetail coordinator lookup<br/>with fallback chain]
F1 --> U
U --> C2[UserMailer.contact_action_request]
U --> F2[UserMailer feedback equivalent]
C2 --> M[Coordinator replies via Message<br/>nature: 'contact' / 'feedback'<br/>source_*_id set]
F2 --> M
M --> M2[Message can itself be replied to<br/>source_message_id - self-referential thread]
D[Public visitor] --> DCF[DonateCtaFeedback: write-once,<br/>emails and stops, no Message thread]
R[Public visitor] --> RTD[ReminderToDonate: write-once,<br/>emails and stops, no Message thread]
DonateCtaFeedback and ReminderToDonate sit outside the main reply chain: they're standalone forms that just email someone and stop. No Message thread, no archive/keep, no coordinator routing table.
-
The 12-level nested cascade.
archive,restore,update_keep, andupdate_unkeeponContact,Feedback, andMessageare all implemented as an identical, manually-unrolled 12-level-deepeachblock walking reply-of-reply-of-reply chains (Contact.message_replies(id).each do |r1| ... Contact.message_replies(r1.id).each do |r2| ...twelve levels deep). It's clearly meant to recurse through an arbitrarily deep thread but is hardcoded to exactly 12 levels — a reply thread deeper than that won't be fully archived/restored/kept. Copy-pasted across all three models rather than shared. A real recursive method (or a sharedThreaded/Archivableconcern) would fix this properly and is a good first refactor if you're looking for one. -
Button-label-driven control flow.
MessagesController#createdispatches on the literal text of the submit button (params[:commit]). Renaming a button in a view silently breaks its handler. -
String-parsed recipient identity.
Message#extract_coordinators/extract_othersparse structured data back out of a human-readable label string rather than carrying id and label separately. -
Session-driven redirects. Several
return_after_*methods across these controllers branch on session state (session[:message_base],session[:archived_contacts]) rather than request params, which can cause navigation to land somewhere unexpected if the session is stale. -
Naming/param mismatches:
DonateCtaFeedbackControllerusesparams.require(:feedback);ReminderToDonateController#indexsets@feedbacks. Neither is a bug per se, but both are traps if you go looking for the "obviously right" variable/param name.