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)


632
633
634
635
636
# File 'lib/active_record/migration.rb', line 632

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



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

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



569
570
571
572
573
574
575
576
# File 'lib/active_record/migration.rb', line 569

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) ⇒ Object



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

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

.forward(migrations_paths, steps = 1) ⇒ Object



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

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

.get_all_versionsObject



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

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) ⇒ Object



527
528
529
530
531
532
533
534
535
536
537
538
# File 'lib/active_record/migration.rb', line 527

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

.migrations(paths) ⇒ Object



593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
# File 'lib/active_record/migration.rb', line 593

def migrations(paths)
  paths = Array.wrap(paths)

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

  seen = Hash.new false

  migrations = files.map do |file|
    version, name = file.scan(/([0-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)
  end

  migrations.sort_by(&:version)
end

.migrations_pathObject



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

def migrations_path
  migrations_paths.first
end

.proper_table_name(name) ⇒ Object



578
579
580
581
# File 'lib/active_record/migration.rb', line 578

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



540
541
542
# File 'lib/active_record/migration.rb', line 540

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

.run(direction, migrations_paths, target_version) ⇒ Object



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

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

.schema_migrations_table_nameObject



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

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

.up(migrations_paths, target_version = nil) ⇒ Object



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

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

Instance Method Details

#current_migrationObject



642
643
644
# File 'lib/active_record/migration.rb', line 642

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

#current_versionObject



638
639
640
# File 'lib/active_record/migration.rb', line 638

def current_version
  migrated.last || 0
end

#migrateObject



655
656
657
658
659
660
661
662
663
664
665
666
667
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
# File 'lib/active_record/migration.rb', line 655

def migrate
  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|
    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



711
712
713
# File 'lib/active_record/migration.rb', line 711

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

#migrationsObject



699
700
701
702
703
704
# File 'lib/active_record/migration.rb', line 699

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

#pending_migrationsObject



706
707
708
709
# File 'lib/active_record/migration.rb', line 706

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

#runObject



646
647
648
649
650
651
652
653
# File 'lib/active_record/migration.rb', line 646

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