Published June 11, 2026
| Version v1.1.0
Software
Open
chain simple forms / surveys into longer runs using the power of R to generate pretty feedback and complex designs https://formr.org
Authors/Creators
- 1. Wilhelm Wundt Institute of Psychology, University of Leipzig
- 2. Georg Elias Müller Institute of Psychology, University of Goettingen
Description
Added
- Run-level custom R functions (
custom_r, settings → "R Functions" tab). Stored likecustom_css/custom_js, injected afterlibrary(formr)into every OpenCPU evaluation and knit context (showif, value, feedback,relative_to, branch conditions, external URLs, email bodies, overview scripts) via a singleeval(parse(text = …))statement, so syntax errors surface as clear runtime errors and Rmd chunks can't be broken by the injected code. Exposed through the v1 API (custom_rread/update) and run export/import. - Run-level secrets (settings → "R Secrets" tab). Encrypted at rest via Halite (
survey_run_secrets), available in R as.formr$secret_<name>, and injected only when that literal reference appears in the unit's R code or the run's custom R functions. The admin UI is write-only: a stored value is never sent back to the browser — it can only be replaced or deleted. Names are restricted to[A-Za-z0-9_]server- and client-side. Run export carries secret names only; import recreates them as empty placeholders to be re-entered. - Secret redaction in OpenCPU debug output, error notifications, result logs, and
opencpu.log. Secret values of 6+ characters are replaced with[SECRET REDACTED]. Best-effort by design: transformed occurrences (e.g. JSON-escaped non-ASCII) can evade a literal match, and the OpenCPU session itself still receives the plaintext — the deployment-level denypaths on/console//sourceremain the wire-level guard. - R syntax validation for custom R code ("Save & Test R Syntax"): runs
base::parse()on OpenCPU (parse only — nothing is executed) and reports errors inline, with a "Copy for LLM" export of code + error. - "Open in R Fiddle" links in the OpenCPU debugger. The R Markdown / R Code panels now link to an in-browser webR fiddle (default
https://fiddle.rforms.org/, configurable/disableable via$settings['r_fiddle_url']). The (secret-redacted) code travels in the URL fragment, which browsers never transmit to the fiddle host. - Optional
api_internal_urlsetting for R→formr API calls from OpenCPU. When set (e.g.http://formr_app/apion the shared Docker network),opencpu_prepare_api_accessinjects it as.formr$hostinstead of the publicapi_base_url(), soformr_api_*()calls skip DNS, TLS, and the reverse proxy (~30% faster per call in benchmarks). Empty (the default) keeps the previous behaviour. The internal hostname must resolve to a vhost that serves the API; the bearer token travels as plaintext HTTP on this URL, so only enable it on a trusted single-host Docker network.
Fixes
- Run settings page: the special-unit links (service message, reminder, overview script) redirect back to the right settings tab again.
site_url()appends a trailing slash to fragment-free URIs, so building the URL before converting:::to#produced…settings#service_message/— a fragment no tab matches. The:::→#conversion now happens before the URL is built (createRunUnitAction/deleteRunUnitAction). api_base_url()no longer appends/apiwhen a dedicatedapi_domain(different fromadmin_domain) is configured (#695). A dedicated API host serves the API at its root — its vhost rewrites/toroute=api/…— so the docs page, the account-page R snippets, and the OpenCPU bridge previously pointed clients at a doubledapi/api/…path. The/apisuffix remains for the admin-domain fallback.- Run settings page: the "Settings saved" response alert now appears in the tab whose form was saved, replacing the previous alert instead of stacking. It used to be inserted after
#app_heading— which lives in the manifest tab — so saving from any other tab gave no visible feedback. RunHelper::nextInRun()fatal on boolean:getCurrentUnitSession()returnsfalsewhen no active unit-session row exists; the guard now checks falsy (not just null) so the friendly "No unit session found" alert renders instead of a 500.SpreadsheetReaderquadratic import time on bloated.xlsxfiles:getHighestDataColumn()was called once per row inside both sheet-reading loops, scanning the entire cell index each time. Now computed once per sheet, bounded to the rightmost allowlisted column. Synthetic 1500×60 whitespace-bloated sheet: 161 s → 9 s; output digest unchanged.- Run export JSON was missing
conditionfromSkipForwardand several attributes fromExternal,Page, andSkipBackward.
Changes
- Run settings page layout homogenized to match the newer admin credential page: consistent
row/colgrid,h4.leadsection headings, equal-height markdown editors, empty-state hints for service messages/reminders/overview scripts, a clearer "Delete Reminder" button, and the Test Run link opens in a new tab. Removes the five duplicatedid="run_settings"form ids (the save handlers are class-based). survey_unit_sessions.result_logwidened to MEDIUMTEXT;truncate_result_log()caps writes at the same 16 MiB limit (byte-safe for UTF-8) in the unit-session and email-queue paths.
Schema
057_custom_r_path.sql—survey_runs.custom_r_path.058_result_log_mediumtext.sql—result_logTEXT → MEDIUMTEXT.059_create_run_secrets.sql—survey_run_secrets(unique per run+name, FK cascade on run delete).
Files
rubenarslan/formr.org-v1.1.0.zip
Files
(4.4 MB)
| Name | Size | Download all |
|---|---|---|
|
md5:e39aa6023769c14f97616f21df4922a9
|
4.4 MB | Preview Download |
Additional details
Related works
- Is supplement to
- Software: https://github.com/rubenarslan/formr.org/tree/v1.1.0 (URL)
Software
- Repository URL
- https://github.com/rubenarslan/formr.org