Skip to content

Feature Toggleのために、flipper gemを導入#8804

Merged
komagata merged 4 commits intomainfrom
feature/feature-toggle
Jul 11, 2025
Merged

Feature Toggleのために、flipper gemを導入#8804
komagata merged 4 commits intomainfrom
feature/feature-toggle

Conversation

@masyuko0222
Copy link
Copy Markdown
Contributor

@masyuko0222 masyuko0222 commented Jun 16, 2025

Issue

概要

ドキュメントとしてまとめています。
上記はリリース後に、BootcampWikiで公開予定です。

変更確認方法

前提: feature/feature-toggleをローカルに取り込む

Controllerの制御確認

  1. app/controllers/users_controller.rbのコードを以下のようにする
class UsersController < ApplicationController # rubocop:todo Metrics/ClassLength
  skip_before_action :require_active_user_login, raise: false, only: %i[new create show]
  before_action :require_token, only: %i[new] if Rails.env.production?
  before_action :set_user, only: %w[show]
  before_action -> { authorize_feature(:users, [User.find_by(login_name: 'kensyu')]) } # 付け足す
  before_action -> { authorized_feature!(:users) } # 付け足す

  PAGER_NUMBER = 24

  def index
    @target = params[:target]
    ...
  1. ユーザー名:kensyuでログイン
  2. /usersにアクセス
  • ユーザー一覧が閲覧できること
  1. ログアウトし、ユーザー名:kimuraでログイン
  2. /usersにアクセス
  • 以下の画面になり、ユーザー一覧が閲覧できないこと

image

Viewの制御確認

  1. app/controllers/users_controller.rbのコードを以下のようにする
class UsersController < ApplicationController # rubocop:todo Metrics/ClassLength
  skip_before_action :require_active_user_login, raise: false, only: %i[new create show]
  before_action :require_token, only: %i[new] if Rails.env.production?
  before_action :set_user, only: %w[show]
  before_action -> { authorize_feature(:users, [User.find_by(login_name: 'kensyu')]) } # 付け足す

  PAGER_NUMBER = 24

  def index
    @target = params[:target]
    ...
  1. app/views/application/_global_nav.slimのコードを以下のようにする
- if authorized_feature?(:users) // 付け足す
  li.global-nav-links__item
    = link_to users_path, class: "global-nav-links__link #{current_link(/^users-(index|show)/)}" do
      .global-nav-links__link-icon
        i.fa-solid.fa-users
      .global-nav-links__link-label ユーザー
  1. ユーザー名:kensyuでログイン
  2. /(ルートページ)にアクセス
  • 左側のナビゲーションに、ユーザー一覧へのリンクが表示されていること

image

  1. ログアウトし、ユーザー名:kimuraでログイン
  2. /(ルートページ)にアクセス
  • 左側のナビゲーションに、ユーザー一覧へのリンクが表示されていないこと

Summary by CodeRabbit

  • 新機能

    • フィーチャーフラグ管理のためのFlipper機能を導入しました。
    • コントローラでフィーチャートグル機能が利用可能になりました。
    • 特定ユーザーやグループ向けに機能の有効化・無効化が可能になりました。
  • ドキュメント

    • Flipperの設定例やカスタマイズ方法のコメント付きテンプレートを追加しました。
  • テスト

    • フィーチャートグル機能の動作確認テストを追加しました。
  • その他

    • 必要なデータベーステーブルを追加しました。
    • 新しいgem依存関係(flipper-active_record)を追加しました。

@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Jun 16, 2025

## Walkthrough

Flipperによるフィーチャートグル(機能切り替え)機能がRailsアプリケーションに導入されました。新たなGem依存追加、初期化ファイルやDBマイグレーションの追加、コントローラ共通関心事(concern)としての機能実装、テストコード追加、設定ファイルの調整が行われています。

## Changes

| ファイル/グループ                                         | 変更概要                                                                                           |
|----------------------------------------------------------|----------------------------------------------------------------------------------------------------|
| .traceroute.yml                                          | `ignore_unreachable_actions`リストに3つのパターン(feature認可関連メソッド)を追加                   |
| Gemfile                                                  | `flipper-active_record`(約1.3系)Gem依存を追加                                                     |
| app/controllers/application_controller.rb                | `FeatureToggle`モジュールをインクルード                                                             |
| app/controllers/concerns/feature_toggle.rb               | Flipperを使ったフィーチャートグル機能のconcernを新規追加。認可メソッド(`authorized_feature?`, `authorized_feature!`, `authorize_feature`)を定義 |
| config/initializers/flipper.rb                           | Flipper初期化ファイルを新規追加(全てコメントアウト例。設定テンプレートのみ)                        |
| db/migrate/20250616101406_create_flipper_tables.rb       | Flipper用テーブル(`flipper_features`, `flipper_gates`)を作成するマイグレーションを新規追加          |
| db/schema.rb                                             | 上記2テーブルのスキーマを反映                                                                       |
| test/controllers/concerns/feature_toggle_test.rb         | `FeatureToggle` concernの統合テストを新規追加。認可メソッドの動作検証を含む                            |

## Sequence Diagram(s)

