scenic-views/scenic · error · ActiveRecord::IrreversibleMigration

#{method} is reversible only if given a revert_to_version

Error message

#{method} is reversible only if given a revert_to_version

What it means

When rolling back, ActiveRecord's command recorder replays recorded statements in reverse, and Scenic's invert_drop_view, invert_update_view, and invert_replace_view all funnel into perform_scenic_inversion. That method needs the revert_to_version keyword to know which db/views definition to restore; without it there is no way to reconstruct the prior view, so it raises ActiveRecord::IrreversibleMigration ('<method> is reversible only if given a revert_to_version') instead of guessing.

Source

Thrown at lib/scenic/command_recorder.rb:50

      perform_scenic_inversion(:create_view, args)
    end

    def invert_update_view(args)
      perform_scenic_inversion(:update_view, args)
    end

    def invert_replace_view(args)
      perform_scenic_inversion(:replace_view, args)
    end

    private

    def perform_scenic_inversion(method, args)
      scenic_args = StatementArguments.new(args)

      if scenic_args.revert_to_version.nil?
        message = "#{method} is reversible only if given a revert_to_version"
        raise ActiveRecord::IrreversibleMigration, message
      end

      [method, scenic_args.invert_version.to_a]
    end
  end
end

View on GitHub (pinned to f2162dbddb)

Solutions

  1. Edit the migration to add revert_to_version naming the version that existed before the change (drop_view :searches, revert_to_version: 3; update_view :searches, version: 2, revert_to_version: 1), then re-run db:rollback - the recorder reads the migration file at rollback time, so editing after the up-run is safe
  2. If the rollback already aborted, fix the file and rerun the same db:rollback or db:migrate:down command; nothing ran, so no schema repair is needed
  3. If the change is intentionally one-way, stop rolling back past it: bring the schema forward again with db:migrate instead

Example fix

# before
def change
  drop_view :searches
end
# db:rollback raises IrreversibleMigration

# after
def change
  drop_view :searches, revert_to_version: 3
end
Defensive patterns

Strategy: validation

Validate before calling

Dir[Rails.root.join('db/migrate/*.rb')].each do |file|
  src = File.read(file)
  next unless src =~ /(drop|update|replace)_view/
  abort file + ': scenic view change lacks revert_to_version (irreversible)' unless src.include?('revert_to_version:')
end

Try / catch

begin
  Rake::Task['db:rollback'].invoke
rescue ActiveRecord::IrreversibleMigration => e
  puts 'rollback aborted: ' + e.message
end

Prevention

When it happens

Trigger: Running rails db:rollback, db:migrate:down VERSION=..., db:migrate:redo, or a revert block after a migration used drop_view :searches, update_view :searches, version: 2, or replace_view :searches, version: 2 without a revert_to_version keyword.

Common situations: Hand-written migrations that encode only the forward path; developers who pair revert_to_version with update_view but forget it on drop_view; CI pipelines that smoke-test with db:migrate:redo and fail on the rollback leg.

Related errors


AI-assisted analysis of scenic-views/scenic@f2162dbddb (2026-08-23). Data as JSON: /api/errors/0a8d9114bae9ed3c. Report an issue: GitHub.