Class: ActiveRecord::Migrator

Inherits:
Object
  • Object
show all
Defined in:
lib/active_record/migration.rb

Overview

:nodoc:

Class Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(direction, migrations_paths, target_version = nil) ⇒ Migrator

Returns a new instance of Migrator.

Raises:

  • (StandardError)


645
646
647
648
649
# File 'lib/active_record/migration.rb', line 645

def initialize(direction, migrations_paths, target_version = nil)
  raise StandardError.new("This database does not yet support migrations") unless Base.connection.supports_migrations?
  Base.connection.initialize_schema_migrations_table
  @direction, @migrations_paths, @target_version = direction, migrations_paths, target_version
end

Class Attribute Details

.migrations_pathsObject



588
589
590
591
592
# File 'lib/active_record/migration.rb', line 588

def migrations_paths
  @migrations_paths ||= ['db/migrate']
  # just to not break things if someone uses: migration_path = some_string
  Array.wrap(@migrations_paths)
end

Class Method Details

.current_versionObject



574
575
576
577
578
579
580
581
# File 'lib/active_record/migration.rb', line 574

def current_version
  sm_table = schema_migrations_table_name
  if Base.connection.table_exists?(sm_table)
    get_all_versions.max || 0
  else
    0
  end
end

.down(migrations_paths, target_version = nil, &block) ⇒ Object



557
558
559
# File 'lib/active_record/migration.rb', line 557

def down(migrations_paths, target_version = nil, &block)
  self.new(:down, migrations_paths, target_version).migrate(&block)
end

.forward(migrations_paths, steps = 1) ⇒ Object



549
550
551
# File 'lib/active_record/migration.rb', line 549

def forward(migrations_paths, steps=1)
  move(:up, migrations_paths, steps)
end

.get_all_versionsObject



569
570
571
572
# File 'lib/active_record/migration.rb', line 569

def get_all_versions
  table = Arel::Table.new(schema_migrations_table_name)
  Base.connection.select_values(table.project(table['version'])).map{ |v| v.to_i }.sort
end

.migrate(migrations_paths, target_version = nil, &block) ⇒ Object



532
533
534
535
536
537
538
539
540
541
542
543
# File 'lib/active_record/migration.rb', line 532

def migrate(migrations_paths, target_version = nil, &block)
  case
    when target_version.nil?
      up(migrations_paths, target_version, &block)
    when current_version == 0 && target_version == 0
      []
    when current_version > target_version
      down(migrations_paths, target_version, &block)
    else
      up(migrations_paths, target_version, &block)
  end
end

.migrations(paths, *args) ⇒ Object



598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
# File 'lib/active_record/migration.rb', line 598

def migrations(paths, *args)
  if args.empty?
    subdirectories = true
  else
    subdirectories = args.first
    ActiveSupport::Deprecation.warn "The `subdirectories` argument to `migrations` is deprecated"
  end

  paths = Array.wrap(paths)

  glob = subdirectories ? "**/" : ""
  files = Dir[*paths.map { |p| "#{p}/#{glob}[0-9]*_*.rb" }]

  seen = Hash.new false

  migrations = files.map do |file|
    version, name, scope = file.scan(/([0-9]+)_([_a-z0-9]*)\.?([_a-z0-9]*)?.rb/).first

    raise IllegalMigrationNameError.new(file) unless version
    version = version.to_i
    name = name.camelize

    raise DuplicateMigrationVersionError.new(version) if seen[version]
    raise DuplicateMigrationNameError.new(name) if seen[name]

    seen[version] = seen[name] = true

    MigrationProxy.new(name, version, file, scope)
  end

  migrations.sort_by(&:version)
end

.migrations_pathObject



594
595
596
# File 'lib/active_record/migration.rb', line 594

def migrations_path
  migrations_paths.first
end

.proper_table_name(name) ⇒ Object



583
584
585
586
# File 'lib/active_record/migration.rb', line 583

