複数のフラグを1つのカラムで管理できるGem「flag_shih_tzu」の使い方とユースケース

こんにちは!kossyです!

今回は、複数のフラグを1つのカラムで管理できるGem「flag_shih_tzu」の使い方とユースケースについて、

備忘録としてブログに残してみたいと思います。

環境

flag_shih_tzu とは

Booleanを含んだ配列を、一つの整数として格納できるActiveRecordのエクステンションです。MySQL, PostgreSQLSQLite等、DBを問わず動作します。

使い方は簡単で、has_flagメソッドに、管理したいフラグ名を数値と共に渡すだけで実現できます。

ちなみに、「shih_tzu」の由来は犬の品種の一つである、「シーズー」から命名したらしいです。

使い方

まずはApplicationRecordを継承したモデルに FlagShihTzu モジュールをincludeします。

class Admin < ActiveRecord::Base
  include FlagShihTzu
end

次に、フラグを格納するカラムを作成するマイグレーションファイルを用意します。

  def change
    add_column :admins, :function_flags, :integer, default: 0, null: false, comment: '機能利用フラグ'
  end

次に、has_flagメソッドに数値と管理したいフラグ名をシンボルで渡します。

columnにカラム名を渡せば、渡したカラムでフラグを管理することができます。

class Admin < ActiveRecord::Base
  include FlagShihTzu

  has_flag(
    1 => :use_announcement,
    2 => :use_term_of_service_version,
    3 => :use_privacy_policy,
    :column => 'function_flags'
  )
end

これで準備完了です。

各種メソッド

上記の定義を行った場合、以下のインスタンスメソッドが定義されます。

Admin#all_features # [:use_announcement, :use_term_of_service_version, :use_privacy_policy]
Admin#selected_features
Admin#select_all_features
Admin#unselect_all_features
Admin#selected_features=

Admin#use_announcement
Admin#use_announcement?
Admin#use_announcement=
Admin#not_use_announcement
Admin#not_use_announcement?
Admin#not_use_announcement=
Admin#use_announcement_changed?
Admin#has_use_announcement?

Admin#use_term_of_service_version
Admin#use_term_of_service_version?
Admin#use_term_of_service_version=
Admin#not_use_term_of_service_version
Admin#not_use_term_of_service_version?
Admin#not_use_term_of_service_version=
Admin#use_term_of_service_version_changed?
Admin#has_use_term_of_service_version?

Admin#use_privacy_policy
Admin#use_privacy_policy?
Admin#use_privacy_policy=
Admin#not_use_privacy_policy
Admin#not_use_privacy_policy?
Admin#not_use_privacy_policy=
Admin#use_privacy_policy_changed?
Admin#use_privacy_policy?

また、以下のクラスメソッドも定義されます。

Admin.use_announcement         # :conditions => "(admins.function_flags in (1,3,5,7))"
Admin.not_use_announcement     # :conditions => "(admins.function_flags not in (1,3,5,7))"
Admin.use_term_of_service_version           # :conditions => "(admins.function_flags in (2,3,6,7))"
Admin.not_use_term_of_service_version       # :conditions => "(admins.function_flags not in (2,3,6,7))"
Admin.use_privacy_policy      # :conditions => "(admins.function_flags in (4,5,6,7))"
Admin.not_use_privacy_policy  # :conditions => "(admins.function_flags not in (4,5,6,7))"

他にも、callbackメソッドやフラグをupdateするメソッドも定義されますので、

より詳しく知りたい方はReadMeをご覧ください。

github.com

ユースケース

複数のフラグを1つのカラムで管理したくなる時がいつか?という観点で考えてみました。

1. 機能利用フラグを管理したい時

例えば管理者権限があるとして、管理者の中でも権限を弱くしたい、といったビジネス要求は往々にしてあります。

そういった際に機能ごとに使用権限を管理することになることが多いと思いますが、機能ごとにフラグのカラムを用意していくと、

機能が追加されるたびにフラグのカラムを追加することになり、管理コストが増します。

そういったケースで、このGemが役に立つのではないでしょうか。

他にもあると思うので随時更新します。

おわりに

実際に開発中のプロダクトでも、際限なく機能利用フラグが増えていっているので、すぐにでも導入したいと思いました。

既にたくさんのフラグが生えているテーブルからの移行については知見がまだないので、そういったケースでどう移行を実現するのか?は需要がありそうな気がしています。