```mermaid
sequenceDiagram
    participant User
    participant Controller
    participant FeatureToggle
    participant Flipper

    User->>Controller: アクションをリクエスト
    Controller->>FeatureToggle: authorized_feature?(feature_key)
    FeatureToggle->>Flipper: 機能有効判定
    Flipper-->>FeatureToggle: 有効/無効
    FeatureToggle-->>Controller: 判定結果
    Controller-->>User: レスポンス(許可または"Feature disabled"エラー)

Poem

🐰
新しい機能、トグルでピョン!
うさぎもワクワク、切り替えボタン。
Flipperの魔法で、世界が変わる。
テストも完璧、安心の春。
ぴょんぴょん跳ねて、コードも軽やか!


<!-- walkthrough_end -->
<!-- This is an auto-generated comment: all tool run failures by coderabbit.ai -->

> [!WARNING]
> There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure.
> 
> <details>
> <summary>🔧 RuboCop (1.75.5)</summary>
> 
> <details>
> <summary>Gemfile</summary>
> 
> rubocop-minitest extension supports plugin, specify `plugins: rubocop-minitest` instead of `require: rubocop-minitest` in /.rubocop.yml.
> For more information, see https://docs.rubocop.org/rubocop/plugin_migration_guide.html.
> rubocop-capybara extension supports plugin, specify `plugins: rubocop-capybara` instead of `require: rubocop-capybara` in /.rubocop.yml.
> For more information, see https://docs.rubocop.org/rubocop/plugin_migration_guide.html.
> Unable to find gem rubocop-fjord; is the gem installed? Gem::MissingSpecError
> /var/lib/gems/3.1.0/gems/rubocop-1.77.0/lib/rubocop/config_loader_resolver.rb:309:in `rescue in gem_config_path'
> /var/lib/gems/3.1.0/gems/rubocop-1.77.0/lib/rubocop/config_loader_resolver.rb:293:in `gem_config_path'
> /var/lib/gems/3.1.0/gems/rubocop-1.77.0/lib/rubocop/config_loader_resolver.rb:84:in `block (2 levels) in resolve_inheritance_from_gems'
> /var/lib/gems/3.1.0/gems/rubocop-1.77.0/lib/rubocop/config_loader_resolver.rb:82:in `reverse_each'
> /var/lib/gems/3.1.0/gems/rubocop-1.77.0/lib/rubocop/config_loader_resolver.rb:82:in `block in resolve_inheritance_from_gems'
> /var/lib/gems/3.1.0/gems/rubocop-1.77.0/lib/rubocop/config_loader_resolver.rb:76:in `each_pair'
> /var/lib/gems/3.1.0/gems/rubocop-1.77.0/lib/rubocop/config_loader_resolver.rb:76:in `resolve_inheritance_from_gems'
> /var/lib/gems/3.1.0/gems/rubocop-1.77.0/lib/rubocop/config_loader.rb:66:in `load_file'
> /var/lib/gems/3.1.0/gems/rubocop-1.77.0/lib/rubocop/config_store.rb:29:in `options_config='
> /var/lib/gems/3.1.0/gems/rubocop-1.77.0/lib/rubocop/cli.rb:160:in `act_on_options'
> /var/lib/gems/3.1.0/gems/rubocop-1.77.0/lib/rubocop/cli.rb:47:in `block in run'
> /var/lib/gems/3.1.0/gems/rubocop-1.77.0/lib/rubocop/cli.rb:81:in `profile_if_needed'
> /var/lib/gems/3.1.0/gems/rubocop-1.77.0/lib/rubocop/cli.rb:43:in `run'
> /var/lib/gems/3.1.0/gems/rubocop-1.77.0/exe/rubocop:19:in `<top (required)>'
> /usr/local/bin/rubocop:25:in `load'
> /usr/local/bin/rubocop:25:in `<main>'
> 
> </details>
> 
> <details>
> <summary>test/controllers/concerns/feature_toggle_test.rb</summary>
> 
> rubocop-minitest extension supports plugin, specify `plugins: rubocop-minitest` instead of `require: rubocop-minitest` in /.rubocop.yml.
> For more information, see https://docs.rubocop.org/rubocop/plugin_migration_guide.html.
> rubocop-capybara extension supports plugin, specify `plugins: rubocop-capybara` instead of `require: rubocop-capybara` in /.rubocop.yml.
> For more information, see https://docs.rubocop.org/rubocop/plugin_migration_guide.html.
> Unable to find gem rubocop-fjord; is the gem installed? Gem::MissingSpecError
> /var/lib/gems/3.1.0/gems/rubocop-1.77.0/lib/rubocop/config_loader_resolver.rb:309:in `rescue in gem_config_path'
> /var/lib/gems/3.1.0/gems/rubocop-1.77.0/lib/rubocop/config_loader_resolver.rb:293:in `gem_config_path'
> /var/lib/gems/3.1.0/gems/rubocop-1.77.0/lib/rubocop/config_loader_resolver.rb:84:in `block (2 levels) in resolve_inheritance_from_gems'
> /var/lib/gems/3.1.0/gems/rubocop-1.77.0/lib/rubocop/config_loader_resolver.rb:82:in `reverse_each'
> /var/lib/gems/3.1.0/gems/rubocop-1.77.0/lib/rubocop/config_loader_resolver.rb:82:in `block in resolve_inheritance_from_gems'
> /var/lib/gems/3.1.0/gems/rubocop-1.77.0/lib/rubocop/config_loader_resolver.rb:76:in `each_pair'
> /var/lib/gems/3.1.0/gems/rubocop-1.77.0/lib/rubocop/config_loader_resolver.rb:76:in `resolve_inheritance_from_gems'
> /var/lib/gems/3.1.0/gems/rubocop-1.77.0/lib/rubocop/config_loader.rb:66:in `load_file'
> /var/lib/gems/3.1.0/gems/rubocop-1.77.0/lib/rubocop/config_store.rb:29:in `options_config='
> /var/lib/gems/3.1.0/gems/rubocop-1.77.0/lib/rubocop/cli.rb:160:in `act_on_options'
> /var/lib/gems/3.1.0/gems/rubocop-1.77.0/lib/rubocop/cli.rb:47:in `block in run'
> /var/lib/gems/3.1.0/gems/rubocop-1.77.0/lib/rubocop/cli.rb:81:in `profile_if_needed'
> /var/lib/gems/3.1.0/gems/rubocop-1.77.0/lib/rubocop/cli.rb:43:in `run'
> /var/lib/gems/3.1.0/gems/rubocop-1.77.0/exe/rubocop:19:in `<top (required)>'
> /usr/local/bin/rubocop:25:in `load'
> /usr/local/bin/rubocop:25:in `<main>'
> 
> </details>
> 
> <details>
> <summary>app/controllers/application_controller.rb</summary>
> 
> rubocop-minitest extension supports plugin, specify `plugins: rubocop-minitest` instead of `require: rubocop-minitest` in /.rubocop.yml.
> For more information, see https://docs.rubocop.org/rubocop/plugin_migration_guide.html.
> rubocop-capybara extension supports plugin, specify `plugins: rubocop-capybara` instead of `require: rubocop-capybara` in /.rubocop.yml.
> For more information, see https://docs.rubocop.org/rubocop/plugin_migration_guide.html.
> Unable to find gem rubocop-fjord; is the gem installed? Gem::MissingSpecError
> /var/lib/gems/3.1.0/gems/rubocop-1.77.0/lib/rubocop/config_loader_resolver.rb:309:in `rescue in gem_config_path'
> /var/lib/gems/3.1.0/gems/rubocop-1.77.0/lib/rubocop/config_loader_resolver.rb:293:in `gem_config_path'
> /var/lib/gems/3.1.0/gems/rubocop-1.77.0/lib/rubocop/config_loader_resolver.rb:84:in `block (2 levels) in resolve_inheritance_from_gems'
> /var/lib/gems/3.1.0/gems/rubocop-1.77.0/lib/rubocop/config_loader_resolver.rb:82:in `reverse_each'
> /var/lib/gems/3.1.0/gems/rubocop-1.77.0/lib/rubocop/config_loader_resolver.rb:82:in `block in resolve_inheritance_from_gems'
> /var/lib/gems/3.1.0/gems/rubocop-1.77.0/lib/rubocop/config_loader_resolver.rb:76:in `each_pair'
> /var/lib/gems/3.1.0/gems/rubocop-1.77.0/lib/rubocop/config_loader_resolver.rb:76:in `resolve_inheritance_from_gems'
> /var/lib/gems/3.1.0/gems/rubocop-1.77.0/lib/rubocop/config_loader.rb:66:in `load_file'
> /var/lib/gems/3.1.0/gems/rubocop-1.77.0/lib/rubocop/config_store.rb:29:in `options_config='
> /var/lib/gems/3.1.0/gems/rubocop-1.77.0/lib/rubocop/cli.rb:160:in `act_on_options'
> /var/lib/gems/3.1.0/gems/rubocop-1.77.0/lib/rubocop/cli.rb:47:in `block in run'
> /var/lib/gems/3.1.0/gems/rubocop-1.77.0/lib/rubocop/cli.rb:81:in `profile_if_needed'
> /var/lib/gems/3.1.0/gems/rubocop-1.77.0/lib/rubocop/cli.rb:43:in `run'
> /var/lib/gems/3.1.0/gems/rubocop-1.77.0/exe/rubocop:19:in `<top (required)>'
> /usr/local/bin/rubocop:25:in `load'
> /usr/local/bin/rubocop:25:in `<main>'
> 
> </details>
> 
> + 4 others
> 
> </details>

<!-- end of auto-generated comment: all tool run failures by coderabbit.ai -->


---

<details>
<summary>📜 Recent review details</summary>

**Configuration used: CodeRabbit UI**
**Review profile: CHILL**
**Plan: Pro**


<details>
<summary>📥 Commits</summary>

Reviewing files that changed from the base of the PR and between 00c8fa64179fb2abae2beb0d969f42e0d67067ff and 376ca0cec82f33cfe0e445c110c24857a61976df.

</details>

<details>
<summary>⛔ Files ignored due to path filters (1)</summary>

* `Gemfile.lock` is excluded by `!**/*.lock`

</details>

<details>
<summary>📒 Files selected for processing (8)</summary>

* `.traceroute.yml` (1 hunks)
* `Gemfile` (1 hunks)
* `app/controllers/application_controller.rb` (1 hunks)
* `app/controllers/concerns/feature_toggle.rb` (1 hunks)
* `config/initializers/flipper.rb` (1 hunks)
* `db/migrate/20250616101406_create_flipper_tables.rb` (1 hunks)
* `db/schema.rb` (1 hunks)
* `test/controllers/concerns/feature_toggle_test.rb` (1 hunks)

</details>

<details>
<summary>🚧 Files skipped from review as they are similar to previous changes (8)</summary>

* Gemfile
* .traceroute.yml
* app/controllers/application_controller.rb
* config/initializers/flipper.rb
* test/controllers/concerns/feature_toggle_test.rb
* db/migrate/20250616101406_create_flipper_tables.rb
* app/controllers/concerns/feature_toggle.rb
* db/schema.rb

</details>

<details>
<summary>⏰ Context from checks skipped due to timeout of 90000ms (1)</summary>

* GitHub Check: build_and_test

</details>

</details>
<!-- internal state start -->


<!-- DwQgtGAEAqAWCWBnSTIEMB26CuAXA9mAOYCmGJATmriQCaQDG+Ats2bgFyQAOFk+AIwBWJBrngA3EsgEBPRvlqU0AgfFwA6NPEgQAfACgjoCEYDEZyAAUASpETZWaCrKNxU3bABsvkCiQBHbGlcABpIcVwvOkgAIgAxEmpsfxh8IiJowDsGQH0GQECGQGsGQEAGADMveG5uSkhSZkAkhkA4HUBTRVDYyAB3NGQHAWZ1Gno5CNgSSGxEauYu2WwAa3wABgAmFfRkW0gMRwFqgA5dhYAWDRgRnhTufAn+EuHRjdQCFAxcCkVsBlHcM7KKqr5ahF8JAyCpopASklcCkvulMvAMERnnceG8RGJwmhaLR/IhEAikUgHKNYLhcNxEBwAPRUojqWDYAQaJjMKklIT4Ci0HwMKkCfD4XAMNDMbhUonBRBU3YANgAnLsTnB7nYEQwvNglMg0JByhhZkD0JBaPgGI52PZHFMKPAAF4ElGQ5KpAgZcHwUXRNgvajwfAYcLtBAMWAoZDcLyYcj0J47c4CcqIEb0f2QABCAqFIu4AHV4LMdGgSjQ+P5ol0SBo3GcNrx8BJ4FrjSRcNpovQEYhXh9xP7kCVOZApDaSrIHd9RiHMKREOE1RraA7mIp4KPx2cAAYAVQmFEQAGF/a98D5KBvDVj6E7oak0HhYJy7b7UyHRLNtRgYyEHWgGJ88QoLxvL4A58IuJSQv4LxjLuyAABQbrMZCIDM56YPQiEeikaAbgAlCcACSuDoF4iDAlqDA2jsyAPu0hpMEBJ4QlCMJDkg8BqOUuDyAibEkO0s72FUDCrvAwo+PIQwMYuvYYGgEnGkgEZoGOiIouM1SJsReoGrxE41F4gjyZsaANkQz5YAIFYplg16sXe3yPraFlVgYABqlCicKsn2DQFLPOqmokBwBhQAAMnCDq8V0MHVIhyGofR/olPAFDMOgf7SMgTz6RpfBaTwaCkOgn4orw0hkJ8NzqbuupINpCK6Vg+lyWZLmhZAEUZFFWAxXlkCYcw2Hnk8DEpWlwzUBl/7ZcCuW1QV3BFaMqBKBg8AxOhKI6WGkAINiZCuQAypRJDIQ+uDaqkdYNkoMbAvAPjjK81BfGcJAAB7CQMkBbgRkA7LApl+nwoE4I5Nq2ptpXYHJ95OTEeWIK5FiQIerDsN0VrOK4BjKtYdj+J8kibX4JANvxZNBCEEJvOl+kOQ+fBwVMKFzIsKxLLhhr6f4FPtNUcEOGAwui9g+GnKMfMbQLfC/rMGD4O07akDGZz+NTXYlfQXRIVeg4qPgeD8OQHRnQao0sBGLZvVL5My65ACCxbVNL/EEuEvP2/x1Q0F2MT6XZLpwuCgPA4OQw0KKnLOI98hToi66jIzTkWci+kMcep58E8KeQ6M/WDcN2t3FgfOUOIanqAD8sXvD+cDUhGBsxuSojPIgi7lIatTYXBZDVQ57+K2CKbZlAE5ZuVJI+eS3FeTZDoC7OdnHnT4+UwSgdDF5cUAMJz7iMDAFmpGd9iedtSPJAdA8RgcsakZRFRCg5F4PZNTKP9CggmMQIfE5RKiUAANocCRgAXQ0D/dsAB+OC/dsLcwALx6AiBQYIeFXL4zdrLPw2gJg60Ap8CgvV+TG2+KgMODZOThE1rJB0QYWwjD4NXToyAEQ0BeH6OSvgDY8EFOweAxkJSVmrMneuZNECXE/DfKaFCZAkCBtQlhyBaDBB5j8QB/wagkGYAAclUdIeARAsBC2El5eSXh5CBy0ZQMAv5xBSAAPpE05DrWgaBuAllwoGZhox/RVR1EHUYT9CTIGgTEMGOo8qezOF2V6u1/j4n9h2ZqZwPGtistcLa/hP7Nwyo4guXDfCfQjGJdQVjFKIDBHQNu4iIYZQVkrFWsi74IGQEwbw9BhQaUAiUcY3CX58HIHRJGyIlBSEMtwb0xEyANjeBgGZMhjblUgv4e6e10LumIkME0ZoZlJ02GdDZUwtiWPkIuapv9HQPxCZGJEDYdRn2bhfPBE4V6YHQNiH8eAWC+gYFUmpup0hiXTmcTeJBfFiVDJ0rwqTToVgUJ6T66hZBYPVt7XBRV/AxHaPSYYqBPF1l/KGHJgRJQ/QZhIp4dZPi4vxXs80XDT5nCoSDdF9SmalzGNwDJN9RiMpmWnJ484grPC7OgsQ3DkCplooaS5QKgm3IhPclAtxWExT6PEpulSIm0HCDdRsP46r6g0XbaIEhMDEQmFK1Mel0mmiZa2WSrl4gInObEy+MtqhjVSmwNWArHVCp8tgXlCSyV0IDsCOMl5NrajJvzaoqZ9IbEtsy9RXt+aolNFlVy+hjDgCgGQFMtwHKEFIOQKgP0WQzK4LwfgwhRCFJkPHRQyhVDqC0DofNJgoDuHYR+cG5ayDKGrSwWteC6IOCcC4AGralBUA7ZobQugwCGALaYAwGgXrEKNjQDQshmBeBCrEU9BhUaOwIsQEdVaYjTutB3W4CcZxiIGtuqgu68CVkPV4c8vqiDYR8ilcEbCeV8sGPIS864cVHLoktMklB8mT1GBuYxit/BONhv4ElNSnEOOleeLSdTrjwZLPkqYQpQxsEcvQOSbBkBllehs4J4Mmbr24VwDca8oZOOCRucIXH652joLx25MD+Ml0ExDYTtBRPOhICAVupxUDPtGJ9ThtBspxJbNVajD5NOTTaV8D9lA92wiYninwKATGclGIwrAjZBFrjUlhpIU5rn4b7OEKRogLEKVFYuFlFVWOp1kmARjP09OKGRuYSwjsvAlgsrNFESh1TOCS9VUpnIfqDk8AmUFgjxDSCMAAOX9CQAwp7YhGAgGAIwABxXRwHgqVbPReq9FbR13uxrO/AT6gaImK3jcFA3iqXnjSMnR6UlBVBkRgBgsgBO/CARQexUrnGuK5OeYc+JUxEreB9D0r1KkAEYNAAGZPZzTOI15gzW26oEBKgTsFdNrLjUoKZhU2GMkEjJS4EjNBHeW4eEDkAhs0zQ9iXLsMdSAnDK/wd5kBlzgTEhlp4KKuwOlqDKgEbxQ1XVGFMJQrlYuQHi4l2SyX9KpcjFW6VmWvrZZiLlxk5QAWFY2ogUr5WqxVZq5uolVJM7AWiHuKkRL2cWScSLk8YuNAUAECetrcWOs3qY5aGdj7GCjaG/jDcjtKhS9koeRi2c/2RgAkDBRi9Q3gcNAF22A1EjyegCHEg54UfeErMp7U3yfIcJIEQW9/ZlWukyCE2GtqeGoueMhwCWcxfhGgQ6FjoTkeYGWjMjKbwJ6ryN2jl1kAEefZ9br5Lhk6QMHCLLkChl2jhEHJQN4fABvcgYZQInWJRHnriwl0dDP4+0/S1Txnlw94s74Hl9nIIuFFe5x1Ai82NS7awH1lEG4Xc3hIG7t0HvkfvHdGklDhuynA/9KbxPZ5GCW/YVgLjlRhdHlF5QKUkvC/cJl8/uXlAFcCA3K1tVqFILo/rXmLlKAxMQs3GyLck4uHtEH/srtVu1tepWhrvejjNVKpgvo7LBgfmouCJvrcrvhHueM9oxGop8DrIOo7OtiQEdKGuPsRJAYhs2PiCYpEoOL0rxDYG2B0t/tnMjJAERNmrdNIMxPJiqkVHSGpP0vNrJPJLHoHsHhrnit8CiAAn8NULUHUvgd7iCEzhMPGiMF4NolFhhNxiJsEuJvREfLpKWjUCTLZMqnBI5lwilDEEMBuMEk4khLIHhLtHqkMiiGaBQFBMRHlIRMRPJGRM2ClOQMgFJmxlDLJsEoplCiGHgkgOITqPjpXEiM3oOGoaGPpPRtUsVAkMqgqr/LQG0KuDcpIagIrLMnJDUcERnCkOEbFBQMnhBE2iTLqhgKBCJLIcqr+DNAnsBCcI7P7twh6iiF7kfoFE2J8kkQjHJtvp7kwooIZrPjUvGmnoOOVvwHwMuKkD5iJB4TrGIJyC2igJTg6PWL7GcIandAUrcSXCnkFhIdvsEW5qGI8pAJoStgYgNBEnhjcRQFsTRroSwSQkOhRmjgpFMEhIkZYakWJmhJao9IqsYb9mYdsaknxAJKTr3uTv3vTn2Gas2GlpSfkuvllhPimFPmzgVnPlzjVsXpTIscnAdLQJxlvjCCQdEGQffkLmAa/k/vNohlKD4fAZWIrgAVAFYKyQCp2K2NKcjoSV8ndJxuiRsTCHAj4X4bhKKc7sQe7kqdYKqeKhqVVOYTqXQHqUJikQaf4CAHBMaSQLIKaciEQa7paR1Cqflmqc3HaUTtqbGvyQNJYW6SQJ6bAX4ZiJCYgL6bxP6dvsKR7oAQLnVgYP+uKOtOIIoVDOLstv8IgTmSgZ1revQBgb1v1tOENrgZNgiOoEIuUKWRCI9CEoOMCdomnqqv+oBoMtFJALwY9NqAXufg5nfseJQbUsIdai2MgKGkaBOaRH0sYiOamAmKaAaMUUijMnQGAHuvwF4gzmDP2dUGyjQgFAuEuLovgOxv6AamWPgFiKnrcoJBKmJMRCjr2XwLDE0u0M4fJoJJXjIUQJ7DTHMqlP6NnliJ4iWFuQBnSTXoZJqPYLIPNoVN8JiKVOqegsGtwroc1iRLEY7vGteXwMOXSQDIZMfMEf4HSP7DaGpFBgob4EhV4q/oGPip8p9NmOCDWuwCzsbGDAMhxVgLQYUgwZUNlowCSqMDDreB4rxRQCcG6jwlYnOMRK8eIaJS8CeWeUJcigoFvGDCxfVJ5Bxd0TUPjtwJAHBJWEQBoJiLQH0M3NzBjq0eCIOUVP2ION8FNMHkbNwPDgDnQahTuWvvlCCmqeEn5Z4RciQCUHeAlgANwkS8IXlUnOCjAGXUFHliVfieivRBW0XPQsAvkYCkkXoUno7XYCqiB04ZYMlM5MknHxgz6c5DZQAI6Mk5Yskhmz6RBc7oCpDD7rLdUo6iR0DZWBw9kmyVKZzaD5J0Vpx7nHwfjdLjqlWnnGxmXWwWWiL87AF5m0ACBUh9AqE0BUhLDLAACsCwMoJ2b1CwJ2hwr1Mu2GNAvGtiFAcB+xlZ/O1Z6uP09Z2u2B1YqAt19FHCbwC52U7QwIk2GSKgiKmS0QlIA05ZlAcZiAaEpU3hgNTi5kfsSm+u+NQNwSRNEQQKVFRoisGAYAWwPgQKv5akTAGozA9+fhxNMYHoIQ2YCgvNzc/F6h0S601MzwSgH0JsG+AtYtjgzUwIZAwxRS8A1MCRQh1NZNFN0gI0QKa1nYmw/obN3gkY1yXNSIPNqtiRXp/hkmAtmIEQ6mKtfNA0lqGoHuBFQt9GrYoontzcURFFAO2I8asM2t6iLIlw+INActn0itZ8zAagckPk6+3hiZ3pEm8U/h/t3t8kGCktpKuoZARA6h5QfQxE6+SwT1T1Ou6WYgr+Kdm4PtGCIdwRCI8tDongFA8d0guhG4oa0J+mjAf14hE41w2NORhFMiH00gUK4I+kG4JooFY9OxOI+A/k/I6hs9gkliSsqeg4u8+I1y8N7URgZJFOA+VJQ+rVI+DOHVTBk+PVbJ41/V5OfJN+XQiR+4k9NF0A+xopzC7ZshdMA0slJMNgogbiHAHAAAssYnScAjKBoCduAueIedPqCuYZSAYJALoANEoLcKPfRJPXjWTXTYLVQ1oUDYbfTQfSXBOKlEnYvTFkQ1AGvWlcaErBgCNORG8E5aTfQ+TRVbQ6IytoTcbb/DFudbVkYFdVSIgK+FMKDSruTmrmgZDT1tDeXm4KjXgQfUttQ9+ZIzTeI5TeEEoqMDsIvFGdSRjVkipWo2gMPZYzQwzdckzTqCzZbRzTba8A6PbV7fndgwJWMDLeoj3Z9IXeIIHaLaE/khuAigMHhrgJI3bkxhkxE+oX0JRFcHA6VOVCJKvh4wbRI94yJUeOtcgP4+zdbeCLbSHY7Tnc7VtOE27TQB9MwSeKrUXb7RJltAkyLcHck4kWkyJtQFk2GukzMx0PigU7nsU/QKU+xP6GHTEcCNbkaNHbLXHVcOoCtAvW3ZOCwOnWnFnU7Xna7ZJh3R7sRryTJAzoje8FVJNn1T9n9lGj8axPAY8QCL6LIVHlxaivVX3g8ffc1TSW1aPi/czsye/RzuyV/SVpTLPY6dGVI/8DI4s+oRMwNPAt6RwC080ZsFbTXpPbJtQBwHyqM3BDKNzOS40+ENk/M5wPS8LYy8y4KBSz4L6VtPszE6c6mOE1WANRi4qnyZxpY4w3kzCv03zYkQmfJr4SS2S3y6y5AH4aS8E2pCy5S0OMXcFD02EBPVCNM5y69Ay0y+bcRNq+y1a3Sza9y3a4awK7Q8K+c9HAnSc/LYrRuKq9vuq4tjq96eEA86aXzmehdUYH7LgFKVfuLnCdAXKe7nASEBo8garqgV1nWXo1gQY8Nk0RizTORaQ6PIOsofRQm5aMc+0ZuIKf4FmX+gEqwY7kSTqNUuZRKZpUufYCuTykaMuExX27/QBIec8lASXDqKEV0f1ClL0zCLoQm8gMOKuNYrADBnklqTRrjWsfnBifJuJhkaGMPCkPkjqPyBfJ8j3R/lXA4SxqgEEWDB0WERaHlNlYezJnGekR0MGOe/gjkX4Hug6IUXwIeWUctHEM2wKkgDUrUWqg0b8U0Xy3qo3u8nitcBeyQvU49NlZ07GXxme3sXI0aIcXwBcfNfQGMlwbVGFQTquyEPwUMX6rsXTZNfB1cu2HOnERleazsCyGpslfQPZgYWfhUtYu7vrHLN0fE7fCiNxmnA6UwB+2IIMfsSh6xGDHSFIFgP1BMJdPeZqD1IuLdNgMZGMkK7VKozveIeUEhF8l5btVqS8LcRC+SVC0hjC9Ne1bcENW/bgyi5/QvpK3RHW2lgBFGQKRaXvtACEKA55PkbTCwFA9HgACJKTUAhgINL40B3XcIJddhmkbgJtJsv4pvtt4cwFqvymZtdh/5Wnot0QJFjpm5i4Tt+66kDQACiH0wlJAl+lXSXNoKXJQkDBu05Fkw3P+UJJcAWDoGZQplpRCiGpdRowX00WUr8877AmGu4pXcHWZxXmT3Z0QOZwB66vas+JaQ6ebtZJVLwXAVAU6hbUkbai6agy63aa6BgN3Na6gTijYiALimKIm8Se8q613hakAAA7CdrsE9SdrQAwE9bQCdgwHKDKEWL+EoIcAwNiAIBBBj09UsLQHDzKDKHD+dgwCdkkND/97DwsAsAwLsOlTKIcCdnD3KCUAIEsJjSQEsDsAIAsLQNj7z4cEsCQGL9T69XDxBIzzd+dpT8KKz6ILsEsCUOdrT5CAsCQIcIcE9XTydqz0sIcEj3D2gG9XKJT7QLcPmkzxAEeUDyD2D4mrJsWtD0AA -->

<!-- internal state end -->
<!-- finishing_touch_checkbox_start -->

<details open="true">
<summary>✨ Finishing Touches</summary>

- [ ] <!-- {"checkboxId": "7962f53c-55bc-4827-bfbf-6a18da830691"} --> 📝 Generate Docstrings

</details>

<!-- finishing_touch_checkbox_end -->
<!-- tips_start -->

---

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

<details>
<summary>❤️ Share</summary>

- [X](https://twitter.com/intent/tweet?text=I%20just%20used%20%40coderabbitai%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20the%20proprietary%20code.%20Check%20it%20out%3A&url=https%3A//coderabbit.ai)
- [Mastodon](https://mastodon.social/share?text=I%20just%20used%20%40coderabbitai%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20the%20proprietary%20code.%20Check%20it%20out%3A%20https%3A%2F%2Fcoderabbit.ai)
- [Reddit](https://www.reddit.com/submit?title=Great%20tool%20for%20code%20review%20-%20CodeRabbit&text=I%20just%20used%20CodeRabbit%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20proprietary%20code.%20Check%20it%20out%3A%20https%3A//coderabbit.ai)
- [LinkedIn](https://www.linkedin.com/sharing/share-offsite/?url=https%3A%2F%2Fcoderabbit.ai&mini=true&title=Great%20tool%20for%20code%20review%20-%20CodeRabbit&summary=I%20just%20used%20CodeRabbit%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20proprietary%20code)

</details>

<details>
<summary>🪧 Tips</summary>

### Chat

There are 3 ways to chat with [CodeRabbit](https://coderabbit.ai?utm_source=oss&utm_medium=github&utm_campaign=fjordllc/bootcamp&utm_content=8804):

- Review comments: Directly reply to a review comment made by CodeRabbit. Example:
  - `I pushed a fix in commit <commit_id>, please review it.`
  - `Explain this complex logic.`
  - `Open a follow-up GitHub issue for this discussion.`
- Files and specific lines of code (under the "Files changed" tab): Tag `@coderabbitai` in a new review comment at the desired location with your query. Examples:
  - `@coderabbitai explain this code block.`
  -	`@coderabbitai modularize this function.`
- PR comments: Tag `@coderabbitai` in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
  - `@coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.`
  - `@coderabbitai read src/utils.ts and explain its main purpose.`
  - `@coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.`
  - `@coderabbitai help me debug CodeRabbit configuration file.`

### Support

Need help? Create a ticket on our [support page](https://www.coderabbit.ai/contact-us/support) for assistance with any issues or questions.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

### CodeRabbit Commands (Invoked using PR comments)

- `@coderabbitai pause` to pause the reviews on a PR.
- `@coderabbitai resume` to resume the paused reviews.
- `@coderabbitai review` to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
- `@coderabbitai full review` to do a full review from scratch and review all the files again.
- `@coderabbitai summary` to regenerate the summary of the PR.
- `@coderabbitai generate docstrings` to [generate docstrings](https://docs.coderabbit.ai/finishing-touches/docstrings) for this PR.
- `@coderabbitai generate sequence diagram` to generate a sequence diagram of the changes in this PR.
- `@coderabbitai resolve` resolve all the CodeRabbit review comments.
- `@coderabbitai configuration` to show the current CodeRabbit configuration for the repository.
- `@coderabbitai help` to get help.

### Other keywords and placeholders

- Add `@coderabbitai ignore` anywhere in the PR description to prevent this PR from being reviewed.
- Add `@coderabbitai summary` to generate the high-level summary at a specific location in the PR description.
- Add `@coderabbitai` anywhere in the PR title to generate the title automatically.

### CodeRabbit Configuration File (`.coderabbit.yaml`)

- You can programmatically configure CodeRabbit by adding a `.coderabbit.yaml` file to the root of your repository.
- Please see the [configuration documentation](https://docs.coderabbit.ai/guides/configure-coderabbit) for more information.
- If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: `# yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json`

### Documentation and Community

- Visit our [Documentation](https://docs.coderabbit.ai) for detailed information on how to use CodeRabbit.
- Join our [Discord Community](http://discord.gg/coderabbit) to get help, request features, and share feedback.
- Follow us on [X/Twitter](https://twitter.com/coderabbitai) for updates and announcements.

</details>

<!-- tips_end -->

@masyuko0222 masyuko0222 self-assigned this Jun 17, 2025
@masyuko0222 masyuko0222 force-pushed the feature/feature-toggle branch 4 times, most recently from 1ecbe33 to 71851dc Compare June 19, 2025 12:29
@masyuko0222 masyuko0222 marked this pull request as ready for review June 20, 2025 07:17
Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (2)
test/controllers/concerns/feature_toggle_test.rb (1)

5-47: テストカバレッジが包括的で適切に実装されています

FeatureToggleコンサーンの全ての主要メソッドに対して適切なテストが書かれています。特に以下の点が良く実装されています:

  • authorized_feature?のboolean判定テスト
  • authorized_feature!の例外処理テスト
  • authorize_featureの複数アクター対応テスト
  • デフォルト無効状態と有効化後の動作確認

テストをより堅牢にするため、以下の追加テストケースを検討してください:

test 'authorized_feature? with nil current_user' do
  @controller.current_user = nil
  assert_not @controller.authorized_feature?(:some_feature)
end

test 'authorize_feature with empty array' do
  @controller.authorize_feature(:some_feature, [])
  assert_not Flipper[:some_feature].enabled?(@controller.current_user)
end
app/controllers/concerns/feature_toggle.rb (1)

3-23: フィーチャートグル機能が適切に実装されています

Flipper gemを使用したフィーチャートグル機能が Rails の慣例に従って正しく実装されています。以下の点が特に良く設計されています:

  • ActiveSupport::Concernの適切な使用
  • ビューでも使用可能なhelper_methodの公開
  • 明確な責務分離(チェック、例外処理、有効化)
  • Array(actors).flattenによる柔軟なアクター指定対応

より堅牢性を高めるため、current_userがnilの場合の明示的な処理を検討してください:

def authorized_feature?(feature_key)
  return false unless current_user
  Flipper[feature_key].enabled?(current_user)
end

ただし、Flipperはnilアクターを適切に処理するため、現在の実装でも問題ありません。

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 88d0cd5 and 71851dc.

⛔ Files ignored due to path filters (1)
  • Gemfile.lock is excluded by !**/*.lock
