forked from fixin.me/fixin.me
56 lines
2.5 KiB
Ruby
56 lines
2.5 KiB
Ruby
class DefaultSettingsStrategy < ActiveRecord::Migration::DefaultStrategy
|
|
COLUMN_DEFAULTS = {
|
|
# TODO: all types `null: false` ?
|
|
# TODO: references `foreign_key: {on_delete: :cascade}` ?
|
|
# `timestamps` - Rails defaults to `null: false, precision: true`.
|
|
# `limit:` for `text` - `text` can be theoretically up to 1GB or
|
|
# longer, so roughly unlimited for practical purposes. But:
|
|
# * the actual usable length depends on additional factors, like compile
|
|
# time limits (`SQLITE_MAX_LENGTH` in SQLite), runtime settings
|
|
# (`max_allowed_packet` in MySQL) and probably other,
|
|
# * Rails does not report limit for `text` column types, unless it is
|
|
# explicitly set.
|
|
# The decision is to always set safe limit and enforce it by validations, to
|
|
# avoid surprises (e.g. text truncation) when saving to dabatase.
|
|
text: {limit: 2**16 - 1}
|
|
}
|
|
COLUMN_DEFAULTS.default = {}
|
|
COLUMN_DEFAULTS.freeze
|
|
|
|
module ColumnSettingsStrategy
|
|
def column(name, type, **options)
|
|
super(name, type, **COLUMN_DEFAULTS[type].merge(options))
|
|
end
|
|
end
|
|
ActiveRecord::ConnectionAdapters::TableDefinition.prepend ColumnSettingsStrategy
|
|
|
|
# `force: :cascade` - does nothing on MySQL, so `force:` is useless.
|
|
# `if_not_exists: true`/`if_exists: true` - without these options it's impossible
|
|
# to change migration status once migration fails partially. If `up` migration
|
|
# creates some, but not all objects, its status is not updated from `down` to
|
|
# `up`. Then it's impossible to migrate: a) up - due to `already exists`
|
|
# errors and b) down - due to migration status.
|
|
MIGRATION_DEFAULTS = {
|
|
add_check_constraint: {if_not_exists: true},
|
|
add_column: {if_not_exists: true},
|
|
add_foreign_key: {if_not_exists: true},
|
|
add_index: {if_not_exists: true, unique: true},
|
|
add_timestamps: {if_not_exists: true},
|
|
create_table: {if_not_exists: true},
|
|
drop_table: {if_exists: true},
|
|
remove_check_constraint: {if_exists: true},
|
|
remove_column: {if_exists: true},
|
|
remove_foreign_key: {if_exists: true},
|
|
remove_index: {if_exists: true},
|
|
remove_timestamps: {if_exists: true},
|
|
}
|
|
MIGRATION_DEFAULTS.default = {}
|
|
MIGRATION_DEFAULTS.freeze
|
|
|
|
def method_missing(method, *args, **kwargs, &)
|
|
conflicts = kwargs.has_key?(:force) ? [:if_not_exists, :if_exists] : []
|
|
defaults = MIGRATION_DEFAULTS[method.to_sym].except(*conflicts)
|
|
super(method, *args, **defaults.merge(kwargs), &)
|
|
end
|
|
end
|