def proper_table_name(name)
  # Use the Active Record objects own table_name, or pre/suffix from ActiveRecord::Base if name is a symbol/string
  name.table_name rescue "#{ActiveRecord::Base.table_name_prefix}#{name}#{ActiveRecord::Base.table_name_suffix}"
end

.rollback(migrations_paths, steps = 1) ⇒ Object



545
546
547
# File 'lib/active_record/migration.rb', line 545

def rollback(migrations_paths, steps=1)
  move(:down, migrations_paths, steps)
end

.run(direction, migrations_paths, target_version) ⇒ Object



561
562
563
# File 'lib/active_record/migration.rb', line 561

def run(direction, migrations_paths, target_version)
  self.new(direction, migrations_paths, target_version).run
end

.schema_migrations_table_nameObject



565
566
567
# File 'lib/active_record/migration.rb', line 565

def schema_migrations_table_name
  Base.table_name_prefix + 'schema_migrations' + Base.table_name_suffix
end

.up(migrations_paths, target_version = nil, &block) ⇒ Object



553
554
555
# File 'lib/active_record/migration.rb', line 553

def up(migrations_paths, target_version = nil, &block)
  self.new(:up, migrations_paths, target_version).migrate(&block)
end

Instance Method Details

#current_migrationObject



655
656
657
# File 'lib/active_record/migration.rb', line 655

def current_migration
  migrations.detect { |m| m.version == current_version }
end

#current_versionObject



651
652
653
# File 'lib/active_record/migration.rb', line 651

def current_version
  migrated.last || 0
end

#migrate(&block) ⇒ Object



668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
# File 'lib/active_record/migration.rb', line 668

def migrate(&block)
  current = migrations.detect { |m| m.version == current_version }
  target = migrations.detect { |m| m.version == @target_version }

  if target.nil? && @target_version && @target_version > 0
    raise UnknownMigrationVersionError.new(@target_version)
  end

  start = up? ? 0 : (migrations.index(current) || 0)
  finish = migrations.index(target) || migrations.size - 1
  runnable = migrations[start..finish]

  # skip the last migration if we're headed down, but not ALL the way down
  runnable.pop if down? && target

  ran = []
  runnable.each do |migration|
    if block && !block.call(migration)
      next
    end

    Base.logger.info "Migrating to #{migration.name} (#{migration.version})" if Base.logger

    seen = migrated.include?(migration.version.to_i)

    # On our way up, we skip migrating the ones we've already migrated
    next if up? && seen

    # On our way down, we skip reverting the ones we've never migrated
    if down? && !seen
      migration.announce 'never migrated, skipping'; migration.write
      next
    end

    begin
      ddl_transaction do
        migration.migrate(@direction)
        record_version_state_after_migrating(migration.version)
      end
      ran << migration
    rescue => e
      canceled_msg = Base.connection.supports_ddl_transactions? ? "this and " : ""
      raise StandardError, "An error has occurred, #{canceled_msg}all later migrations canceled:\n\n#{e}", e.backtrace
    end
  end
  ran
end

#migratedObject



728
729
730
# File 'lib/active_record/migration.rb', line 728

def migrated
  @migrated_versions ||= self.class.get_all_versions
end

#migrationsObject



716
717
718
719
720
721
# File 'lib/active_record/migration.rb', line 716

def migrations
  @migrations ||= begin
    migrations = self.class.migrations(@migrations_paths)
    down? ? migrations.reverse : migrations
  end
end

#pending_migrationsObject



723
724
725
726
# File 'lib/active_record/migration.rb', line 723

def pending_migrations
  already_migrated = migrated
  migrations.reject { |m| already_migrated.include?(m.version.to_i) }
end

#runObject



659
660
661
662
663
664
665
666
# File 'lib/active_record/migration.rb', line 659

def run
  target = migrations.detect { |m| m.version == @target_version }
  raise UnknownMigrationVersionError.new(@target_version) if target.nil?
  unless (up? && migrated.include?(target.version.to_i)) || (down? && !migrated.include?(target.version.to_i))
    target.migrate(@direction)
    record_version_state_after_migrating(target.version)
  end
end