RailsでFeature Flags (Flipper)を使ってみる

September 04, 2022

これは何?

Rails で Feature Flags (Feature Toggles) を導入するため、Flipper (gem) を使ってみます。

確認環境

$ bundle exec ruby --version
ruby 2.7.5p203 (2021-11-24 revision f69aeb8314) [x86_64-darwin19]
$ bundle exec rails --version
Rails 6.0.4.6

インストール

Gemfile

# For flipper
gem 'flipper'
gem 'flipper-active_record'
$ bundle install
$ bundle exec rails g flipper:active_record
      create  db/migrate/20220813075433_create_flipper_tables.rb

$ bundle exec rails db:migrate
== 20220813075433 CreateFlipperTables: migrating ==============================
-- create_table(:flipper_features)
   -> 0.0029s
-- add_index(:flipper_features, :key, {:unique=>true})
   -> 0.0013s
-- create_table(:flipper_gates)
   -> 0.0012s
-- add_index(:flipper_gates, [:feature_key, :key, :value], {:unique=>true})
   -> 0.0013s
== 20220813075433 CreateFlipperTables: migrated (0.0076s) =====================

使ってみる

全体

$ rails c
...
irb(main):009:0> Flipper.enabled? :search
  Flipper::Adapters::ActiveRecord::Gate Load (0.2ms)  SELECT "flipper_gates".* FROM "flipper_gates" WHERE "flipper_gates"."feature_key" = ?  [["feature_key", "search"]]
  Flipper feature(search) enabled? false (0.8ms)  [ thing=nil ]
=> false
irb(main):010:0> Flipper.enable :search
   (0.1ms)  begin transaction
  Flipper::Adapters::ActiveRecord::Feature Load (0.1ms)  SELECT "flipper_features".* FROM "flipper_features" WHERE "flipper_features"."key" = ? ORDER BY "flipper_features"."id" ASC LIMIT ?  [["key", "search"], ["LIMIT", 1]]
   (0.0ms)  commit transaction
   (0.0ms)  begin transaction
  Flipper::Adapters::ActiveRecord::Gate Load (0.1ms)  SELECT "flipper_gates".* FROM "flipper_gates" WHERE "flipper_gates"."feature_key" = ?  [["feature_key", "search"]]
  Flipper::Adapters::ActiveRecord::Gate Load (0.1ms)  SELECT "flipper_gates".* FROM "flipper_gates" WHERE "flipper_gates"."feature_key" = ? AND "flipper_gates"."key" = ?  [["feature_key", "search"], ["key", "boolean"]]
  Flipper::Adapters::ActiveRecord::Gate Create (1.1ms)  INSERT INTO "flipper_gates" ("feature_key", "key", "value", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?)  [["feature_key", "search"], ["key", "boolean"], ["value", "true"], ["created_at", "2022-08-28 15:47:53.857786"], ["updated_at", "2022-08-28 15:47:53.857786"]]
   (0.8ms)  commit transaction
  Flipper feature(search) enable true (5.5ms)  [ thing=#<Flipper::Types::Boolean:0x00007f829903c550 @value=true> gate_name=boolean ]
=> true
irb(main):011:0> Flipper.enabled? :search
  Flipper::Adapters::ActiveRecord::Gate Load (0.1ms)  SELECT "flipper_gates".* FROM "flipper_gates" WHERE "flipper_gates"."feature_key" = ?  [["feature_key", "search"]]
  Flipper feature(search) enabled? true (0.8ms)  [ thing=nil gate_name=boolean ]
=> true

特定のユーザーだけ指定

$ rails c
...
irb(main):024:0> u = User.last
  User Load (0.1ms)  SELECT "users".* FROM "users" ORDER BY "users"."id" DESC LIMIT ?  [["LIMIT", 1]]
=> #<User id: 1, email: "xxxxx@example.com", created_at: "2022-08-28 04:31:57", updated_at: "2022-08-28 04:31:57">
irb(main):025:0> Flipper.enabled? :search, u
  Flipper::Adapters::ActiveRecord::Gate Load (0.1ms)  SELECT "flipper_gates".* FROM "flipper_gates" WHERE "flipper_gates"."feature_key" = ?  [["feature_key", "search"]]
  Flipper feature(search) enabled? false (0.9ms)  [ thing=#<Flipper::Types::Actor:0x00007f8299209770 @thing=#<User id: 1, email: "xxxxx@example.com", created_at: "2022-08-28 04:31:57", updated_at: "2022-08-28 04:31:57">, @value="User;1"> ]
=> false
irb(main):026:0> Flipper.enable_actor :search, u
   (0.1ms)  begin transaction
  Flipper::Adapters::ActiveRecord::Feature Load (0.1ms)  SELECT "flipper_features".* FROM "flipper_features" WHERE "flipper_features"."key" = ? ORDER BY "flipper_features"."id" ASC LIMIT ?  [["key", "search"], ["LIMIT", 1]]
   (0.0ms)  commit transaction
   (0.0ms)  begin transaction
  Flipper::Adapters::ActiveRecord::Gate Create (0.4ms)  INSERT INTO "flipper_gates" ("feature_key", "key", "value", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?)  [["feature_key", "search"], ["key", "actors"], ["value", "User;1"], ["created_at", "2022-08-28 15:51:58.809694"], ["updated_at", "2022-08-28 15:51:58.809694"]]
   (0.7ms)  commit transaction
  Flipper feature(search) enable true (3.0ms)  [ thing=#<Flipper::Types::Actor:0x00007f8296df6950 @thing=#<User id: 1, email: "xxxxx@example.com", created_at: "2022-08-28 04:31:57", updated_at: "2022-08-28 04:31:57">, @value="User;1"> gate_name=actor ]
=> true
irb(main):027:0> Flipper.enabled? :search, u
  Flipper::Adapters::ActiveRecord::Gate Load (0.2ms)  SELECT "flipper_gates".* FROM "flipper_gates" WHERE "flipper_gates"."feature_key" = ?  [["feature_key", "search"]]
  Flipper feature(search) enabled? true (0.9ms)  [ thing=#<Flipper::Types::Actor:0x00007f8291b780c0 @thing=#<User id: 1, email: "xxxxx@example.com", created_at: "2022-08-28 04:31:57", updated_at: "2022-08-28 04:31:57">, @value="User;1"> gate_name=actor ]
=> true

パーセント指定

$ rails c
...
irb(main):024:0> u = User.last
  User Load (0.1ms)  SELECT "users".* FROM "users" ORDER BY "users"."id" DESC LIMIT ?  [["LIMIT", 1]]
=> #<User id: 1, email: "xxxxx@example.com", created_at: "2022-08-28 04:31:57", updated_at: "2022-08-28 04:31:57">
irb(main):030:0> Flipper.enabled? :search, u
  Flipper::Adapters::ActiveRecord::Gate Load (0.2ms)  SELECT "flipper_gates".* FROM "flipper_gates" WHERE "flipper_gates"."feature_key" = ?  [["feature_key", "search"]]
  Flipper feature(search) enabled? false (1.0ms)  [ thing=#<Flipper::Types::Actor:0x00007f8296fd3b10 @thing=#<User id: 1, email: "xxxxx@example.com", created_at: "2022-08-28 04:31:57", updated_at: "2022-08-28 04:31:57">, @value="User;1"> ]
=> false

どうやら、パーセント指定の時は、Zlib.crc32 を使っているようでした。

参考


SHARE

Profile picture

Written by tamesuu