📒 Files selected for processing (8)
  • .traceroute.yml (1 hunks)
  • Gemfile (1 hunks)
  • app/controllers/application_controller.rb (1 hunks)
  • app/controllers/concerns/feature_toggle.rb (1 hunks)
  • config/initializers/flipper.rb (1 hunks)
  • db/migrate/20250616101406_create_flipper_tables.rb (1 hunks)
  • db/schema.rb (1 hunks)
  • test/controllers/concerns/feature_toggle_test.rb (1 hunks)
🔇 Additional comments (6)
Gemfile (1)

35-35: Flipper gemの追加を承認します

flipper-active_record gemの追加は適切です。バージョン制約も適切に設定されています。

ただし、最新の安定版を使用していることを確認することをお勧めします。

flipper-active_record gemの最新バージョンは何ですか?セキュリティアドバイザリはありますか?
app/controllers/application_controller.rb (1)

6-6: FeatureToggle concernのincludeは適切です

ApplicationControllerへのFeatureToggle concernの追加により、全てのコントローラーでフィーチャートグル機能が利用可能になります。includeの位置も適切です。

.traceroute.yml (1)

38-40: フィーチャートグルメソッドの除外設定が適切です

FeatureToggle concernで提供されるメソッド(authorize_featureauthorized_feature?authorized_feature!)をtracerouteの未到達アクション検出から除外する設定は適切です。

