Open-source project
gazay/gon avatar
gazay/gon

gon: passing Rails variables to JavaScript without view hacks

Your Rails variables in your JS

3,105 stars185 forksRubyMIT

At a glance

What is it?
gon is a Ruby gem that writes server-side variables into a script tag so browser code can read them as a global object. It fits Rails apps that need request data in JavaScript, and it is a poor fit when you want a typed API contract.
Who is it for?
Adopt gon if you have a Rails app that needs a handful of request-scoped values in JavaScript and you want to avoid parsing data attributes or inlining script in views. Do not adopt it if your front end consumes a versioned JSON API, or if you need a typed contract between server and client, because gon exposes a mutable global that both sides can change.
Can I use it commercially?
Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 3 days ago.
What is it written in?
Mainly Ruby, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on September 30, 2026, and from our analysis. They are not legal advice.

Editorial analysis

What gon solves for Rails developers

The README describes the problem it targets directly: sending start data from a controller to JavaScript normally means writing the value into a data attribute in the view, parsing it back out in JavaScript, or inlining script in the template. gon replaces that round trip with a single helper call in the layout and a global object in the browser. You assign values in the controller, and the gem serializes them into the rendered page.

The audience is narrow and specific. This is a Rails gem, and the README points to separate ports for other stacks: gon-sinatra for Sinatra, NGon for .NET MVC, and PhoenixGon for Elixir Phoenix. If you are not on Rails, you are not the target reader of this repository, even though the concept transfers.

The README frames the payoff as avoiding "the long way through views and parsing." That is accurate but incomplete. The real gain is that the controller stays the single place where the value is decided, and the template only decides where the data lands in the document.

How the data moves from controller to browser

The mechanism is a script tag plus a global. You put one helper call in the layout, and the gem renders the current variable set into the page. The README shows `Gon::Base.render_data` for current Rails and `include_gon` for Rails 3.

In the controller you assign onto a `gon` object. The README's own example computes `gon.your_other_int` from a previously assigned value and appends to an array that was already assigned, which shows that assignments are evaluated in order against the same in-memory object rather than queued. `gon.all_variables` returns the whole set, and `gon.clear` empties it.

On the JavaScript side the values appear on a `gon` object, so `gon.your_int` is the same number the controller assigned. There is no fetch, no serialization step in your code, and no schema. The variable names are the contract, and nothing enforces them.

For AMD projects the gem offers `include_gon_amd`, which emits a `define` call instead of a global. The README notes that the `namespace_check` option does nothing in that mode and that `namespace` becomes the module name. That is a real behavioural difference between two helpers that otherwise share options, and it is easy to miss.

Installing gon and passing your first value

The README does not include a standalone install section, but the gemspec and Gemfile in the repository root confirm it is distributed as a Ruby gem. Add the gem line to your Gemfile as the README describes, then install it with Bundler.

Then place the helper in your application layout. The README uses this form for current Rails:

erb
<head>
  <title>some title</title>
  <%= Gon::Base.render_data %>
</head>

If you are on Rails 3, the README gives `include_gon` instead. Assign values in a controller action and read them in JavaScript:

ruby
gon.your_int = 123
gon.your_other_int = 345 + gon.your_int
gon.all_variables
# > {:your_int => 123, :your_other_int => 468}
js
alert(gon.your_int)
alert(gon.your_other_int)

After the page loads, the browser console should show the same values the controller assigned. If `gon` is undefined in the browser, the helper is not in the layout that rendered the page.

gon.watch, Rabl and Jbuilder: the optional layers

The README promotes `gon.watch` as a way to renew variable data over ajax without writing long JavaScript functions, and it says the feature supports `gon.watch.rabl` and `gon.watch.jbuilder` usage. The detailed instructions live in the project wiki, not in the README, so the exact request format and refresh semantics are not documented in the repository's main file.

Rabl and Jbuilder support work the other way around: instead of assigning values in the controller, you write the assignment logic in a template. The README's stated benefits for Rabl are cleaning up controllers, working with database objects and collections, and keeping the option to avoid the common way of transferring data to JavaScript. That last point is the honest one. Using Rabl with gon does not remove the view layer, it moves the serialization logic into a template format you may already have.

There is also `gon.global`, which the README describes as sending data to JavaScript from anywhere, aimed at initialization data. That is a broader reach than the per-request flow, and it is documented only through a wiki link.

Where gon is the wrong tool

The global namespace is the main limitation. Everything you assign lands on one object in the browser, and any script on the page can read or overwrite it. There is no namespacing beyond the AMD helper's module name, and no separation between request-scoped data and data meant to persist.

Payload size is the second constraint. Because `render_data` writes the current variable set into the document, every value you assign is serialized into the HTML on every request. The README offers no guidance on trimming the set, but `gon.clear` exists, which suggests the maintainers expect you to manage the contents yourself.

The third issue is coupling. The controller and the JavaScript share variable names with nothing checking them. Rename `gon.your_int` on the server and the browser code fails silently at runtime. If your front end is a separate application, or if you need a versioned contract between server and client, a JSON endpoint with an explicit schema is a better fit than a global object written into a template.

Finally, the README does not document rollback, deprecation policy, or what happens to `gon.watch` requests when the session expires. Those are the questions to ask before putting live values behind the watch feature.

How gon compares to a JSON endpoint

The straightforward alternative is to render JSON from a controller action and fetch it from the browser. The difference in approach is timing and coupling. A JSON endpoint is requested by the client after the page loads, so the data arrives asynchronously and the JavaScript must handle loading states. gon writes the data into the initial document, so it is available synchronously when your script runs, with no extra request.

That trade favors gon for small, request-scoped values that the page needs immediately, such as a user id or a role. It favors the JSON endpoint when the payload is large, when the client decides what it needs, or when the same data serves multiple consumers. The README's own example of `gon.your_int` and `gon.your_hash` is squarely in the first category.

There is a middle option the README itself describes as the problem gon replaces: data attributes on elements, parsed in JavaScript. That keeps the values out of a global, at the cost of a parse step and a DOM dependency. gon is a convenience over that pattern, not a different class of solution.

Maintenance, licence and upgrade cost

The repository is not archived, and the last push was on 2026-09-20, which is recent. The release history shows v7.1.0 on 2026-06-11, v7.0.0 on 2026-01-11 and v6.6.0 on 2025-11-14. The jump from 6.x to 7.x within a year is the main upgrade signal: check the CHANGELOG.md at the repository root before bumping a major version, because the README still documents the Rails 3 `include_gon` helper alongside the current `Gon::Base.render_data` form, and that coexistence is exactly the kind of thing a major release can change.

The gem is MIT licensed. That is permissive and standard for Rails ecosystem libraries, but it is not legal advice, and you should confirm the terms in the LICENSE file rather than relying on the README's one-line statement. The README also points to Tidelift as the security contact for vulnerability reports, which means security coordination goes through a commercial platform rather than a GitHub issue tracker.

The maintainer list in the README names a single current maintainer. That is a real bus-factor consideration for a gem that sits in the request path of every page render, and it is worth weighing before you build on `gon.watch`.

Editorial conclusion

Adopt gon if you have a Rails app that needs a handful of request-scoped values in JavaScript and you want to avoid parsing data attributes or inlining script in views. Do not adopt it if your front end consumes a versioned JSON API, or if you need a typed contract between server and client, because gon exposes a mutable global that both sides can change. Before installing, verify the gem's current version against the releases listed in its repository, confirm the helper name for your Rails version (render_data on current Rails, include_gon on Rails 3), and check whether your JSON encoding library is one of the engines multi_json autodetects.

Frequently asked questions

How do I install gon in a Rails app?

Add the gem to your Gemfile, install it, and put the helper in your application layout. The README shows `Gon::Base.render_data` for current Rails and `include_gon` for Rails 3.

What is the difference between gon and gon.watch?

Plain gon writes the variable set into the rendered page once, so the values are available when your script runs. `gon.watch` renews that data over ajax without reloading the page, and the README says it supports `gon.watch.rabl` and `gon.watch.jbuilder` usage, with instructions on the project wiki.

Can I use gon with Sinatra or Phoenix instead of Rails?

Not this repository. The README points to gon-sinatra for Sinatra and PhoenixGon for Elixir Phoenix, and to NGon for .NET MVC, as separate ports rather than part of this gem.

Official sources

  1. gazay/gon on GitHub
  2. Issues
  3. License: MIT
  4. README
  5. Releases
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/gazay-gon.svg)](https://hysenlabs.com/projects/gazay-gon)