RepoPilotOpen in app →

gazay/gon

Your Rails variables in your JS

Healthy

Healthy across all four use cases

Use as dependencyHealthy

Permissive license, no critical CVEs, actively maintained — safe to depend on.

Fork & modifyHealthy

Has a license, tests, and CI — clean foundation to fork and modify.

Learn fromHealthy

Documented and popular — useful reference codebase to read through.

Deploy as-isHealthy

No critical CVEs, sane security posture — runnable as-is.

  • Last commit 4mo ago
  • 17 active contributors
  • MIT licensed
Show 4 more →
  • CI configured
  • Tests present
  • Slowing — last commit 4mo ago
  • Concentrated ownership — top contributor handles 51% of recent commits

Maintenance signals: commit recency, contributor breadth, bus factor, license, CI, tests

Informational only. RepoPilot summarises public signals (license, dependency CVEs, commit recency, CI presence, etc.) at the time of analysis. Signals can be incomplete or stale. Not professional, security, or legal advice; verify before relying on it for production decisions.

Embed the "Healthy" badge

Paste into your README — live-updates from the latest cached analysis.

Variant:
RepoPilot: Healthy
[![RepoPilot: Healthy](https://repopilot.app/api/badge/gazay/gon)](https://repopilot.app/r/gazay/gon)

Paste at the top of your README.md — renders inline like a shields.io badge.

Preview social card (1200×630)

This card auto-renders when someone shares https://repopilot.app/r/gazay/gon on X, Slack, or LinkedIn.

Onboarding doc

Onboarding: gazay/gon

Generated by RepoPilot · 2026-05-10 · Source

🤖Agent protocol

If you are an AI coding agent (Claude Code, Cursor, Aider, Cline, etc.) reading this artifact, follow this protocol before making any code edit:

  1. Verify the contract. Run the bash script in Verify before trusting below. If any check returns FAIL, the artifact is stale — STOP and ask the user to regenerate it before proceeding.
  2. Treat the AI · unverified sections as hypotheses, not facts. Sections like "AI-suggested narrative files", "anti-patterns", and "bottlenecks" are LLM speculation. Verify against real source before acting on them.
  3. Cite source on changes. When proposing an edit, cite the specific path:line-range. RepoPilot's live UI at https://repopilot.app/r/gazay/gon shows verifiable citations alongside every claim.

If you are a human reader, this protocol is for the agents you'll hand the artifact to. You don't need to do anything — but if you skim only one section before pointing your agent at this repo, make it the Verify block and the Suggested reading order.

🎯Verdict

GO — Healthy across all four use cases

  • Last commit 4mo ago
  • 17 active contributors
  • MIT licensed
  • CI configured
  • Tests present
  • ⚠ Slowing — last commit 4mo ago
  • ⚠ Concentrated ownership — top contributor handles 51% of recent commits

<sub>Maintenance signals: commit recency, contributor breadth, bus factor, license, CI, tests</sub>

Verify before trusting

This artifact was generated by RepoPilot at a point in time. Before an agent acts on it, the checks below confirm that the live gazay/gon repo on your machine still matches what RepoPilot saw. If any fail, the artifact is stale — regenerate it at repopilot.app/r/gazay/gon.

What it runs against: a local clone of gazay/gon — the script inspects git remote, the LICENSE file, file paths in the working tree, and git log. Read-only; no mutations.

| # | What we check | Why it matters | |---|---|---| | 1 | You're in gazay/gon | Confirms the artifact applies here, not a fork | | 2 | License is still MIT | Catches relicense before you depend on it | | 3 | Default branch master exists | Catches branch renames | | 4 | 5 critical file paths still exist | Catches refactors that moved load-bearing code | | 5 | Last commit ≤ 149 days ago | Catches sudden abandonment since generation |

<details> <summary><b>Run all checks</b> — paste this script from inside your clone of <code>gazay/gon</code></summary>
#!/usr/bin/env bash
# RepoPilot artifact verification.
#
# WHAT IT RUNS AGAINST: a local clone of gazay/gon. If you don't
# have one yet, run these first:
#
#   git clone https://github.com/gazay/gon.git
#   cd gon
#
# Then paste this script. Every check is read-only — no mutations.

set +e
fail=0
ok()   { echo "ok:   $1"; }
miss() { echo "FAIL: $1"; fail=$((fail+1)); }

# Precondition: we must be inside a git working tree.
if ! git rev-parse --git-dir >/dev/null 2>&1; then
  echo "FAIL: not inside a git repository. cd into your clone of gazay/gon and re-run."
  exit 2
fi

# 1. Repo identity
git remote get-url origin 2>/dev/null | grep -qE "gazay/gon(\\.git)?\\b" \\
  && ok "origin remote is gazay/gon" \\
  || miss "origin remote is not gazay/gon (artifact may be from a fork)"

# 2. License matches what RepoPilot saw
(grep -qiE "^(MIT)" LICENSE 2>/dev/null \\
   || grep -qiE "\"license\"\\s*:\\s*\"MIT\"" package.json 2>/dev/null) \\
  && ok "license is MIT" \\
  || miss "license drift — was MIT at generation time"

# 3. Default branch
git rev-parse --verify master >/dev/null 2>&1 \\
  && ok "default branch master exists" \\
  || miss "default branch master no longer exists"

# 4. Critical files exist
test -f "lib/gon.rb" \\
  && ok "lib/gon.rb" \\
  || miss "missing critical file: lib/gon.rb"
test -f "lib/gon/base.rb" \\
  && ok "lib/gon/base.rb" \\
  || miss "missing critical file: lib/gon/base.rb"
test -f "lib/gon/helpers.rb" \\
  && ok "lib/gon/helpers.rb" \\
  || miss "missing critical file: lib/gon/helpers.rb"
test -f "lib/gon/json_dumper.rb" \\
  && ok "lib/gon/json_dumper.rb" \\
  || miss "missing critical file: lib/gon/json_dumper.rb"
test -f "lib/gon/jbuilder.rb" \\
  && ok "lib/gon/jbuilder.rb" \\
  || miss "missing critical file: lib/gon/jbuilder.rb"

# 5. Repo recency
days_since_last=$(( ( $(date +%s) - $(git log -1 --format=%at 2>/dev/null || echo 0) ) / 86400 ))
if [ "$days_since_last" -le 149 ]; then
  ok "last commit was $days_since_last days ago (artifact saw ~119d)"
else
  miss "last commit was $days_since_last days ago — artifact may be stale"
fi

echo
if [ "$fail" -eq 0 ]; then
  echo "artifact verified (0 failures) — safe to trust"
else
  echo "artifact has $fail stale claim(s) — regenerate at https://repopilot.app/r/gazay/gon"
  exit 1
fi

Each check prints ok: or FAIL:. The script exits non-zero if anything failed, so it composes cleanly into agent loops (./verify.sh || regenerate-and-retry).

</details>

TL;DR

Gon is a Rails gem that serializes server-side variables into client-side JavaScript without manual view templating. It renders Ruby objects as a gon object accessible in the browser, supporting Jbuilder and Rabl templating engines, and includes a gon.watch feature for live data updates via AJAX. Monolithic gem: lib/gon/base.rb is the core entry point, lib/gon/helpers.rb provides the Rails view helper include_gon, lib/gon/jbuilder/ and lib/gon/rabl.rb add template support, js/watch.js handles client-side polling, and spec/ mirrors the structure with integration tests for each adapter.

👥Who it's for

Rails developers building interactive web applications who need to pass initialization data (user IDs, configuration, feature flags) from controllers to JavaScript without embedding JS in views or writing manual JSON serialization code.

🌱Maturity & risk

This is a stable, production-ready gem with 52KB of Ruby code, comprehensive test coverage across 7 spec files, an active CI pipeline (.github/workflows/ci.yml), and a detailed wiki. However, the project appears to be in maintenance mode rather than active feature development—no recent commit dates visible in the file structure.

Single-maintainer project (gazay) with minimal dependency footprint visible. Risk factors: Rails version compatibility layer needed (lib/gon/compatibility/old_rails.rb), watch feature relies on JavaScript polling behavior that may not suit modern reactive frameworks, and the gem injects a global gon object into every request which could cause namespace collisions in large apps.

Active areas of work

No active development signals visible in file structure. The project includes Dependabot configuration (.github/dependabot.yml) suggesting automated dependency updates, but no specific issues, PRs, or recent changelog entries are evident from the provided data.

🚀Get running

git clone https://github.com/gazay/gon.git
cd gon
bundle install
bundle exec rspec

Daily commands: Add to Gemfile: gem 'gon'. In app/views/layouts/application.html.erb add: <%= Gon::Base.render_data %> or Rails 3: <%= include_gon %>. In controllers: gon.user_id = current_user.id. Access in JS: gon.user_id. For watch feature, include js/watch.js and call gon.watch().

🗺️Map of the codebase

  • lib/gon.rb — Main entry point and public API for the gem; defines the core Gon module and its class-level interface for storing and accessing variables.
  • lib/gon/base.rb — Core functionality for managing gon variables; implements the primary data storage and retrieval logic shared across all gon instances.
  • lib/gon/helpers.rb — Rails view helper that renders gon data as inline JavaScript; critical for translating Ruby objects into browser-accessible JSON.
  • lib/gon/json_dumper.rb — Handles serialization of Ruby objects to JSON with proper escaping and type handling; ensures safe transmission of data to the browser.
  • lib/gon/jbuilder.rb — Integration layer for Jbuilder templates; enables gon to accept complex JSON structures built with Jbuilder DSL.
  • lib/gon/rabl.rb — Integration layer for Rabl and Rabl-Rails templates; allows gon to leverage Rabl's declarative JSON generation.
  • lib/gon/watch.rb — Implements gon.watch functionality for live data updates via AJAX; enables real-time synchronization of Rails variables to JavaScript.

🛠️How to make changes

Add a new simple variable to be accessible in JavaScript

  1. In your Rails controller, assign a variable to the gon object (lib/gon/base.rb)
  2. In your view template, call the gon_init_tag helper to render the data as inline JavaScript (lib/gon/helpers.rb)
  3. Access the variable in your JavaScript file via the gon namespace (e.g., gon.variable_name) (js/watch.js)

Add support for a new templating engine (similar to Jbuilder/Rabl)

  1. Create a new integration file in lib/gon/my_template.rb following the pattern in lib/gon/jbuilder.rb (lib/gon/jbuilder.rb)
  2. Register your template type in the env_finder to detect and load it automatically (lib/gon/env_finder.rb)
  3. Implement template rendering and output merging logic to populate gon variables (lib/gon/base.rb)
  4. Add integration tests in spec/gon/my_template_spec.rb validating template parsing and variable access (spec/gon/jbuilder_spec.rb)

Enable live updates via gon.watch for a specific variable

  1. In your controller, call gon.watch(:variable_name) to mark it for polling (lib/gon/watch.rb)
  2. Create a dedicated action or endpoint that returns the updated variable value as JSON (lib/gon/request.rb)
  3. The client-side watch.js will automatically poll and update gon.variable_name when changes are detected (js/watch.js)

🔧Why these technologies

  • Ruby on Rails gem — Seamless integration with Rails controllers, views, and request lifecycle; provides thread-local storage per request
  • JSON serialization — Universal data format understood by JavaScript; avoids complex parsing and supports all standard types
  • Inline JavaScript (gon_init_tag) — Eliminates separate AJAX call for initial page load; reduces latency and ensures gon is available before user code runs
  • Jbuilder/Rabl integration — Reuses existing view templates for JSON generation; developers already familiar with these DSLs avoid duplication
  • AJAX polling (gon.watch) — Lightweight real-time updates without WebSocket complexity; suitable for low-frequency variable changes

⚖️Trade-offs already made

  • Inline JavaScript in HTML vs. separate API endpoint

    • Why: Inline approach is simpler and faster for initial page load; avoids race conditions where JS tries to access gon before it loads
    • Consequence: Larger HTML payload and slightly slower page rendering; cannot update gon after page load without separate endpoint (gon.watch)
  • Thread-local storage (current.rb) vs. instance variables on controller/view

    • Why: Thread-local avoids passing gon through method signatures; works across helpers, partials, and nested calls transparently
    • Consequence: Less explicit data flow; harder to debug in multi-threaded environments; requires cleanup to avoid memory leaks in thread pools
  • AJAX polling (gon.watch) vs. WebSockets

    • Why: Polling is simpler, requires no server upgrade, works with older browsers, reduces infrastructure complexity
    • Consequence: Higher latency (configurable poll interval); higher server load for frequent updates; not suitable for real-time chat/notifications
  • String escaping (escaper.rb) vs. HTML entity encoding

    • Why: JavaScript string escaping prevents XSS when data is embedded in <script> tags; more efficient than HTML entities for this context
    • Consequence: Requires careful escaping rules; potential vulnerability if rules are incomplete or bypassed by special characters

🚫Non-goals (don't propose these)

  • Does not handle real-time bidirectional communication (use WebSockets gem for that)
  • Does not provide authentication/authorization (gon exposes all assigned variables to browser; secure data at controller level)
  • Does not support client-to-server data binding (gon is read-only from JavaScript; use Rails form helpers or AJAX for mutations)
  • Does not work outside Rails (see gon-sinatra for Sinatra support)
  • Does not handle circular references or deeply nested objects (rely on Jbuilder/Rabl for complex transformations)

🪤Traps & gotchas

1. Thread safety: Gon uses thread-local storage (lib/gon/current.rb); concurrent request handling in some app servers may cause leakage—ensure per-request isolation. 2. Jbuilder/Rabl context: When using gon.jbuilder_template = 'path', the template needs controller context (via instance_variable_get); missing instance variables will silently fail. 3. Watch polling interval: gon.watch() defaults to periodic polling without exponential backoff; high-traffic apps may experience excessive AJAX calls—no built-in rate limiting. 4. Escaping collision: Variables escaped by lib/gon/escaper.rb using Rack::Utils.escape_html may double-escape if the view also escapes; test carefully. 5. Rails version sniffing: lib/gon/compatibility/old_rails.rb handles Rails 2.x compatibility but the file structure suggests this is legacy support—not tested in modern CI.

🏗️Architecture

💡Concepts to learn

  • Thread-local request storage — Gon uses thread-local variables (in lib/gon/current.rb) to isolate state per HTTP request in multi-threaded Rails servers; understanding this prevents data leakage between concurrent requests
  • HTML entity escaping for XSS prevention — The lib/gon/escaper.rb module escapes user-supplied data before embedding in HTML to prevent JavaScript injection attacks; critical for security when passing untrusted variables
  • Railties initialization hooks — Gon registers itself with Rails' initialization system (visible in lib/gon.rb require chain) to inject helpers into ActionView; understanding Railties is needed to debug or extend initialization
  • Client polling / long pollingjs/watch.js implements polling to refresh gon variables via repeated AJAX calls; this pattern is simpler than WebSockets but less efficient for high-frequency updates
  • View context introspection — Gon's Jbuilder and Rabl adapters use instance_variable_get to access controller instance variables within template evaluation; this reflection pattern is powerful but can mask errors
  • Rack utility functions — Gon relies on Rack::Utils.escape_html for HTML escaping; understanding Rack's built-in utilities prevents reinventing security functions
  • Response object introspectionlib/gon/env_finder.rb inspects the Rails request/response cycle to determine output format and rendering context; this is non-obvious Rails internals knowledge
  • gazay/gon-sinatra — Official port of Gon for Sinatra applications; same variable-passing pattern but without Rails helpers
  • rails/jbuilder — Upstream templating library integrated into Gon; understanding Jbuilder's DSL is essential for gon.jbuilder_template feature
  • nesquena/rabl — Upstream templating library with native Gon support; the lib/gon/rabl.rb adapter depends on this gem's API
  • brooklynDev/NGon — .NET MVC port of Gon; demonstrates the same server-to-client variable serialization pattern in a different ecosystem
  • khusnetdinov/phoenix_gon — Elixir Phoenix port of Gon; shows how the concept adapts to functional web frameworks

🪄PR ideas

To work on one of these in Claude Code or Cursor, paste: Implement the "<title>" PR idea from CLAUDE.md, working through the checklist as the task list.

Add comprehensive test coverage for lib/gon/escaper.rb

The escaper module is critical for security (preventing XSS attacks when passing Rails variables to JS), but there's no dedicated spec file for it. Currently escaping logic is likely tested indirectly through basic_spec.rb. Adding explicit tests for edge cases (special characters, unicode, nested structures, malicious payloads) would improve maintainability and catch regressions.

  • [ ] Create spec/gon/escaper_spec.rb with tests for HTML/JS escaping edge cases
  • [ ] Add tests for unicode and multi-byte character handling
  • [ ] Add tests for nested object/array escaping scenarios
  • [ ] Add security-focused tests for common XSS attack vectors
  • [ ] Verify all escaper methods in lib/gon/escaper.rb have corresponding tests

Add integration tests for lib/gon/env_finder.rb environment detection

The env_finder.rb module handles Rails environment detection (development, test, production), which is critical for watch mode and compilation behavior. There's no dedicated spec file for it. This should have explicit tests covering different Rails environment configurations and edge cases.

  • [ ] Create spec/gon/env_finder_spec.rb
  • [ ] Add tests for each Rails environment (development, test, production, staging)
  • [ ] Add tests for custom environment detection logic
  • [ ] Add tests for the interaction between env_finder and lib/gon/watch.rb
  • [ ] Test behavior when Rails environment is not properly initialized

Add tests for lib/gon/request.rb request isolation and thread safety

The request.rb module manages per-request gon data storage, and there's already a thread_spec.rb but it's limited. Given the complexity of request isolation in Rails (especially with multiple threads/fibers), add comprehensive tests for request-scoped data isolation, middleware interactions, and concurrent request handling.

  • [ ] Expand spec/gon/thread_spec.rb with fiber-based concurrency tests (for Rails 7.0+)
  • [ ] Add tests for request data isolation between concurrent requests
  • [ ] Add tests for request lifecycle (creation, access, cleanup)
  • [ ] Add tests for interaction with lib/gon/request.rb and middleware stack
  • [ ] Test behavior when gon data is accessed outside request context

🌿Good first issues

  • Add TypeScript type definitions for the gon object (e.g., gon.d.ts) so TypeScript projects using this gem can get IDE autocomplete and type safety. Create ts/gon.d.ts with JSDoc-style type declarations.
  • Write integration test for Rabl-Rails adapter in spec/gon/rabl_spec.rb—the test file exists but only covers Rabl 0.11+; add spec for the sample_rabl_rails.rabl template in spec/test_data/ to verify compatibility.
  • Document the thread-local storage behavior and request isolation guarantees in README.md with a 'Gotchas' section, since lib/gon/current.rb is not obvious and the watch feature's polling interval is not configurable per the current codebase.

Top contributors

Click to expand

📝Recent commits

Click to expand
  • 75dc0dc — v7.0.0 (willnet)
  • a448271 — Merge pull request #301 from willnet/remove-duplicate-dependency (willnet)
  • a18e93f — Merge pull request #300 from willnet/add-dependabot (willnet)
  • 007ed34 — Resolve duplicate dependency gem version constraints (willnet)
  • a9b43a8 — Merge pull request #299 from willnet/latest-actions-checkout (willnet)
  • 0bad075 — Add dependabot.yml to automatically update GitHub Actions (willnet)
  • 6cebf80 — Update actions/chckout to the latest version (willnet)
  • 22c0b51 — Merge pull request #296 from krororo/replace-current-attributes (willnet)
  • 9c13f62 — Add test for Rails 5.1 without request_store dependency (krororo)
  • a7a1da0 — Merge pull request #297 from willnet/add-ruby-4-0-to-ci (willnet)

🔒Security observations

  • High · Potential XSS Vulnerability in JavaScript Variable Injection — lib/gon/escaper.rb, lib/gon/json_dumper.rb, lib/gon/helpers.rb. The gon gem passes Rails variables to JavaScript without explicit mention of XSS prevention mechanisms in the codebase. The gem's core purpose is to expose Rails data to JS, which requires careful escaping. The presence of lib/gon/escaper.rb suggests awareness, but the actual implementation and consistency of escaping across all data types needs verification. User-controlled data passed through gon could be injected into JS context. Fix: 1. Verify that all data serialization paths use the escaper module consistently. 2. Ensure JSON serialization properly escapes special characters. 3. Add Content Security Policy (CSP) headers to mitigate XSS impact. 4. Document security best practices for users of the gem. 5. Add automated security tests for XSS payloads.
  • High · No Input Validation for Data Types — lib/gon/base.rb, lib/gon/global.rb, lib/gon/json_dumper.rb. The gem accepts arbitrary Ruby data structures from Rails controllers and serializes them to JavaScript. Without strict type validation and sanitization, malicious or unexpected data structures could be passed through, potentially leading to prototype pollution or other JS-based attacks when the data is consumed by JavaScript code. Fix: 1. Implement input validation to restrict accepted data types. 2. Document which data types are safe to expose via gon. 3. Consider implementing a whitelist of allowed keys/properties. 4. Add warnings in documentation about exposing sensitive data.
  • Medium · Potential Data Exposure Through Global Variables — lib/gon/global.rb, lib/gon/current.rb. The gem uses global variables (lib/gon/global.rb) to store data that gets exposed to the frontend. Global variables can accidentally leak sensitive information across requests if not properly isolated per-request, especially in multi-threaded environments or when the gem interacts with shared state. Fix: 1. Verify request isolation is properly implemented using lib/gon/current.rb. 2. Ensure thread-local storage is used correctly to prevent data leakage between concurrent requests. 3. Add integration tests for multi-threaded environments. 4. Document potential gotchas with global state management.
  • Medium · Dependency Management and Outdated Gems — Gemfile, gon.gemspec. No dependency file content was provided for analysis. The gem likely depends on JSON serialization libraries and Rails, which could contain vulnerabilities. Regular updates and vulnerability scanning are critical. Fix: 1. Run 'bundle audit' regularly to check for vulnerable dependencies. 2. Keep Ruby and Rails dependencies up to date. 3. Implement automated dependency vulnerability scanning in CI/CD pipeline (already visible in .github/workflows/ci.yml). 4. Pin dependency versions carefully to avoid breaking changes.
  • Medium · Missing Security Headers Configuration — lib/gon/helpers.rb. The gem exposes data in <script> tags within HTML. Without proper security headers (CSP, X-Content-Type-Options, X-Frame-Options), the application is more vulnerable to script injection attacks. Fix: 1. Add documentation on recommended security headers for apps using gon. 2. Provide middleware or configuration helpers to set appropriate CSP headers. 3. Document inline script security implications. 4. Recommend using nonce-based CSP for dynamic script tags.
  • Low · No Explicit Sensitive Data Warning — README.md, lib/gon/helpers.rb. The gem allows passing any Rails variable to JavaScript, including potentially sensitive data like authentication tokens, secrets, or private user information. There's no built-in mechanism to prevent developers from accidentally exposing sensitive data. Fix: 1. Add prominent warnings in README about not exposing sensitive data. 2. Create a security guide document. 3. Consider implementing optional validation to warn about common sensitive variable names. 4. Document best practices for what data is safe to expose to the frontend.
  • Low · Outdated CoffeeScript Usage — coffee/watch.coffee. The codebase includes CoffeeScript (coffee/watch.coffee) which is less commonly maintained. The JavaScript equivalent (js/watch.js) exists, but inconsistent language usage could lead to maintenance issues and potential for bugs. Fix: undefined

LLM-derived; treat as a starting point, not a security audit.


Generated by RepoPilot. Verdict based on maintenance signals — see the live page for receipts. Re-run on a new commit to refresh.

Healthy signals · gazay/gon — RepoPilot