Skip to content

Support Rails 8.1 / Ruby 4 (Haml 6, Ransack 4)#39

Open
lleirborras wants to merge 5 commits into
masterfrom
upgrade/rails-8.1-ruby-4
Open

Support Rails 8.1 / Ruby 4 (Haml 6, Ransack 4)#39
lleirborras wants to merge 5 commits into
masterfrom
upgrade/rails-8.1-ruby-4

Conversation

@lleirborras

Copy link
Copy Markdown
Member

Summary

Makes stradivari load and run on Rails 8.1 / Ruby 4 while staying compatible with the older stack apps are on today (Rails 6.1 / Ruby 2.7 / Haml 5). No app is forced to upgrade in lockstep — the same gem version works on both.

This is the first piece of the fleet Rails 8.1 / Ruby 4 upgrade. stradivari is a dependency of ~13 apps, and its Haml 5 assumptions were blocking them.

What changed

  • Filter dispatch now resolves on Rails 8. The Active Record filter picked an implementation off the AR major version and had no branch past Rails 7, so it raised "Unsupported Active Record version". It now uses the modern path for Rails 4 and up.
  • Haml 6 support. Haml 6 removed the haml_tag / haml_concat / capture_haml helpers that the table / tabs / filter / details builders rely on. Added Stradivari::HamlCompat, a small reimplementation over Action View's capture / content_tag / output_buffer. It defers to Haml's native helpers when they're present (Haml 5), so nothing changes for apps still on Haml 5 — the shim only kicks in on Haml 6+. This also removes the per-app haml_tag shim several apps were carrying.
  • Ransack 4. Filter queries run through Ransack 4. (Consumers still need to declare ransackable_attributes on their models — that's the app's responsibility, unchanged.)
  • Engine hardening. Helper injection into ActionController::Base / ActionMailer::Base is now guarded with defined?, so the engine loads in api_only apps that don't pull in Action Mailer.
  • Gem hygiene. Dropped the bundler ~> 1.5 development pin (it forced Bundler 1.x and blocked bundle install on current toolchains). No required_ruby_version cap — consumers span Ruby 2.x through 4.0. Bumped to 0.8.0 with a changelog entry.
  • First automated tests. The gem had none. Added a smoke harness (test/smoke.rb) that boots a minimal app and exercises filter dispatch, a Ransack query, the Haml shim, table_for, and tabs_for, plus a CI matrix.

How to test

CI runs the smoke across the matrix:

  • Ruby 4.0.5 / 3.4 — Rails 8.1, Haml 7, Ransack 4
  • Ruby 3.4 — Rails 7.2
  • Ruby 2.7 — Rails 6.1, Haml 5, Ransack 2 (backward-compat row)

Locally: BUNDLE_GEMFILE=test/Gemfile.ci bundle install && BUNDLE_GEMFILE=test/Gemfile.ci bundle exec ruby test/smoke.rb. Override the stack with RAILS_VERSION / HAML_VERSION / RANSACK_VERSION.

Verified green on both ends: Ruby 4.0.5 / Rails 8.1.3 / Haml 7.2 / Ransack 4.4 and Ruby 2.7.8 / Rails 6.1 / Haml 5.2 / Ransack 2.

Risks / follow-ups

  • The capture_haml shim has to bridge a buffer quirk in the tabs generator under Haml 6 (the generator instance-execs blocks whose Haml-compiled output targets a different buffer). Covered by the tabs_for smoke check; worth an eye in review.
  • Bootstrap 3 markup and the Less assets are untouched — this PR is Ruby/Rails/Haml only. The BS3 → BS4/5 migration is separate.
  • The Rails3 filter branch is kept but untested (no consumer is on Rails 3, and Rails 3 can't run on Ruby 3/4).

lleirborras and others added 5 commits June 18, 2026 22:40
…ard)

- filter/model/active_record.rb: default to the Rails 4+ adapter instead of
  enumerating each AR major and raising on > 7 (was the Rails 8 hard blocker).
- HamlCompat: ship haml_tag / haml_concat / capture_haml (removed in Haml 6)
  over ActionView content_tag/capture, mixed into the view via StradivariHelper
  so the generators work on Haml 6+ and consumers drop their app-side shim.
- engine: guard the ActionController/ActionMailer helper injection with
  defined? so the gem loads without ActionMailer (api_only apps).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The ancient `bundler \"~> 1.5\"` dev dependency forced Bundler 1.x and blocked
install under modern Bundler. Bump version to 0.8.0.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
test/smoke.rb boots a minimal Rails app and exercises filter dispatch, a
Ransack 4 query, the Haml-6 shim, table_for and tabs_for on sqlite. Runnable
via Dockerfile.ai (Ruby 4.0.5) and a GitHub Actions matrix (Ruby 3.4/4.0 x
Rails 7.2/8.1). RAILS_VERSION-parameterised test/Gemfile.ci.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- HamlCompat methods defer to the native helper via `super` when present, so
  consumers still on Haml 5 use Haml::Helpers unchanged; the reimplementation
  only kicks in on Haml 6+ (where the helpers were removed).
- Drop the required_ruby_version >= 3.0 cap — it would have broken consumers
  still on Ruby 2.x. The gem code runs from Ruby 2.7 to 4.0.
- Smoke: Ruby-2.7-safe syntax, run haml_tag inside a capture buffer, dynamic
  version banner. Gemfile.ci takes HAML/RANSACK/SQLITE3 version env for the
  matrix. CI sweeps Ruby 4.0/3.4 x Rails 8.1/7.2 + Ruby 2.7/Rails 6.1/Haml 5.
- Stop tracking the stale test lockfile; gitignore test/*.lock.

Verified green on both Ruby 4.0.5/Rails 8.1/Haml 7 and Ruby 2.7/Rails 6.1/Haml 5.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
GitHub Actions sets `env: FOO: ${{ matrix.foo }}` to an empty string (not
unset) when a matrix row omits that key, so `ENV.fetch('HAML_VERSION', default)`
returned "" and `gem 'haml', ""` raised "Illformed requirement []". The newer
matrix rows (which leave HAML/RANSACK/SQLITE3 unset) failed bundle install; the
2.7/6.1 row passed because it sets them. Route every optional version through a
helper that treats blank as absent.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant