bgentry / flipper-activerecord Goto Github PK
View Code? Open in Web Editor NEWDEPRECATED - A Flipper adapter for ActiveRecord
License: MIT License
DEPRECATED - A Flipper adapter for ActiveRecord
License: MIT License
It is documented as such, but I did not have a clear expectation in the test (since added here flippercloud/flipper#106). This line should only clear the gates like this, not the entire feature, or you end up with behavior like this flippercloud/flipper#104 in the flipper UI.
Every time when enabled?
gets called, flipper makes multiple network round trips to the database.
Instead, we can get all features in one query and cache it during the same HTTP request-response cycle, so that following enabled?
check will be done without hitting the database. It makes sense to most typical Rails apps.
This change has several implications and trade-offs between time and space at scale:
Would this be something we're interested in?
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 featureflipper_gates
table uses feature_key
string over flipper_feature_id
integer to reference the related flipper_features
recordflipper_gates
table uses key
string over name
string to identify the gateflipper_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.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.