Class: SlashMigrate::MigrationFileWriter

Inherits:
Object
  • Object
show all
Defined in:
app/services/slash_migrate/migration_file_writer.rb

Overview

Writes a migration file on behalf of every builder, so file creation is collision-safe in one place:

- the version is collision-free (mirrors Rails' own next_migration_number),
  so two migrations generated in the same second still get distinct,
  ordered versions rather than clashing;
- the write is exclusive, so a re-submitted form can't clobber a file;
- a second pending migration with the same name is refused, since duplicate
  migration classes break db:migrate — caught here with a clear message
  instead of a cryptic failure when the student runs it.

Constant Summary collapse

DuplicateError =
Class.new(StandardError)

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(basename:, source:) ⇒ MigrationFileWriter

basename: the slug with no version and no extension, e.g. “create_posts”.



20
21
22
23
# File 'app/services/slash_migrate/migration_file_writer.rb', line 20

def initialize(basename:, source:)
  @basename = basename
  @source = source
end

Class Method Details

.write(basename:, source:) ⇒ Object



15
16
17
# File 'app/services/slash_migrate/migration_file_writer.rb', line 15

def self.write(basename:, source:)
  new(basename: basename, source: source).write
end

Instance Method Details

#writeObject



25
26
27
28
29
30
31
32
33
34
35
36
37
# File 'app/services/slash_migrate/migration_file_writer.rb', line 25

def write
  if (existing = existing_with_same_name)
    raise DuplicateError, "A migration named #{@basename.camelize} already exists (#{existing}). " \
      "Run or delete it before generating another."
  end

  path = migrate_dir.join("#{next_version}_#{@basename}.rb")
  # A brand-new app has no db/migrate until its first migration — and that
  # first migration is exactly what a student generates here — so create it.
  migrate_dir.mkpath
  path.open(File::WRONLY | File::CREAT | File::EXCL) { |file| file.write(@source) }
  path.relative_path_from(Rails.root).to_s
end