Skip to content

Ruby support is not consumable by Rails projects out-of-the-box (image vintage + reek/rubocop scope) #25

@matthew-on-git

Description

@matthew-on-git

Summary

The Makefile + image already declare Ruby support (HAS_RUBY, rubocop, rspec, reek), but a real-world Rails project (Rails 7.1, Ruby 3.2) cannot use make check without significant setup gymnastics. Two distinct gaps surfaced when wholesale-syncing the reference Makefile into a downstream Rails consumer:

  1. Image ships Ruby 3.1.2 — too old to parse Gemfiles that use the windows platform alias (introduced in Bundler shipped with Ruby 3.2).
  2. reek and (likely) rubocop defaults scan vendor/bundle/ — generates tens of thousands of warnings and runs for minutes against installed gem code.

Both are blocking adoption for any Rails 7+ project.


Gap 1 — Image Ruby version (3.1.2) too old for modern Gemfiles

Reproduce

In a downstream project with a typical Rails 7.1 Gemfile:

# Gemfile
group :development, :test do
  gem 'debug', platforms: %i[mri windows]
end

Run make test against ghcr.io/devrail-dev/dev-toolchain:v1:

Actual

Bundler::GemfileError:
  `windows` is not a valid platform. The available options are: [:ruby, :ruby_18, ...,
  :mri, ..., :mswin, ..., :mingw, ..., :x64_mingw, ...]

_test exits non-zero in 341ms. RSpec never runs.

Why

Image: ruby 3.1.2p20 (2022-04-12 revision 4491bb740a) (verified via docker run --rm ghcr.io/devrail-dev/dev-toolchain:v1 ruby --version).

Bundler shipped with Ruby 3.1.x does not recognize the windows platform alias, which was added in a later Bundler release (shipped with Ruby 3.2+). Modern Rails generators emit platforms: %i[mri windows] in the default Gemfile, so any Rails 7+ project using rails new will hit this immediately.

Suggested fix

Bump the base image (or COPY layer) to Ruby 3.2+. Confirm in CI by adding a smoke test that runs bundle install against a Gemfile containing the windows platform tag.


Gap 2 — reek (and probably rubocop) defaults scan vendor/bundle/

Reproduce

In a downstream project with .devrail.yml declaring languages: [ruby] and a typical vendor/bundle/ from bundle install --path vendor/bundle:

make lint

Actual

... 73,742 total warnings ...

vendor/bundle/ruby/3.2.0/gems/zeitwerk-2.7.5/lib/zeitwerk/registry.rb -- 4 warnings:
  [4]:IrresponsibleModule: Zeitwerk::Registry has no descriptive comment
  [53]:NestedIterators: ...
  [48]:TooManyStatements: ...
  ...

{"target":"lint","status":"fail","duration_ms":245518,
 "languages":["ruby"],"failed":["ruby:rubocop","ruby:reek"]}

_lint runs for 245 seconds and reports 73K+ warnings — almost all from gems in vendor/bundle/ (Zeitwerk, ActiveSupport, etc.), not the project's own code.

Why

The current internal targets call reek (and per the same pattern, rubocop) against . with no exclusions and no path scope. Rails projects conventionally restrict linting to app lib spec (and sometimes config bin). Without that, every gem's source code is treated as project code.

A downstream .reek.yml / .rubocop.yml could exclude vendor/, but two reasons that's not a clean solution:

  1. Most consumers never look at the upstream Makefile and won't know they need to add this config.
  2. Even with the config, the runtime is still wasted enumerating thousands of files.

Suggested fix

Default the Ruby lint/format scope to a sensible Rails-shaped path set, with an override hook:

RUBY_PATHS ?= app lib spec
# in _lint:
rubocop $(RUBY_PATHS) || ...
reek $(RUBY_PATHS) || ...

Or, alternatively, default to . but always exclude vendor/, node_modules/, tmp/, log/, and .git/ — matching the pattern already used in _lint for bash (-not -path './vendor/*').

The bash branch already does this:

sh_files=$$(find . -name '*.sh' -not -path './.git/*' -not -path './vendor/*' -not -path './node_modules/*' 2>/dev/null);

The Ruby branch needs the equivalent.


Combined impact

A consumer following README.md and dropping languages: [ruby] into .devrail.yml will see make check fail catastrophically on a fresh Rails project:

  • _test: Bundler error; RSpec never runs
  • _lint: 245s of noise, 73K warnings, exit 1
  • _format, _security: likely the same scope issue

This is currently being worked around in at least one downstream project by leaving the Makefile pinned to an older DevRail vintage that predates Ruby support entirely. That defeats the value proposition.


Repro environment

  • Image: ghcr.io/devrail-dev/dev-toolchain:v1 (whatever :v1 resolves to as of 2026-04-25)
  • Host: Linux 6.19 / Docker 28.x
  • Downstream project: Rails 7.1, Ruby 3.2, RSpec 3.13, RuboCop 1.85, standard vendor/bundle layout

Happy to provide a minimal reproducer repo if useful.


Suggested acceptance criteria

  • Base image runs Ruby 3.2+ (and Bundler shipped with it)
  • _lint Ruby branch scopes rubocop/reek to project paths (or excludes vendor/, node_modules/, tmp/, log/, .git/)
  • _format, _security Ruby branches use the same scope as _lint
  • CI smoke test against a minimal Rails 7+ Gemfile (with windows platform) confirms make check passes
  • CHANGELOG entry under "Fixed"

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions