rails-preflight 0.1.0 · 9 Oct 2026, 19:05

mastodon: Rails 5.2.4.4 to 7.0

3 steps, and Ruby 2.7.2 can stay. 13 blockers, 9 of them gems.

Ruby 2.7.2 (.ruby-version) Online: 41 gems looked up on rubygems.org

Route and plan

Checked through 7.0. Faded stops count code that later versions remove, found in the same scan; gem limits past 7.0 aren't checked. Run rails-preflight 8.1 for the full route.

StepWhat to doBlockersEffort
Now, on 5.22 gems, 2 more (Ruby, Docker).0High
→ 6.02 gems.Needs Ruby 2.5.0–2.7: 2.7.2 works2Medium
→ 6.13 gems, 1 removed API (1 line).Needs Ruby 2.5.0–3.0: 2.7.2 works4Medium
→ 7.04 gems, 3 removed APIs (7 lines).Needs Ruby 2.7.0–3.2: 2.7.2 works7Medium
OptionalStart on what later versions remove while you're in the code: 5 removed APIs (18 lines).–Medium

Steps

Before you start

on Rails 5.2
  • To fix
    Ruby 2.7.2 is end-of-life. Rails 7.0 supports up to Ruby 3.2; Ruby 3.3+ needs Rails 7.1.
    Fix: high
    Ruby
  • To fix
    No ENV LANG or LC_ALL set, which can cause encoding errors.
    Fix: low
    Docker
  • To fix
    paperclip is deprecated and archived. Move to Active Storage, or to the maintained kt-paperclip fork. Used in 8 files.
    8 filesFix: high
    app/models/backup.rb
    app/models/concerns/account_avatar.rb
    app/models/concerns/account_header.rb
    app/models/custom_emoji.rb
    app/models/import.rb
    app/models/media_attachment.rb
    app/models/preview_card.rb
    app/models/site_upload.rb
    Source ↗
  • To fix
    webpacker was retired after Rails 7.0. Move to jsbundling-rails or import maps, or to shakapacker to keep webpack. Used in 28 files.
    28 filesFix: medium
    app/views/about/more.html.haml
    app/views/admin/action_logs/index.html.haml
    app/views/admin/custom_emojis/index.html.haml
    app/views/admin/domain_allows/new.html.haml
    app/views/admin/domain_blocks/edit.html.haml
    app/views/admin/domain_blocks/new.html.haml
    app/views/admin/ip_blocks/index.html.haml
    app/views/admin/pending_accounts/index.html.haml
    app/views/admin/reports/show.html.haml
    app/views/admin/settings/edit.html.haml
    app/views/admin/statuses/index.html.haml
    app/views/admin/tags/index.html.haml
    app/views/auth/sessions/two_factor.html.haml
    app/views/home/index.html.haml
    app/views/layouts/admin.html.haml
    app/views/layouts/application.html.haml
    app/views/layouts/auth.html.haml
    app/views/layouts/embedded.html.haml
    app/views/layouts/error.html.haml
    app/views/layouts/mailer.html.haml
    app/views/layouts/modal.html.haml
    app/views/layouts/public.html.haml
    app/views/media/player.html.haml
    app/views/public_timelines/show.html.haml
    app/views/relationships/show.html.haml
    app/views/settings/two_factor_authentication/webauthn_credentials/new.html.haml
    app/views/shares/show.html.haml
    app/views/tags/show.html.haml
    Source ↗

5.2.4.4 → 6.0

2 blockers
RubyNeeds Ruby 2.5.0–2.7: 2.7.2 works
  • Blocker
    nsa 0.2.7 requires activesupport >= 4.2, < 6, so it doesn't install on Rails 6.0. Upgrade it to a release that allows 6.0, or replace it.
    Fix: medium
    Gems
  • Blocker
    rails-i18n 5.1.3 requires railties >= 5.0, < 6, so it doesn't install on Rails 6.0. Upgrade it to a release that allows 6.0, or replace it.
    Fix: medium
    Gems

6.0 → 6.1

4 blockers
RubyNeeds Ruby 2.5.0–3.0: 2.7.2 works
  • Blocker
    active_model_serializers 0.10.10 requires actionpack >= 4.1, < 6.1, activemodel >= 4.1, < 6.1, so it doesn't install on Rails 6.1. Upgrade it to a release that allows 6.1, or replace it.
    Fix: medium
    Gems
  • Blocker
    devise-two-factor 3.1.0 requires activesupport < 6.1, railties < 6.1, so it doesn't install on Rails 6.1. Upgrade it to a release that allows 6.1, or replace it.
    Fix: medium
    Gems
  • Blocker
    bullet 6.1.0 doesn't load on Rails 6.1: Bullet raises on an Active Record minor it doesn't know; Rails 6.1 needs bullet >= 6.1.1. Upgrade it in the same step.
    Fix: low
    Source ↗
  • Blocker
    force_ssl at the controller level was removed in Rails 6.1. Use config.force_ssl to force HTTPS for the whole app.
    1 occurrence1 fileFix: medium
    app/controllers/application_controller.rb8force_ssl if: :https_enabled?
    6.1 notes ↗

6.1 → 7.0

7 blockers
RubyNeeds Ruby 2.7.0–3.2: 2.7.2 works
  • Blocker
    annotate 3.1.1 requires activerecord >= 3.2, < 7.0, so it doesn't install on Rails 7.0. Upgrade it to a release that allows 7.0, or replace it.
    Fix: medium
    Gems
  • Blocker
    discard 1.2.0 requires activerecord >= 4.2, < 7, so it doesn't install on Rails 7.0. Upgrade it to a release that allows 7.0, or replace it.
    Fix: medium
    Gems
  • Blocker
    redis-actionpack 5.2.0 requires actionpack >= 5, < 7, so it doesn't install on Rails 7.0. Upgrade it to a release that allows 7.0, or replace it.
    Fix: medium
    Gems
  • Blocker
    redis-activesupport 5.2.0 requires activesupport >= 3, < 7, so it doesn't install on Rails 7.0. Upgrade it to a release that allows 7.0, or replace it.
    Fix: medium
    Gems
  • Blocker
    Changing error messages in place (errors[:attr] << msg, errors.messages[:attr] = ..., errors.messages.delete/clear) was removed in Rails 7.0: it now changes a copy, so the error is silently lost. Use errors.add, errors.delete and errors.clear.
    2 occurrences2 filesFix: low
    app/validators/ed25519_key_validator.rb9record.errors[attribute] << I18n.t('crypto.errors.invalid_key') unless verified?(key)
    app/validators/ed25519_signature_validator.rb11record.errors[attribute] << I18n.t('crypto.errors.invalid_signature') unless verified?(verify_key, signature, message)
    7.0 notes ↗
  • Blocker
    ActionMailer::DeliveryJob and ActionMailer::Parameterized::DeliveryJob were removed in Rails 7.0. Mail is delivered by ActionMailer::MailDeliveryJob.
    2 occurrences (1 app, 1 test)2 filesFix: low
    config/initializers/delivery_job.rb1ActionMailer::DeliveryJob.class_eval do
    spec/models/user_spec.rb178expect { user.send_confirmation_instructions }.to have_enqueued_job(ActionMailer::DeliveryJob)
    7.0 notes ↗
  • Blocker
    ActiveModel::Errors#keys, #values, #to_h, #slice! and #to_xml were removed in Rails 7.0. Use errors.attribute_names, errors.to_hash or the ActiveModel::Error objects errors.each yields.
    3 occurrences (2 app, 1 test)2 filesFix: low
    lib/mastodon/accounts_cli.rb106user.errors.to_h.each do |key, error|
    lib/mastodon/accounts_cli.rb172user.errors.to_h.each do |key, error|
    spec/support/matchers/model/model_have_error_on_field.rb11keys = record.errors.keys
    7.0 notes ↗

Ahead of 7.0

7.2

