Since I had a production application depending on this gem I wrote a large migration to move
from it to the new official flipper-active_record adapter gem. Posted here to help anyone who might face a similar struggle. This is a fully reversible migration.
I'm assuming you used the following original migration for flipper-activerecord:
class CreateFlipperTables < ActiveRecord::Migration
def self.up
create_table :flipper_features do |t|
t.string :name, null: false
t.timestamps null: false
end
add_index :flipper_features, :name, unique: true
create_table :flipper_gates do |t|
t.integer :flipper_feature_id, null: false
t.string :name, null: false
t.string :value
t.timestamps null: false
end
add_foreign_key :flipper_gates, :flipper_features, on_delete: :cascade
add_index :flipper_gates, [:flipper_feature_id, :name, :value], unique: true
end
def self.down
remove_foreign_key :flipper_gates, :flipper_features
drop_table :flipper_gates
drop_table :flipper_features
end
end
Again, I'm assuming you are moving to flipper-active_record which at the time of this writing uses the following migration:
class CreateFlipperTables < ActiveRecord::Migration
def self.up
create_table :flipper_features do |t|
t.string :key, null: false
t.timestamps null: false
end
add_index :flipper_features, :key, unique: true
create_table :flipper_gates do |t|
t.string :feature_key, null: false
t.string :key, null: false
t.string :value
t.timestamps null: false
end
add_index :flipper_gates, [:feature_key, :key, :value], unique: true
end
def self.down
drop_table :flipper_gates
drop_table :flipper_features
end
end
The two migrations are similar aside from the following changes necessary to be compatible with flipper-active_record:
flipper_features table uses key string over name string to identify the feature
flipper_gates table uses feature_key string over flipper_feature_id integer to reference the related flipper_features record
flipper_gates table uses key string over name string to identify the gate
there is no foreign key associating flipper_features and flipper_gates
Since I'm assuming that — like me — you had both existing flipper_features and flipper_gates records in production which you could not afford to wipe, here's the migration:
class MigrateToFlipperActiveRecord < ActiveRecord::Migration
# Create Migration classes to avoid relying on models that may not
# exist in the future. See:
# http://blog.testdouble.com/posts/2014-11-04-healthy-migration-habits
class MigrationFeature < ActiveRecord::Base
self.table_name = "flipper_features"
end
class MigrationGate < ActiveRecord::Base
self.table_name = "flipper_gates"
end
def up
# Add new columns and indices
add_column :flipper_features, :key, :string
# Migrate existing data to avoid errors when enabling null: false
MigrationFeature.all.find_each do |feature|
feature.update_attribute(:key, feature.name)
end
change_column_null :flipper_features, :key, false
add_column :flipper_gates, :key, :string
add_column :flipper_gates, :feature_key, :string
# Migrate existing data to avoid errors when enabling null: false
MigrationGate.all.find_each do |gate|
feature = MigrationFeature.find_by(id: gate.flipper_feature_id)
gate.update(key: gate.name, feature_key: feature.key)
end
change_column_null :flipper_gates, :key, false
change_column_null :flipper_gates, :feature_key, false
add_index :flipper_features, :key, unique: true
add_index :flipper_gates, [:feature_key, :key], unique: true
# Renove old columns (and indices automatically)
remove_column :flipper_features, :name
change_table :flipper_gates do |t|
t.remove :flipper_feature_id
t.remove :name
end
end
def down
# Add old columns and indices
add_column :flipper_features, :name, :string
# Migrate existing data to avoid errors when enabling null: false
MigrationFeature.all.find_each do |feature|
feature.update_attribute(:name, feature.key)
end
change_column_null :flipper_features, :name, false
add_index :flipper_features, :name, unique: true
add_column :flipper_gates, :flipper_feature_id, :integer
add_column :flipper_gates, :name, :string
# Migrate existing data to avoid errors when enabling null: false
MigrationGate.all.find_each do |gate|
feature = MigrationFeature.find_by(key: gate.feature_key)
gate.update(
flipper_feature_id: feature.id,
name: gate.key
)
end
change_column_null :flipper_gates, :flipper_feature_id, false
change_column_null :flipper_gates, :name, false
add_foreign_key :flipper_gates, :flipper_features,
on_delete: :cascade
add_index :flipper_gates, [:flipper_feature_id, :name],
unique: true
# Remove new columns (and indices automatically)
remove_column :flipper_features, :key
change_table :flipper_gates do |t|
t.remove :feature_key
t.remove :key
end
end
end
I've run this migration in both directions and checked state so it should be safe but I highly recommend testing in your development and staging environments before running it in production.
Since I had a production application depending on this gem I wrote a large migration to move from it to the new official flipper-active_record adapter gem. Posted here to help anyone who might face a similar struggle. This is a fully reversible migration.
I'm assuming you used the following original migration for flipper-activerecord:
Again, I'm assuming you are moving to
flipper-active_record
which at the time of this writing uses the following migration:The two migrations are similar aside from the following changes necessary to be compatible with
flipper-active_record
:flipper_features
table useskey
string overname
string to identify the featureflipper_gates
table usesfeature_key
string overflipper_feature_id
integer to reference the relatedflipper_features
recordflipper_gates
table useskey
string overname
string to identify the gateflipper_features
andflipper_gates
Since I'm assuming that — like me — you had both existing
flipper_features
andflipper_gates
records in production which you could not afford to wipe, here's the migration:I've run this migration in both directions and checked state so it should be safe but I highly recommend testing in your development and staging environments before running it in production.