config/initializers/flipper.rb (1)

1-46: Flipper初期化ファイルの構成が適切です

包括的な設定オプションをコメントアウトした形で提供しており、安全で良いアプローチです。メモ化、プレローディング、ストリクトモード、ログ出力などの重要な設定オプションが網羅されています。

デフォルトで何も有効化されていないため、プロジェクトの要件に応じて段階的に設定を有効化できます。

db/migrate/20250616101406_create_flipper_tables.rb (1)

1-22: Flipperテーブル作成マイグレーションは正確な構造です

flipper_featuresflipper_gatesテーブルの構造は、FlipperのActiveRecordアダプターが期待するスキーマと一致しています。

適切なインデックス設定:

  • flipper_features.keyのユニークインデックス
  • flipper_gatesの複合ユニークインデックス(feature_key, key, value
  • valueカラムの長さ制限によりインデックスキーサイズエラーを防止

downメソッドでのテーブル削除順序も適切で、可逆的なマイグレーションになっています。

db/schema.rb (1)

331-346: Flipperのスキーマ変更が適切に実装されています

新しく追加されたflipper_featuresflipper_gatesテーブルは、Flipper gemの標準的な構造に従っており、適切なインデックスが設定されています。フィーチャーフラグ機能の実装に必要なデータベース基盤が正しく構築されています。

@masyuko0222 masyuko0222 force-pushed the feature/feature-toggle branch from 71851dc to 00c8fa6 Compare June 21, 2025 15:46
@masyuko0222
Copy link
Copy Markdown
Contributor Author

@su-su-su-su
お疲れ様です。こちらのPRのレビューをしていただけないでしょうかm(__)m

@su-su-su-su
Copy link
Copy Markdown
Contributor

@masyuko0222
お疲れ様です。了解しました。
1週間ほど期間をいただければと思います🙇‍♂️
よろしくお願いいたします!

@su-su-su-su
Copy link
Copy Markdown
Contributor

su-su-su-su commented Jun 30, 2025

@masyuko0222

お疲れ様です。
レビュー遅くなり申し訳ございません。

挙動の確認させていただきました。
興味本位で
app/controllers/users_controller.rb

before_action -> { authorize_feature(:users, [User.find_by(login_name: 'kimura')]) } 

としてから
ユーザー名:kimuraでログイン
/usersにアクセス

before_action -> { authorize_feature(:users, [User.find_by(login_name: 'kensyu')]) } 

に戻して
ユーザー名:kimuraでログイン
/usersにアクセスしました。
すると権限は残っており/usersが見れてしまいます。

コンソールで確認すると

kimura = User.find_by(login_name: 'kimura')
Flipper[:users].enabled?(kimura)
=> true 

となっています。
過って権限を付与することはないと思うのですが、念のため確認させてください🙇

@masyuko0222
Copy link
Copy Markdown
Contributor Author

@su-su-su-su
ご確認ありがとうございます!

ユーザー名:kimuraでログイン
/usersにアクセスしました。
すると権限は残っており/usersが見れてしまいます。

こちらの挙動は、Flipper(flipper-active_record gem)の仕様によるものです。
一度 enable された機能フラグは、DBにその状態が保存されるため、明示的に disable しない限り有効なままとなります。

過って権限を付与することはないと思うのですが、念のため確認させてください🙇

ご指摘の通り、初めて使う方が開発環境でこの挙動に触れると、混乱を招く可能性があると私も感じました。
コード上でdisableを自動的に行うこともできますが、そうすると不要なコードが増えてしまうため、運用上は誤って付与してしまった際に、console上で disable するようドキュメントに記載する方針にしたいと考えています。

改めてご確認いただき、ありがとうございました🙇

@su-su-su-su
Copy link
Copy Markdown
Contributor

@masyuko0222

ご確認ありがとうございます!

こちらの挙動は、Flipper(flipper-active_record gem)の仕様によるものです。
一度 enable された機能フラグは、DBにその状態が保存されるため、明示的に disable しない限り有効なままとなります。

なるほどです。Flipperの仕様なのですね。

コード上でdisableを自動的に行うこともできますが、そうすると不要なコードが増えてしまうため、運用上は誤って付与してしまった際に、console上で disable するようドキュメントに記載する方針にしたいと考えています。

ありがとうございます。
確かにそうですね。ではその方法でご対応お願いします🙇

@masyuko0222
Copy link
Copy Markdown
Contributor Author

@su-su-su-su
以下のようにドキュメントに追記しました。
⚠ 誤って機能の認可を与えてしまった場合

問題なさそうでしたら、引き続きレビューのほどよろしくお願いいたします🙇

@su-su-su-su
Copy link
Copy Markdown
Contributor

@masyuko0222

確認させていただきました!
お手数ですが、レビュアーに私を追加していただけますでしょうか🙏

@masyuko0222 masyuko0222 requested a review from su-su-su-su July 4, 2025 06:11
Copy link
Copy Markdown
Contributor

@su-su-su-su su-su-su-su left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

レビュアーの追加ありがとうございます。
確認させていただきました。
私からはApproveとさせていただきます!

@su-su-su-su su-su-su-su self-requested a review July 4, 2025 06:23
・View用(ヘルパー)の`authorized_feature?`
・Controller用の`authorized_feature!`
・ApplicationControllerでincludeしているため、全てのコントローラで、使っているか使っていないかの追跡をしてしまう
・他のconcernsもignoreしているので、それに倣って
@masyuko0222 masyuko0222 force-pushed the feature/feature-toggle branch from 00c8fa6 to 376ca0c Compare July 5, 2025 03:35
@masyuko0222
Copy link
Copy Markdown
Contributor Author

@su-su-su-su
ありがとうございます!

@komagata
メンバーレビューを頂いたので、レビューよろしくお願いいたします!

@masyuko0222 masyuko0222 requested a review from komagata July 8, 2025 11:59
Copy link
Copy Markdown
Member

@komagata komagata left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

確認させて頂きました。OKです〜🙆‍♂️

@komagata komagata merged commit 3e2ee5d into main Jul 11, 2025
6 checks passed
@komagata komagata deleted the feature/feature-toggle branch July 11, 2025 03:50
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants