ankane/chartkick
Create beautiful JavaScript charts with one line of Ruby
Healthy across all four use cases
Permissive license, no critical CVEs, actively maintained — safe to depend on.
Has a license, tests, and CI — clean foundation to fork and modify.
Documented and popular — useful reference codebase to read through.
No critical CVEs, sane security posture — runnable as-is.
- ✓Last commit 6w ago
- ✓2 active contributors
- ✓MIT licensed
Show 4 more →Show less
- ✓CI configured
- ✓Tests present
- ⚠Small team — 2 contributors active in recent commits
- ⚠Single-maintainer risk — top contributor 99% 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.
[](https://repopilot.app/r/ankane/chartkick)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/ankane/chartkick on X, Slack, or LinkedIn.
Onboarding doc
Onboarding: ankane/chartkick
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:
- 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. - 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.
- Cite source on changes. When proposing an edit, cite the specific path:line-range. RepoPilot's live UI at https://repopilot.app/r/ankane/chartkick 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 6w ago
- 2 active contributors
- MIT licensed
- CI configured
- Tests present
- ⚠ Small team — 2 contributors active in recent commits
- ⚠ Single-maintainer risk — top contributor 99% 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 ankane/chartkick
repo on your machine still matches what RepoPilot saw. If any fail,
the artifact is stale — regenerate it at
repopilot.app/r/ankane/chartkick.
What it runs against: a local clone of ankane/chartkick — 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 ankane/chartkick | 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 ≤ 69 days ago | Catches sudden abandonment since generation |
#!/usr/bin/env bash
# RepoPilot artifact verification.
#
# WHAT IT RUNS AGAINST: a local clone of ankane/chartkick. If you don't
# have one yet, run these first:
#
# git clone https://github.com/ankane/chartkick.git
# cd chartkick
#
# 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 ankane/chartkick and re-run."
exit 2
fi
# 1. Repo identity
git remote get-url origin 2>/dev/null | grep -qE "ankane/chartkick(\\.git)?\\b" \\
&& ok "origin remote is ankane/chartkick" \\
|| miss "origin remote is not ankane/chartkick (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/chartkick.rb" \\
&& ok "lib/chartkick.rb" \\
|| miss "missing critical file: lib/chartkick.rb"
test -f "lib/chartkick/helper.rb" \\
&& ok "lib/chartkick/helper.rb" \\
|| miss "missing critical file: lib/chartkick/helper.rb"
test -f "vendor/assets/javascripts/chartkick.js" \\
&& ok "vendor/assets/javascripts/chartkick.js" \\
|| miss "missing critical file: vendor/assets/javascripts/chartkick.js"
test -f "build/rollup.config.js" \\
&& ok "build/rollup.config.js" \\
|| miss "missing critical file: build/rollup.config.js"
test -f "lib/chartkick/engine.rb" \\
&& ok "lib/chartkick/engine.rb" \\
|| miss "missing critical file: lib/chartkick/engine.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 69 ]; then
ok "last commit was $days_since_last days ago (artifact saw ~39d)"
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/ankane/chartkick"
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).
⚡TL;DR
Chartkick is a Ruby gem that generates Chart.js-powered JavaScript charts via simple Rails view helpers, eliminating the need to write chart configuration code. Users write <%= line_chart User.group_by_day(:created_at).count %> in ERB and get a fully rendered, interactive chart without touching JavaScript. It wraps Chart.js, Google Charts, and Highcharts under a unified API. Dual-stack design: lib/chartkick/ contains Ruby side (helper.rb for view helpers, engine.rb for Rails integration, sinatra.rb for Sinatra support, utils.rb for data transformation), while vendor/assets/javascripts/ and build/ contain the JavaScript layer. Build pipeline uses Rollup + Babel (build/rollup.config.js) to transpile and bundle JavaScript from node_modules.
👥Who it's for
Rails and Sinatra developers building admin dashboards, analytics pages, or data visualizations who want production-ready charts without learning charting library APIs. They value minimal code, sensible defaults, and chart types that work with ActiveRecord grouped queries out of the box.
🌱Maturity & risk
Production-ready and actively maintained. The repo shows 13K+ lines of Ruby code, comprehensive test coverage (test/ directory with chartkick_test.rb), working CI via GitHub Actions (build.yml), and follows semantic versioning (version.rb tracking). Recent activity visible in CHANGELOG.md and build tooling (rollup, Babel) kept current.
Low risk for abandonment: single maintainer (ankane) but high-quality related ecosystem (Groupdate, Hightop, Blazer). Dependency risk is minimal—Chart.js 4.5.1 is stable, date-fns 2.30.0 is actively maintained. No indication of breaking API changes; the 13K Ruby codebase is stable. Watch for Chart.js major version updates requiring gem version bumps.
Active areas of work
No specific recent activity visible in file metadata, but the repo structure shows active maintenance: licensed third-party bundles (Chart.js, date-fns, kurkle-color) are current versions, build tooling is modern (Rollup 3.9+, Babel 7.20+), and guides exist for CSP and plugin integration. Repository accepts contributions via standard PR process (pull_request_template.md present).
🚀Get running
git clone https://github.com/ankane/chartkick.git
cd chartkick
bundle install
cd build && npm install && npm run build
Daily commands:
cd build
npm run build
```This transpiles and bundles JavaScript into vendor/assets/javascripts/chartkick.js. For Rails integration, add to Gemfile, run `bundle install`, then use helpers in ERB templates. No separate dev server; Rails serves static assets.
🗺️Map of the codebase
lib/chartkick.rb— Main entry point and module definition that exports all public APIs and initializes the gemlib/chartkick/helper.rb— Core helper methods that generate chart HTML tags and wire up JavaScript integration for Rails viewsvendor/assets/javascripts/chartkick.js— Client-side JavaScript that initializes and renders Chart.js instances from HTML data attributesbuild/rollup.config.js— Build configuration that bundles Chart.js and dependencies into distributable JavaScript assetslib/chartkick/engine.rb— Rails engine that registers asset pipeline and initializes the gem within Rails applicationschartkick.gemspec— Gem metadata and dependency specification for packaging and distributionbuild/package.json— NPM dependencies defining Chart.js version and all charting library transitive dependencies
🧩Components & responsibilities
- lib/chartkick/helper.rb (Rails Helper) (Ruby, ERB, JSON) — Accepts Ruby data structures (arrays, hashes), serializes to JSON, generates HTML div with data-* attributes and unique ID
- Failure mode: Invalid data structure throws serialization error; malformed options passed to Chart.js; missing required data key
- chartkick.js (Client Initializer) (JavaScript ES6, DOM APIs) — On page load, finds all divs with data-chartkick attribute, parses JSON config, instantiates Chart.js with merged options, applies plugins
- Failure mode: Malformed JSON in data attributes; Chart.js config validation fails; plugin loading fails; canvas context unavailable
- Chart.js (Rendering Engine) (Canvas 2D API, JavaScript) — Renders animated Canvas-based charts with event handlers, responsive scaling, legend, tooltips, and extensive customization
- Failure mode: Unsupported chart type; invalid axis config; dataset mismatch; memory pressure on large datasets
- lib/chartkick/engine.rb (Rails Integration) (Rails Engine API, Asset Pipeline) — Registers Chartkick as Rails engine, tells asset pipeline to serve chartkick.js and Chart.bundle.js, loads helpers into ActionView
- Failure mode: Asset pipeline misconfiguration; gem not installed in Gemfile; precompilation failure
🔀Data flow
Rails View Template→Chartkick Helper (helper.rb)— View calls line_chart(@user_growth_data) with Ruby array/hash of chart dataChartkick Helper→HTML output— Helper serializes Ruby data to JSON, wraps in <div data-chartkick='...' data-options='...'>; returns HTML stringBrowser DOM→chartkick.js (initialization)— On page load, chartkick.js scans DOM for [data-chartkick] divschartkick.js→Chart.js constructor— Parses data-* attributes, merges with defaults and plugins, invokes new Chart
🛠️How to make changes
Add a new chart type
- Add helper method in lib/chartkick/helper.rb following pattern: def pie_chart(data, options = {}) (
lib/chartkick/helper.rb) - Map chart type to Chart.js type in chartkick.js initialization logic within vendor/assets/javascripts/chartkick.js (
vendor/assets/javascripts/chartkick.js) - Add test cases in test/chartkick_test.rb to verify HTML output and options handling (
test/chartkick_test.rb)
Upgrade Chart.js version
- Update chart.js version in build/package.json dependencies section (
build/package.json) - Run npm install and npm run build to regenerate Chart.bundle.js (
build/rollup.config.js) - Update vendor/assets/javascripts/Chart.bundle.js and test compatibility (
vendor/assets/javascripts/Chart.bundle.js) - Update CHANGELOG.md with version bump and breaking changes (
CHANGELOG.md)
Add support for a new JavaScript framework
- Create new integration file (e.g., lib/chartkick/vue.rb) following the pattern in lib/chartkick/sinatra.rb (
lib/chartkick/sinatra.rb) - Export helper methods in lib/chartkick.rb by requiring the new framework module (
lib/chartkick.rb) - Create integration guide in guides/ directory with usage examples (
guides/Chartjs-Plugins.md)
🔧Why these technologies
- Chart.js 4.5.1 — Lightweight, zero-dependency charting library with broad browser support and excellent customization via plugins
- date-fns + chartjs-adapter-date-fns — Provides date/time axis support for time-series charts without jQuery dependency
- Rollup bundler — Efficient ES6 module bundling to reduce JavaScript payload and enable tree-shaking of unused Chart.js features
- Rails Engine + asset pipeline — Seamless integration with Rails conventions; automatic asset serving and minification
⚖️Trade-offs already made
-
Data embedded in HTML data attributes rather than separate API calls
- Why: Simplicity: single helper call generates self-contained chart without JavaScript-Rails communication
- Consequence: Not ideal for very large datasets; chart data sent with every page load even if not immediately visible
-
Chart.js as only bundled library (not Chart.js + Highcharts + Plotly)
- Why: Minimizes gem size and dependency surface; users can easily swap via Chartkick plugin system
- Consequence: Some users may need to fork or customize to use alternative charting libraries
-
Client-side initialization only; no server-side rendered SVG
- Why: Reduces server load; leverages browser Canvas rendering and interactivity
- Consequence: No pre-rendered charts in email or PDF; requires JavaScript enabled on client
🚫Non-goals (don't propose these)
- Does not provide real-time chart updates or WebSocket integration
- Does not handle authentication or data access control (responsibility of Rails app)
- Does not support server-side chart rendering to static images
- Does not include dashboard or admin panel (see Blazer companion gem)
- Does not handle database queries directly (data passed explicitly to helpers)
🪤Traps & gotchas
Asset pipeline variance: Chartkick supports three JS setups (importmap, bundler like Webpack/esbuild, Sprockets), each with different pin/require statements in README—verify which setup the consuming Rails app uses before debugging chart not rendering. Data attribute encoding: chartkick.js expects chart data encoded as JSON in a data-chartkick DOM attribute (set by helper.rb); corrupted or missing attributes cause silent failures. Chart.js peer dependency: the Gem itself doesn't vendor a specific Chart.js version constraint; build/package.json pins Chart.js 4.5.1, but users must ensure their JavaScript bundler includes it. Sinatra vs Rails: lib/chartkick/sinatra.rb requires manual helper inclusion; not automatic like Rails engine. No other environment variables or service dependencies required.
🏗️Architecture
💡Concepts to learn
- Rails Engine — Chartkick is packaged as a Rails engine (lib/chartkick/engine.rb) to auto-register helpers and load assets without manual configuration; understanding engines is key to how the gem integrates.
- ActiveRecord Data Grouping — Chartkick helpers are designed to accept output from ActiveRecord's
group()andgroup_by_day()(from Groupdate), transforming grouped result hashes into chart data; this pattern is the expected input. - Data Attribute Serialization — Chartkick helpers serialize chart config and data into HTML5
data-*attributes, which chartkick.js then parses; this decoupling of server-side generation from client-side rendering is core to the architecture. - Chart.js Adapter Pattern — Chart.js 4.x uses adapters (e.g., chartjs-adapter-date-fns in build/package.json) to support date/time scales; Chartkick relies on these adapters for time-series charts.
- ES6 Module Bundling with Rollup — The JavaScript source is bundled via Rollup (build/rollup.config.js) to produce vendor/assets/javascripts/chartkick.js; understanding the build step is necessary to modify or debug JavaScript functionality.
- Dual Asset Pipeline Support (Importmap, Bundler, Sprockets) — Chartkick supports three distinct Rails asset loading mechanisms; helpers output chart data the same way, but JS initialization differs by setup—knowing which one your app uses prevents integration issues.
- View Helper Pattern — Chartkick's public API is Ruby view helpers (line_chart, pie_chart, etc. in helper.rb) that generate HTML; understanding how ActionView helpers work is essential to extending or debugging chart generation.
🔗Related repos
ankane/groupdate— Companion gem that provides ActiveRecord time-grouping methods (group_by_day, group_by_week) used as input data to Chartkick helpers; often used together for time-series analysis.ankane/blazer— Sister project for building admin dashboards and BI interfaces; uses Chartkick as the visualization layer for data queries and reports.ankane/vega— Alternative visualization gem for advanced, declarative grammar-based charts (Vega-Lite); chosen by Chartkick users needing more control than Chart.js offers.chartjs/Chart.js— The core charting library that powers Chartkick; understanding Chart.js config options helps troubleshoot advanced chart customization via Chartkick options.rails/rails— The Rails framework that Chartkick integrates with via Rails::Engine; needed to understand asset pipeline behavior and view helper system.
🪄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 unit tests for lib/chartkick/helper.rb
The test/chartkick_test.rb file exists but appears minimal. The helper.rb file contains the core chart rendering logic that converts Ruby data into JavaScript, yet there are likely no tests covering edge cases like nil data, empty arrays, invalid chart types, custom options merging, and HTML escaping. This is critical for a library that generates user-facing HTML/JS.
- [ ] Examine current test coverage in test/chartkick_test.rb
- [ ] Add tests in test/chartkick_test.rb for lib/chartkick/helper.rb methods
- [ ] Cover edge cases: nil/empty data, invalid chart types, custom options, HTML escaping, and data format transformations
- [ ] Verify tests run via Rakefile/build.yml
Add JavaScript unit tests for vendor/assets/javascripts/chartkick.js
The build directory has a rollup config and babel setup suggesting a modern build pipeline, but there's no test runner configured (no Jest, Vitest, or Mocha in devDependencies). The chartkick.js wrapper around Chart.js likely needs tests for data parsing, chart initialization, update logic, and plugin integration mentioned in guides/Chartjs-Plugins.md.
- [ ] Add test runner (Jest or Vitest) to build/package.json devDependencies
- [ ] Create test directory (build/tests or test/js) with test files for chartkick.js
- [ ] Add test scripts to build/package.json and .github/workflows/build.yml
- [ ] Test core functions: chart creation, data transformation, plugin handling, and Chart.js integration
Add Content Security Policy examples to lib/chartkick/engine.rb and README
guides/Content-Security-Policy.md exists but lib/chartkick/engine.rb (which sets up Rails integration) likely doesn't document CSP requirements, and the README only mentions CSP exists as a guide. Users integrating Chartkick with strict CSP policies will fail silently with Chart.js inline scripts. The engine should document required CSP directives or provide a helper.
- [ ] Review guides/Content-Security-Policy.md for CSP requirements (script-src, style-src directives)
- [ ] Add CSP configuration examples and helpers to lib/chartkick/engine.rb or create lib/chartkick/csp.rb
- [ ] Document required CSP directives in README.md with a dedicated CSP section
- [ ] Update guides/Content-Security-Policy.md with Rails engine integration example
🌿Good first issues
- Add test coverage for lib/chartkick/sinatra.rb—currently only Rails helpers are tested in test/chartkick_test.rb; Sinatra integration lacks explicit test cases for helper availability in Sinatra apps.: medium
- Expand guides/ documentation: add a 'guides/Common-Data-Patterns.md' showing real-world examples of preparing data for multi-series charts, time-series aggregations with Groupdate, and handling sparse data (e.g., days with zero values).: small
- Create an integration test in test/ that validates the full stack: Ruby helper output → JSON serialization → chartkick.js DOM initialization, ensuring end-to-end rendering of at least one chart type (line_chart) with real data.: medium
📝Recent commits
Click to expand
Recent commits
26e1114— Updated readme [skip ci] (ankane)1ffb9e0— Updated license year [skip ci] (ankane)2116aec— Updated checkout action (ankane)c2f50b9— Updated license year [skip ci] (ankane)b136a9b— Test with Ruby 4.0 on CI (ankane)925dc9c— Updated test setup [skip ci] (ankane)f211185— Version bump to 5.2.1 [skip ci] (ankane)b65364c— Updated Chart.js to 4.5.1 (ankane)4eb4889— Updated checkout action (ankane)7e37143— Updated issue templates [skip ci] (ankane)
🔒Security observations
Chartkick has a reasonable security posture as a charting library with no obvious critical vulnerabilities. Main concerns are outdated Babel dependencies that should be updated, potential XSS risks inherent to data rendering libraries (requires proper usage), and documentation gaps around security best practices. The codebase appears clean with no hardcoded secrets or exposed configurations detected. Recommendations focus on dependency updates, enhanced security documentation, and stricter version pinning.
- Medium · Outdated Babel Dependencies —
build/package.json - devDependencies. The @babel/cli@^7.20.7 and @babel/core@^7.20.12 dependencies are significantly outdated (released in December 2022). These versions may contain known security vulnerabilities and lack security patches from the past 2+ years. The caret (^) version specifier allows updates within the major version, but the base versions are old. Fix: Update Babel packages to the latest stable versions: @babel/cli@^7.23.0+, @babel/core@^7.23.0+, and @babel/preset-env to the latest version. Run 'npm audit' to identify specific vulnerabilities and apply patches. - Low · Potential XSS Risk in Chart Data Rendering —
lib/chartkick/helper.rb, vendor/assets/javascripts/chartkick.js. As a charting library that renders user-provided data, chartkick processes external data sources. While the library itself uses Chart.js which has security controls, improper usage in Ruby templates could lead to XSS if chart data is not properly sanitized before passing to JavaScript. Fix: Ensure all user-supplied data passed to chart helpers is properly sanitized. Review the helper implementation to verify data is escaped before JavaScript rendering. Document safe data handling practices in guides/Content-Security-Policy.md. - Low · Missing Security Headers Documentation —
README.md, guides/Content-Security-Policy.md. While a CSP guide exists (guides/Content-Security-Policy.md), the README and documentation should prominently feature security best practices, especially around Content Security Policy requirements for inline JavaScript execution common in chart rendering. Fix: Enhance CSP documentation with concrete examples and security headers recommended for chart rendering. Add a security section to the README with links to the CSP guide. - Low · Dependency Pinning Could Be Stricter —
build/package.json - devDependencies. Production dependencies use exact versions (chart.js@4.5.1, etc.), which is good. However, devDependencies use caret ranges (^7.20.7) which allow breaking changes within major versions. For reproducible builds, all dependencies should ideally have pinned versions. Fix: Consider using exact version pinning for devDependencies (remove ^ and ~ operators) or use a lockfile (package-lock.json) to ensure consistent builds across environments.
LLM-derived; treat as a starting point, not a security audit.
👉Where to read next
- Open issues — current backlog
- Recent PRs — what's actively shipping
- Source on GitHub
Generated by RepoPilot. Verdict based on maintenance signals — see the live page for receipts. Re-run on a new commit to refresh.