not needed for 7.0
  • Later
    Setting config.action_dispatch.show_exceptions to true or false was removed in Rails 7.2. Use :all (was true), :rescuable, or :none (was false).
    1 occurrence1 fileFix: low
    config/environments/test.rb31config.action_dispatch.show_exceptions = false
    7.2 notes ↗
  • Later
    Rails.application.secrets was removed in Rails 7.2. Use credentials, or Rails.application.config_for for non-secret settings.
    1 occurrence1 fileFix: medium
    config/routes.rb6Sidekiq::Web.set :session_secret, Rails.application.secrets[:secret_key_base]
    7.2 notes ↗
  • Later
    fixture_path was removed in Rails 7.2. Assign fixture_paths instead, which takes an array.
    1 occurrence, in a test1 fileFix: low
    spec/rails_helper.rb37config.fixture_path = "#{::Rails.root}/spec/fixtures"
    7.2 notes ↗

8.0

not needed for 7.0
  • Later
    Defining enum with keyword arguments was removed in Rails 8.0. Pass the name positionally, e.g. enum :status, { pending: 0 }.
    14 occurrences12 filesFix: low
    app/models/account.rb78enum protocol: [:ostatus, :activitypub]
    app/models/account.rb79enum suspension_origin: [:local, :remote], _prefix: true
    app/models/account_warning.rb16enum action: %i(none disable sensitive silence suspend), _suffix: :action
    app/models/domain_block.rb22enum severity: [:silence, :suspend, :noop]
    app/models/import.rb27enum type: [:following, :blocking, :muting, :domain_blocking, :bookmarks]
    app/models/ip_block.rb20enum severity: {
    app/models/list.rb19enum replies_policy: [:list, :followed, :none], _prefix: :show
    app/models/media_attachment.rb34enum type: [:image, :gifv, :video, :unknown, :audio]
    app/models/media_attachment.rb35enum processing: [:queued, :in_progress, :complete, :failed], _prefix: true
    app/models/preview_card.rb40enum type: [:link, :photo, :video, :rich]
    app/models/relay.rb17enum state: [:idle, :pending, :accepted, :rejected]
    app/models/status.rb47enum visibility: [:public, :unlisted, :private, :direct, :limited], _suffix: :visibility
    db/migrate/20190511134027_add_silenced_at_suspended_at_to_accounts.rb8enum severity: [:silence, :suspend, :noop]
    db/post_migrate/20190511152737_remove_suspended_silenced_account_fields.rb10enum severity: [:silence, :suspend, :noop]
    8.0 notes ↗

8.1

not needed for 7.0
  • Later
    STATS_DIRECTORIES was removed in Rails 8.1. Register extra directories with Rails::CodeStatistics.register_directory(Services, app/services).
    1 occurrence1 fileFix: low
    lib/tasks/statistics.rake16::STATS_DIRECTORIES << [name, Rails.root.join(dir)]
    8.1 notes ↗

Nothing in the code is removed by 7.1.

What this report can't see

Private Gems

Private gems (2): compatibility with Rails 7.0 is unknown

health_check · nilsimsa

Check each gemspec's Rails dependency, and bump them in the same step.

Docker Configuration

Could not detect a versioned ruby base image in Dockerfile.

Gem Compatibility

5 gems that depend on Rails had no release since before Rails 7.0 shipped (2021-12-15). Check they work on 7.0, or find replacements.

case_transform (last release 2016-09-22) · hamlit-rails (last release 2019-04-08) · rails-controller-testing (last release 2020-06-23) · makara (last release 2021-06-04) · pluck_each (last release 2021-09-21)

RailsBump or next_rails' bundle_report compatibility show which releases support 7.0.

Behavior changes

Some changes leave no telltale line: new framework defaults and changed query behavior.

Run the test suite with config.active_support.deprecation = :raise.

Multi-line code and test coverage

The scan matches single lines and never runs the app, so a call split across lines is missed, and it can't tell how much of the app the tests cover.

Treat a clean step as "nothing found", not "nothing there".