Upgrading
How to upgrade an existing Rails Pulse install, including the one-time route migration required when moving from any 0.3.x release to 0.4.0.
Routine upgrades
Most releases only need the upgrade generator and a migrate:
bundle update rails_pulse
rails generate rails_pulse:upgrade
rails db:migrate # separate Pulse database: rails db:migrate:rails_pulse
rails rails_pulse:status # exits 1 while anything still needs action
The upgrade generator copies any new migrations into your app, compares your tables against the gem’s schema as a safety net, and appends new settings to config/initializers/rails_pulse.rb without rewriting values you already set. Review the initializer with git diff and keep or discard hunks.
rails rails_pulse:status reports the schema, pending migrations, route backfill, initializer and summary state for this install, and ends with an “Action needed” list when something is outstanding. Run it after migrating, and from a deploy check if you want a release to fail before it serves traffic.
Always restart your web and worker processes after migrating.
If the gem is deployed before its migrations
Rails Pulse checks its tables once per process at boot. When the gem is newer than the schema it is connected to, it logs one warning, pauses tracking, and answers every dashboard page with a 503 that lists the upgrade commands, instead of raising on each request. Tracking resumes on the next restart after the schema is current. config.schema_check_enabled = false turns the guard off.
Upgrading from 0.3.x to 0.4.0
This applies to every 0.3.x release (0.3.0 through 0.3.3). 0.4.0 contains a breaking schema change and a mandatory one-time data migration.
Back up your database first. The route migration is irreversible.
db:rollbackraisesActiveRecord::IrreversibleMigrationonChangeRailsPulseRoutesToMultiVerbModel, and routes merged by the backfill are deleted with no audit trail. Recovery from a bad upgrade is restore-from-backup only.
What changed
- Route identity is now
[controller_action, path].GET /users(users#index) andPOST /users(users#create) are separate routes, and dynamic paths are normalized at capture time (/posts/42becomes/posts/:id). rails_pulse_routes.methodis dropped. The HTTP verb now lives on each request, and a route carries anhttp_methodsarray instead.- Every application, worker, and dashboard process must be restarted together against the migrated schema.
Single database
bundle update rails_pulse
rails generate rails_pulse:upgrade
rails db:migrate
rails rails_pulse:migrate_routes # required
rails rails_pulse:status # expect "OK — nothing to do."
Separate database
bundle update rails_pulse
rails generate rails_pulse:upgrade --database=separate
rails db:migrate:rails_pulse
rails rails_pulse:migrate_routes # required
rails rails_pulse:status # expect "OK — nothing to do."
Before migrating, add schema_dump: false to the rails_pulse entry in config/database.yml and delete db/rails_pulse_structure.sql if it exists. Without that setting Rails dumps or loads a structure file for the Pulse database and db:migrate can fail with relation already exists. The upgrade generator warns when the key is missing.
Do not run db:setup or db:prepare as a substitute for db:migrate:rails_pulse on an existing install.
Why migrate_routes is required
A schema migrate alone adds the new columns but leaves the Action column empty and leaves GET /sign_in and POST /sign_in as separate rows. rails rails_pulse:migrate_routes:
- Backfills
controller_actionfrom your live router, then from request history - Collapses historical literal paths (
/posts/42) into their parameterized form - Merges routes that share the same action
- Adds a unique index for unrecognised paths (404s and other requests with no controller action)
The task prints what it updated, merged, and skipped. If it reports duplicate null-action paths that it could not resolve, fix those rows manually and re-run it.
Until the backfill has run, the dashboard shows a banner with the exact command, and the upgrade generator prints the same warning.
Restart everything together
A rolling restart that leaves 0.3.x processes running against the new schema will silently drop request tracking in those processes and return 500s on the routes page. Release-phase migrations (Heroku, Kamal) are fine as long as no old process survives the release. Deploy order:
- Deploy the new gem
rails generate rails_pulse:upgraderails db:migrate(ordb:migrate:rails_pulse)rails rails_pulse:migrate_routesrails rails_pulse:status(exits 1 if anything above was skipped)- Restart all processes before serving traffic
Initializer changes
The upgrade generator appends settings your initializer does not mention. In 0.4.0 that includes:
-
config.track_exceptions = false. Exception tracking is off for existing installs so nothing starts capturing on upgrade. Opt in once you have reviewed what is stored:config.track_exceptions = true config.capture_exception_params = true # filtered via Rails' filter_parametersSee Exception Tracking.
-
New
max_table_recordsentries forrails_pulse_exception_occurrences,rails_pulse_exception_groups, andrails_pulse_deployments. The hash you set is now merged with the gem defaults, so a partial hash no longer removes caps for tables you did not list. -
config.async = false if Rails.env.test?. Tracking writes now run on a background thread. Transactional tests share one database connection across threads, so the tracker writes inline there. The tracker also detects a shared connection on its own, but add the line to be explicit. Without it, PostgreSQL test suites could fail withmessage type 0x5a arrived from server while idle. -
Historical comparison settings (
baseline_window,comparison_window,hourly_summary_retention,regression_thresholds) are added as comments. See Advanced Configuration.
Other changes to check
- Authentication is now on by default outside development and test, not only in production. Staging environments that previously served the dashboard unauthenticated now fall back to HTTP Basic against
RAILS_PULSE_USERNAME/RAILS_PULSE_PASSWORD, and deny everything if the password is unset. Configureconfig.authorizebefore deploying. See Authentication. - Authentication hooks fail closed. An
authentication_methodthat returnsfalsewithout rendering or redirecting is now a 403. Predicate-style checks belong in the newconfig.authorize. - Assets are no longer registered with Sprockets. If you added
rails-pulse.jsorrails-pulse.csstoconfig.assets.precompile, remove those entries.assets:precompilenow runsrails_pulse:install_assets, which copies the pre-built files intopublic/assetssoconfig.asset_hostand CDN-only content security policies keep working. - Ruby 3.1 is the minimum. The gem previously declared 3.0 but could not actually install there.
- Tagging by path.
RailsPulse::Route.find_by(path:)can now return several rows. Look routes up bycontroller_actioninstead. See Tagging. - Charts. ECharts is now tree-shaken and the JavaScript bundle is a third of its previous size. This only matters if you have customised the dashboard’s charts.
- Standalone dashboard authentication.
rails_pulse_serverno longer runsauthorizeorauthentication_method. It uses HTTP Basic againstRAILS_PULSE_USERNAME/RAILS_PULSE_PASSWORDunless you setconfig.standalone_authentication_method. See Standalone Dashboard. - Removed methods.
RailsPulse.warm_metric_cache!,RailsPulse.clear_metric_cache!, and thegroup_by_date/group_by_hourscopes the gem previously added to everyActiveRecord::Relationare gone. Nothing in the dashboard used them; check your own code if you called them.
Troubleshooting an upgrade
Common failure modes and their fixes are listed under Troubleshooting.
Next Steps
- Exception Tracking — decide whether to turn it on
- Authentication — move to the
authorizepredicate - Deployment Tracking — record deploys so regressions line up with releases