Class: AfterMigrate::Configuration

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

Constant Summary collapse

MIGRATION_TASK_PATTERN =

Task names that mean "this process is applying schema changes". Matches db:migrate, db:migrate:up, db:rollback, apartment:migrate, db:schema:load, after_migrate:* -- and deliberately NOT db:seed, assets:precompile, server, console, or a bare Sidekiq command line.

/
  (?:\A|:)(?:migrate|rollback)(?::|\z)
  | \Adb:(?:schema|structure):load\z
  | \Aafter_migrate:
/x

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initializeConfiguration

Resolved here, not in a host app's config/initializers/*.rb.

Railtie initializers run BEFORE :load_config_initializers (Rails::Application#ordered_railties pushes the application last), so by the time an app calls AfterMigrate.configure, our railtie has already decided whether to subscribe. An app setting config.enabled = false therefore could NOT switch the subscription off -- the only value the railtie ever sees is this one.

Off outside migrations: leaving this armed in every web and worker process.



77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
# File 'lib/after_migrate.rb', line 77

def initialize
  @enabled = self.class.resolve_enabled
  @verbose = true
  @vacuum = true
  @analyze = 'only_affected_tables'
  @rake_tasks_enhanced = true
  @defer = true
  # Store failures degrade to a warning by default; they must not abort a migration.
  @raise_on_store_error = false
  @store = :memory
  @run_id = ENV.fetch('AFTER_MIGRATE_RUN_ID', 'default')
  @store_options = {
    file: {
      path: 'tmp/after_migrate/affected_tables.json'
    },
    redis: {
      client: nil,
      key_prefix: 'after_migrate',
      ttl: 24 * 60 * 60
    }
  }
end

Instance Attribute Details

#analyzeObject

Returns the value of attribute analyze.



11
12
13
# File 'lib/after_migrate.rb', line 11

def analyze
  @analyze
end

#deferObject

Returns the value of attribute defer.



11
12
13
# File 'lib/after_migrate.rb', line 11

def defer
  @defer
end

#enabledObject

Returns the value of attribute enabled.



11
12
13
# File 'lib/after_migrate.rb', line 11

def enabled
  @enabled
end

#raise_on_store_errorObject

Returns the value of attribute raise_on_store_error.



11
12
13
# File 'lib/after_migrate.rb', line 11

def raise_on_store_error
  @raise_on_store_error
end

#rake_tasks_enhancedObject

Returns the value of attribute rake_tasks_enhanced.



11
12
13
# File 'lib/after_migrate.rb', line 11

def rake_tasks_enhanced
  @rake_tasks_enhanced
end

#run_idObject

Returns the value of attribute run_id.



11
12
13
# File 'lib/after_migrate.rb', line 11

def run_id
  @run_id
end

#storeObject

Returns the value of attribute store.



11
12
13
# File 'lib/after_migrate.rb', line 11

def store
  @store
end

#store_optionsObject

Returns the value of attribute store_options.



11
12
13
# File 'lib/after_migrate.rb', line 11

def store_options
  @store_options
end

#vacuumObject

Returns the value of attribute vacuum.



11
12
13
# File 'lib/after_migrate.rb', line 11

def vacuum
  @vacuum
end

#verboseObject

Returns the value of attribute verbose.



11
12
13
# File 'lib/after_migrate.rb', line 11

def verbose
  @verbose
end

Class Method Details

.env_overrideObject

nil when unset/blank so "not configured" stays distinguishable from "configured false".



41
42
43
44
45
46
# File 'lib/after_migrate.rb', line 41

def env_override
  raw = ENV['AFTER_MIGRATE_ENABLED'].to_s.strip
  return nil if raw.empty?

  raw.casecmp('true').zero?
end

.migration_task?Boolean

Returns:

  • (Boolean)


48
49
50
# File 'lib/after_migrate.rb', line 48

def migration_task?
  task_names.any? { |name| MIGRATION_TASK_PATTERN.match?(name) }
end

.resolve_enabledObject

Three states, so the common case needs no configuration at all:

AFTER_MIGRATE_ENABLED=true    -> always on  (force it, e.g. from a console)
AFTER_MIGRATE_ENABLED=false   -> always off (explicit opt-out always wins)
unset                         -> ON only while running migrations

Auto-detection is safe because a web or worker process never has a migration task on its command line, so the gem simply never arms itself there.



33
34
35
36
37
38
# File 'lib/after_migrate.rb', line 33

def resolve_enabled
  override = env_override
  return override unless override.nil?

  migration_task?
end

.task_namesObject

Rake's parsed task list is the reliable source (rails db:migrate dispatches through Rake and the environment is loaded by the environment prerequisite, so top_level_tasks is already populated by the time our railtie runs). ARGV is the belt-and-braces fallback for rake db:migrate and for anything that bypasses Rake's parser.



56
57
58
59
60
61
62
63
64
65
66
# File 'lib/after_migrate.rb', line 56

def task_names
  names = []
  if defined?(::Rake) && ::Rake.respond_to?(:application)
    top_level = ::Rake.application.top_level_tasks
    names.concat(Array(top_level))
  end
  names.concat(Array(ARGV))
  names.map(&:to_s)
rescue StandardError
  Array(ARGV).map(&:to_s)
end

Instance Method Details

#redisObject



108
109
110
# File 'lib/after_migrate.rb', line 108

def redis
  store_options_for(:redis)[:client]
end

#redis=(value) ⇒ Object



112
113
114
# File 'lib/after_migrate.rb', line 112

def redis=(value)
  store_options_for(:redis)[:client] = value
end

#redis_key_prefixObject



116
117
118
# File 'lib/after_migrate.rb', line 116

def redis_key_prefix
  store_options_for(:redis)[:key_prefix]
end

#redis_key_prefix=(value) ⇒ Object



120
121
122
# File 'lib/after_migrate.rb', line 120

def redis_key_prefix=(value)
  store_options_for(:redis)[:key_prefix] = value
end

#redis_ttlObject



124
125
126
# File 'lib/after_migrate.rb', line 124

def redis_ttl
  store_options_for(:redis)[:ttl]
end

#redis_ttl=(value) ⇒ Object



128
129
130
# File 'lib/after_migrate.rb', line 128

def redis_ttl=(value)
  store_options_for(:redis)[:ttl] = value
end

#store_options_for(store_name) ⇒ Object



132
133
134
# File 'lib/after_migrate.rb', line 132

def store_options_for(store_name)
  store_options[store_name.to_sym] ||= {}
end

#store_pathObject



100
101
102
# File 'lib/after_migrate.rb', line 100

def store_path
  store_options_for(:file)[:path]
end

#store_path=(value) ⇒ Object



104
105
106
# File 'lib/after_migrate.rb', line 104

def store_path=(value)
  store_options_for(:file)[:path] = value
end