Skip to content

CorrectAnswerNotifier等3クラスをnewspaperからActiveSupport::Notificationsへ移行#9015

Merged
komagata merged 3 commits intomainfrom
chore/replace-newspaper-in-correct_answer-graduation-comeback
Oct 1, 2025
Merged

CorrectAnswerNotifier等3クラスをnewspaperからActiveSupport::Notificationsへ移行#9015
komagata merged 3 commits intomainfrom
chore/replace-newspaper-in-correct_answer-graduation-comeback

Conversation

@ryufuta
Copy link
Copy Markdown
Contributor

@ryufuta ryufuta commented Aug 5, 2025

Issue

概要

下記の3クラスの実装をnewspaperからActiveSupport::Notificationsに置き換えました。

  • CorrectAnswerNotifier
  • GraduationNotifier
  • ComebackNotifier

変更確認方法

  1. chore/replace-newspaper-in-correct_answer-graduation-comebackをローカルに取り込む
  2. foreman start -f Procfile.devでローカルサーバーを起動

CorrectAnswerNotifier

Q&Aの質問作成者がベストアンサーを選択すると、質問作成者以外の「Watch中」のユーザーに通知が届くことを確認します。

  1. sotugyou(任意のユーザーで可)でログイン
  2. sotugyou以外が作成した未解決の質問(例:テストの質問38 )に回答
  3. 上記の質問の作成者(上の例ではhajime)でログイン
  4. sotugyouの回答をベストアンサーにする
  5. sotugyouで再度ログイン
  6. 通知メニューに上記Q&Aのベストアンサー決定の通知が届いていることを確認

Q&Aを自動的にクローズした際にもベストアンサー決定の通知が飛ぶため、こちらも確認します。
定期処理を実行できるようにするためローカル環境に環境変数TOKENを設定しておく必要があります。
ローカル環境に環境変数を設定するにはdotenv-railsというgemを使用すると便利です。

以下はこのgemを使用する場合の手順です。
Gemfileに追記済みのため改めてインストールする必要はない)

  1. bootcampのリポジトリのルートディレクトリに.env.localファイルを作成
  2. ファイルにTOKEN=hogeを追記
  3. 環境変数を反映させるためにローカルサーバーを再起動

以下は自動的にクローズした際のベストアンサー決定の通知の確認手順です。

  1. sotugyou(kimura以外のユーザーであれば可)でログイン
  2. 自動クローズされる質問 (警告コメントが投稿されてから1週間経過した未解決のQ&A)にアクセス
  3. 「Watch中」ボタンをクリック
  4. http://localhost:3000/scheduler/daily/auto_close_questions?token=hoge にアクセス(定期処理が実行される)
  5. 自動クローズされる質問 に再度アクセスして、pjordからクロージングコメントが投稿されて解決済みになっていることを確認
  6. sotugyouでログインした状態でサイト内通知に「kimuraさんの質問【自動クローズされる質問】でpjordさんの回答がベストアンサーに選ばれました。」という通知が届いていることを確認

GraduationNotifier

管理者が現役生のステータスを「卒業」にすると、管理者とメンターに通知が届くことを確認します。

  1. komagataでログイン
  2. thirtyのプロフィールページ(※基本的にはどの現役生でも可)にアクセス
  3. ページ内の「ステータス変更」欄にある「卒業にする」ボタンをクリック
  4. mentormentaro(管理者や他のメンターでも可)でログイン
  5. 通知メニューに「🎉thirtyさんが卒業しました!」という通知が届いていることを確認

#9114 のバグが原因でkimuraとhatsunoを卒業させようとするとエラーが発生するためその他の現役生で動作確認を実施してください。

ComebackNotifier

休会中のユーザーが復帰すると、管理者とメンターに通知が届くことを確認します。

  1. 休会からの復帰ページ にアクセス
    ログインページの「休会からの復帰」リンクから遷移できます
  2. kyuukai(任意の休会中のユーザーで可)の登録情報(ログイン名とパスワード)を入力して「休会から復帰する」ボタンをクリック
  3. mentormentaro(管理者や他のメンターでも可)でログイン
  4. 通知メニューに「kyuukaiさんが休会から復帰しました!」という通知が届いていることを確認する

Screenshot

リファクタリングのためUIの変更はありません。

Summary by CodeRabbit

  • Refactor
    • 通知イベントの発火・購読方式を統一し、正答保存・卒業更新・カムバック更新の通知フローを一元化。
  • Chores
    • 初期化時の通知購読設定を見直し、関連するサブスクライブ登録を整理。
  • 影響
    • 管理者・メンター向け通知やチャット連携の安定性が向上し、対象アクション後の通知がより確実に届きます。UIや操作方法の変更はありません。

@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Aug 5, 2025

Walkthrough

Newspaperによるイベント発行・購読をActiveSupport::Notificationsへ移行。コントローラとモデルのpublish呼び出しをinstrumentに変更し、イニシャライザでの購読先をAS::Notificationsに再登録。各Notifierのcallシグネチャを5引数形式に対応させ、既存の処理内容は維持。

Changes

Cohort / File(s) Summary
Publish呼び出しの移行(コントローラ)
app/controllers/api/correct_answers_controller.rb, app/controllers/comeback_controller.rb, app/controllers/graduation_controller.rb
Newspaper.publish(:event, {...})ActiveSupport::Notifications.instrument('event.name', ...) に変更。イベント名をシンボルからドット区切りの文字列へ更新。ペイロードは同等。
Publish呼び出しの移行(モデル)
app/models/question_auto_closer.rb
正答保存イベントの発行をNewspaper→ActiveSupport::Notificationsへ切替(correct_answer.save)。他の処理は不変。
Notifierシグネチャ対応
app/models/correct_answer_notifier.rb, app/models/graduation_notifier.rb, app/models/comeback_notifier.rb
def call(payload)def call(_name, _started, _finished, _unique_id, payload) に変更。既存のペイロード利用ロジックは不変。
購読登録の移行(AS::Notifications)
config/initializers/active_support_notifications.rb
correct_answer.savegraduation.updatecomeback.update を各Notifierにsubscribeで登録。
購読登録の削除(Newspaper)
config/initializers/newspaper.rb
上記3イベントのNewspaper.subscribeを削除。その他の既存購読は維持。

Sequence Diagram(s)

sequenceDiagram
  autonumber
  actor User
  participant Controller as Controller (create/update)
  participant AS as ActiveSupport::Notifications
  participant Notifier as *Notifier

  User->>Controller: 操作(例:正答作成/卒業更新/カムバック)
  Controller->>AS: instrument("*.save|*.update", payload)
  Note over AS: 非同期/同期で購読者に配信
  AS->>Notifier: call(name, started, finished, id, payload)
  Notifier->>Notifier: payloadから対象抽出・通知処理
Loading

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~10 minutes

Possibly related issues

Possibly related PRs

Suggested reviewers

  • komagata
  • matuaya

Poem

ぴょんっと跳ねて通知が飛ぶ
ドットで結ぶ新しい道
しんぶん屋さんに手を振って
Railsの風にのりかえて
きょうもイベント、無事到着 🥕✨

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check name Status Explanation
Title Check ✅ Passed タイトルは差分の主旨を短く明確に示しています。CorrectAnswerNotifier等3クラスの移行(newspaper→ActiveSupport::Notifications)という主要な変更点を具体的に表しており、レビュー履歴を眺める同僚が主旨をすぐに把握できます。
Description Check ✅ Passed PRの説明はリポジトリのテンプレートに概ね沿っており、Issueリンク、概要、各Notifierごとの具体的な変更確認手順(ローカル起動手順や自動クローズ検証手順を含む)およびスクリーンショット欄の記載(UI変更なし)を含んでいてレビューに必要な情報は揃っています。手順が具体的で再現性が高く、マージ前の確認に十分です。
✨ Finishing touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch chore/replace-newspaper-in-correct_answer-graduation-comeback

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.

🔧 RuboCop (1.76.1)
config/initializers/active_support_notifications.rb

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.79.2/lib/rubocop/config_loader_resolver.rb:309:in rescue in gem_config_path' /var/lib/gems/3.1.0/gems/rubocop-1.79.2/lib/rubocop/config_loader_resolver.rb:293:in gem_config_path'
/var/lib/gems/3.1.0/gems/rubocop-1.79.2/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.79.2/lib/rubocop/config_loader_resolver.rb:82:in reverse_each'
/var/lib/gems/3.1.0/gems/rubocop-1.79.2/lib/rubocop/config_loader_resolver.rb:82:in block in resolve_inheritance_from_gems' /var/lib/gems/3.1.0/gems/rubocop-1.79.2/lib/rubocop/config_loader_resolver.rb:76:in each_pair'
/var/lib/gems/3.1.0/gems/rubocop-1.79.2/lib/rubocop/config_loader_resolver.rb:76:in resolve_inheritance_from_gems' /var/lib/gems/3.1.0/gems/rubocop-1.79.2/lib/rubocop/config_loader.rb:58:in load_file'
/var/lib/gems/3.1.0/gems/rubocop-1.79.2/lib/rubocop/config_store.rb:29:in options_config=' /var/lib/gems/3.1.0/gems/rubocop-1.79.2/lib/rubocop/cli.rb:162:in act_on_options'
/var/lib/gems/3.1.0/gems/rubocop-1.79.2/lib/rubocop/cli.rb:47:in block in run' /var/lib/gems/3.1.0/gems/rubocop-1.79.2/lib/rubocop/cli.rb:82:in profile_if_needed'
/var/lib/gems/3.1.0/gems/rubocop-1.79.2/lib/rubocop/cli.rb:43:in run' /var/lib/gems/3.1.0/gems/rubocop-1.79.2/exe/rubocop:19:in <top (required)>'
/usr/local/bin/rubocop:25:in load' /usr/local/bin/rubocop:25:in

'

app/controllers/comeback_controller.rb

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.79.2/lib/rubocop/config_loader_resolver.rb:309:in rescue in gem_config_path' /var/lib/gems/3.1.0/gems/rubocop-1.79.2/lib/rubocop/config_loader_resolver.rb:293:in gem_config_path'
/var/lib/gems/3.1.0/gems/rubocop-1.79.2/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.79.2/lib/rubocop/config_loader_resolver.rb:82:in reverse_each'
/var/lib/gems/3.1.0/gems/rubocop-1.79.2/lib/rubocop/config_loader_resolver.rb:82:in block in resolve_inheritance_from_gems' /var/lib/gems/3.1.0/gems/rubocop-1.79.2/lib/rubocop/config_loader_resolver.rb:76:in each_pair'
/var/lib/gems/3.1.0/gems/rubocop-1.79.2/lib/rubocop/config_loader_resolver.rb:76:in resolve_inheritance_from_gems' /var/lib/gems/3.1.0/gems/rubocop-1.79.2/lib/rubocop/config_loader.rb:58:in load_file'
/var/lib/gems/3.1.0/gems/rubocop-1.79.2/lib/rubocop/config_store.rb:29:in options_config=' /var/lib/gems/3.1.0/gems/rubocop-1.79.2/lib/rubocop/cli.rb:162:in act_on_options'
/var/lib/gems/3.1.0/gems/rubocop-1.79.2/lib/rubocop/cli.rb:47:in block in run' /var/lib/gems/3.1.0/gems/rubocop-1.79.2/lib/rubocop/cli.rb:82:in profile_if_needed'
/var/lib/gems/3.1.0/gems/rubocop-1.79.2/lib/rubocop/cli.rb:43:in run' /var/lib/gems/3.1.0/gems/rubocop-1.79.2/exe/rubocop:19:in <top (required)>'
/usr/local/bin/rubocop:25:in load' /usr/local/bin/rubocop:25:in

'

app/controllers/graduation_controller.rb

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.79.2/lib/rubocop/config_loader_resolver.rb:309:in rescue in gem_config_path' /var/lib/gems/3.1.0/gems/rubocop-1.79.2/lib/rubocop/config_loader_resolver.rb:293:in gem_config_path'
/var/lib/gems/3.1.0/gems/rubocop-1.79.2/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.79.2/lib/rubocop/config_loader_resolver.rb:82:in reverse_each'
/var/lib/gems/3.1.0/gems/rubocop-1.79.2/lib/rubocop/config_loader_resolver.rb:82:in block in resolve_inheritance_from_gems' /var/lib/gems/3.1.0/gems/rubocop-1.79.2/lib/rubocop/config_loader_resolver.rb:76:in each_pair'
/var/lib/gems/3.1.0/gems/rubocop-1.79.2/lib/rubocop/config_loader_resolver.rb:76:in resolve_inheritance_from_gems' /var/lib/gems/3.1.0/gems/rubocop-1.79.2/lib/rubocop/config_loader.rb:58:in load_file'
/var/lib/gems/3.1.0/gems/rubocop-1.79.2/lib/rubocop/config_store.rb:29:in options_config=' /var/lib/gems/3.1.0/gems/rubocop-1.79.2/lib/rubocop/cli.rb:162:in act_on_options'
/var/lib/gems/3.1.0/gems/rubocop-1.79.2/lib/rubocop/cli.rb:47:in block in run' /var/lib/gems/3.1.0/gems/rubocop-1.79.2/lib/rubocop/cli.rb:82:in profile_if_needed'
/var/lib/gems/3.1.0/gems/rubocop-1.79.2/lib/rubocop/cli.rb:43:in run' /var/lib/gems/3.1.0/gems/rubocop-1.79.2/exe/rubocop:19:in <top (required)>'
/usr/local/bin/rubocop:25:in load' /usr/local/bin/rubocop:25:in

'

  • 5 others

Tip

👮 Agentic pre-merge checks are now available in preview!

Pro plan users can now enable pre-merge checks in their settings to enforce checklists before merging PRs.

  • Built-in checks – Quickly apply ready-made checks to enforce title conventions, require pull request descriptions that follow templates, validate linked issues for compliance, and more.
  • Custom agentic checks – Define your own rules using CodeRabbit’s advanced agentic capabilities to enforce organization-specific policies and workflows. For example, you can instruct CodeRabbit’s agent to verify that API documentation is updated whenever API schema files are modified in a PR. Note: Upto 5 custom checks are currently allowed during the preview period. Pricing for this feature will be announced in a few weeks.

Please see the documentation for more information.

Example:

reviews:
  pre_merge_checks:
    custom_checks:
      - name: "Undocumented Breaking Changes"
        mode: "warning"
        instructions: |
          Pass/fail criteria: All breaking changes to public APIs, CLI flags, environment variables, configuration keys, database schemas, or HTTP/GraphQL endpoints must be documented in the "Breaking Change" section of the PR description and in CHANGELOG.md. Exclude purely internal or private changes (e.g., code not exported from package entry points or explicitly marked as internal).

Please share your feedback with us on this Discord post.


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.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@ryufuta ryufuta self-assigned this Aug 5, 2025
@ryufuta ryufuta force-pushed the chore/replace-newspaper-in-correct_answer-graduation-comeback branch 2 times, most recently from 4e3bdae to 6b5dde6 Compare August 19, 2025 08:45
@ryufuta ryufuta force-pushed the chore/replace-newspaper-in-correct_answer-graduation-comeback branch from 6b5dde6 to e206393 Compare September 12, 2025 11:06
@ryufuta ryufuta marked this pull request as ready for review September 13, 2025 12:21
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: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
app/controllers/api/correct_answers_controller.rb (1)

18-22: NameErrorの致命的バグ: @answer が未定義

update内でanswerローカルを更新後に@answerを参照しています。実行時に未定義参照になります。ローカル変数に合わせて修正してください。

   def update
     answer = @question.answers.find(params[:answer_id])
     answer.update!(type: '')
-    Newspaper.publish(:answer_save, { answer: @answer })
+    Newspaper.publish(:answer_save, { answer: answer })
   end
🧹 Nitpick comments (1)
app/controllers/graduation_controller.rb (1)

12-12: イベント発火位置が適切

更新成功後にgraduation.updateを発火しており一貫しています。必要に応じて「確定後」を保証したい場合はafter_commitでの発火も検討ください(任意)。

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between c7665c5 and e206393.

📒 Files selected for processing (9)
  • app/controllers/api/correct_answers_controller.rb (1 hunks)
  • app/controllers/comeback_controller.rb (1 hunks)
  • app/controllers/graduation_controller.rb (1 hunks)
  • app/models/comeback_notifier.rb (1 hunks)
  • app/models/correct_answer_notifier.rb (1 hunks)
  • app/models/graduation_notifier.rb (1 hunks)
  • app/models/question_auto_closer.rb (1 hunks)
  • config/initializers/active_support_notifications.rb (2 hunks)
  • config/initializers/newspaper.rb (0 hunks)
💤 Files with no reviewable changes (1)
  • config/initializers/newspaper.rb
🧰 Additional context used
📓 Path-based instructions (1)
**/*.rb

⚙️ CodeRabbit configuration file

**/*.rb: # refactoring

  • まずFat Controllerを避け、次にFat Modelを避ける。
  • Serviceクラスの乱用を避ける。
  • controller concernを作ろうとしたらPORO(Plain Old Ruby Object)やActiveRecordモデルでの実装で代替できないか検討する。

Rails Patterns

  • ViewHelperにメソッドを実装する時にはまずDecoratorパターンを使うことを検討する。(active_decorator gemを導入しているのでそれを使う)
  • 複雑なActiveRecordクエリがあり、再利用できそうな場合はQueryObjectパターンを検討する。(rails-patterns gemを導入しているのでそれのQuery機能を使う)
  • Viewにpartialを作る場合はViewComponentを使うことを検討する。
  • 複数のActiveRecordモデルを操作する1つの責務がある時や外部APIとやりとりする処理がある場合にはInteractorオブジェクトパターンを検討する。(interactor gemを導入しているのでそれを使う)
  • 複数のInteractorを実行するような処理がある場合Organizerオブジェクトパターンを検討する。(interactor gemを導入しており、その中にOrganizerの機能があるので使う)

Files:

  • app/controllers/api/correct_answers_controller.rb
  • app/models/question_auto_closer.rb
  • app/controllers/graduation_controller.rb
  • app/models/graduation_notifier.rb
  • app/models/comeback_notifier.rb
  • app/models/correct_answer_notifier.rb
  • config/initializers/active_support_notifications.rb
  • app/controllers/comeback_controller.rb
🧠 Learnings (3)
📓 Common learnings
Learnt from: matuaya
PR: fjordllc/bootcamp#9108
File: app/models/after_user_retirement.rb:0-0
Timestamp: 2025-09-01T22:31:57.345Z
Learning: fjordllc/bootcampプロジェクトにおいて、`Newspaper.publish(:retirement_create, { user: user })`は通知処理ではなく、UnfinishedDataDestroyerやTimesChannelDestroyer等による重要なデータクリーンアップ処理を実行するため、管理者による退会(triggered_by: 'admin')の場合でも必ず実行する必要がある。
Learnt from: matuaya
PR: fjordllc/bootcamp#9108
File: app/models/after_user_retirement.rb:0-0
Timestamp: 2025-09-01T22:31:57.345Z
Learning: fjordllc/bootcampプロジェクトにおいて、`Newspaper.publish(:retirement_create, { user: user })`はUnfinishedDataDestroyer(未チェックProduct・WIP Report削除、career_pathリセット)とTimesChannelDestroyer(Discord分報チャンネル削除)による重要なデータクリーンアップ処理を実行するため、退会のトリガーが何であろうと(admin、hibernation、user)必ず実行する必要がある。
Learnt from: reckyy
PR: fjordllc/bootcamp#8356
File: app/models/notification.rb:45-47
Timestamp: 2025-07-15T12:58:02.735Z
Learning: fjordllc/bootcampプロジェクトの`app/models/notification.rb`において、`training_completed`通知種別は`TARGETS_TO_KINDS`ハッシュに含めない設計になっている。これは`training_completed`が通知一覧のフィルタ対象ではないためで、意図的な設計判断である。
Learnt from: Miya096jp
PR: fjordllc/bootcamp#9102
File: app/controllers/mentor/buzzes_controller.rb:0-0
Timestamp: 2025-09-04T01:39:22.261Z
Learning: fjordllc/bootcamp プロジェクトでは、更新処理の成功時の通知メッセージについて、I18n を使用せずに日本語文字列を直接記述する方針で一貫性を保っている。
Learnt from: jun-kondo
PR: fjordllc/bootcamp#0
File: :0-0
Timestamp: 2025-07-23T21:11:21.826Z
Learning: fjordllc/bootcampプロジェクトの`app/models/inquiry_notifier.rb`において、`NOTIFICATION_SENDER_NAME`で指定される管理者ユーザーは必ず存在することがシステムの前提条件として保証されているため、senderがnilになることは想定されておらず、エラーハンドリングは不要である。
Learnt from: komagata
PR: fjordllc/bootcamp#9101
File: app/models/graduation_notifier.rb:23-28
Timestamp: 2025-09-12T21:16:47.639Z
Learning: Rails upgrade PRにおいて、configuration systemの変更やwebhook設定の改善提案も、アップグレードに直接関連しない場合は別PRで対応すべきである。PRのスコープ維持が重要。
📚 Learning: 2025-09-01T22:31:57.345Z
Learnt from: matuaya
PR: fjordllc/bootcamp#9108
File: app/models/after_user_retirement.rb:0-0
Timestamp: 2025-09-01T22:31:57.345Z
Learning: fjordllc/bootcampプロジェクトにおいて、`Newspaper.publish(:retirement_create, { user: user })`は通知処理ではなく、UnfinishedDataDestroyerやTimesChannelDestroyer等による重要なデータクリーンアップ処理を実行するため、管理者による退会(triggered_by: 'admin')の場合でも必ず実行する必要がある。

Applied to files:

  • app/controllers/graduation_controller.rb
  • app/controllers/comeback_controller.rb
📚 Learning: 2025-09-01T22:31:57.345Z
Learnt from: matuaya
PR: fjordllc/bootcamp#9108
File: app/models/after_user_retirement.rb:0-0
Timestamp: 2025-09-01T22:31:57.345Z
Learning: fjordllc/bootcampプロジェクトにおいて、`Newspaper.publish(:retirement_create, { user: user })`はUnfinishedDataDestroyer(未チェックProduct・WIP Report削除、career_pathリセット)とTimesChannelDestroyer(Discord分報チャンネル削除)による重要なデータクリーンアップ処理を実行するため、退会のトリガーが何であろうと(admin、hibernation、user)必ず実行する必要がある。

Applied to files:

  • app/controllers/graduation_controller.rb
  • app/controllers/comeback_controller.rb
🔇 Additional comments (6)
app/models/question_auto_closer.rb (1)

100-103: 削除不可 — :answer_save の購読が残っているため Newspaper.publish は消さないでください

config/initializers/newspaper.rb に Newspaper.subscribe(:answer_save, answer_cache_destroyer) が存在します。かつ以下で Newspaper.publish(:answer_save, ...) が使われています:

  • app/models/question_auto_closer.rb:101
  • app/controllers/api/correct_answers_controller.rb:10,21
  • app/controllers/api/answers_controller.rb:33,42

対応方針: 購読者(AnswerCacheDestroyer 等)を先に ActiveSupport::Notifications 側へ移行し、初期化ファイルの subscribe を置換してから Newspaper.publish を削除すること。不要確認が取れるまで旧経路は残してください。

Likely an incorrect or invalid review comment.

app/models/correct_answer_notifier.rb (1)

4-4: AS::Notificationsの5引数シグネチャ対応、問題なし

購読コールバックの引数順・未使用変数のプレフィックス運用ともに適切です。

config/initializers/active_support_notifications.rb (1)

7-7: 新規サブスクリプションの追加、妥当です

イベント名・購読先ともに目的に合致しています。既存と同様to_prepare内での登録ですが、開発環境の再読み込みで重複登録しないかだけ念のため確認ください(本プロジェクトの既存方針に倣うならこのままでOK)。

Also applies to: 34-35

app/controllers/comeback_controller.rb (1)

15-15: イベント発火の順序が妥当

comeback!直後にcomeback.updateを発火しており、Notiferの前提とも整合しています。

app/models/comeback_notifier.rb (1)

4-4: 5引数シグネチャへの対応OK

ペイロードの取り扱いのみで十分で、互換性も問題ありません。

app/models/graduation_notifier.rb (1)

4-4: 5引数シグネチャへの対応OK

既存ロジックを保ったままインタフェースだけ揃えられています。

if @answer.save
Newspaper.publish(:answer_save, { answer: @answer })
Newspaper.publish(:correct_answer_save, { answer: @answer })
ActiveSupport::Notifications.instrument('correct_answer.save', answer: @answer)
Copy link
Copy Markdown

@coderabbitai coderabbitai bot Sep 13, 2025

Choose a reason for hiding this comment

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

💡 Verification agent

🧩 Analysis chain

二重イベント発火の可能性(Newspaper + Notifications)

Newspaper.publish(:answer_save, …)instrument('correct_answer.save', …)の併用は意図的ですか?移行完了後は旧経路を外すほうが安全です。少なくとも重複通知が発生していないか確認をお願いします。

削除する場合の最小差分:

-      Newspaper.publish(:answer_save, { answer: @answer })
       ActiveSupport::Notifications.instrument('correct_answer.save', answer: @answer)

確認用:


🏁 Script executed:

#!/bin/bash
rg -n "Newspaper\.subscribe\([^)]*answer_save" -C2

Length of output: 390


Newspaper.subscribe(:answer_save) が残っています — publish の削除は危険です(要修正)

config/initializers/newspaper.rb:5 に Newspaper.subscribe(:answer_save, answer_cache_destroyer) が存在します。コントローラから Newspaper.publish(:answer_save, ...) を削除すると AnswerCacheDestroyer(キャッシュ破棄等)が呼ばれなくなります。
対応案(いずれかを選択):

  • Newspaper.publish を維持する(既存サブスクライバに依存)。
  • AnswerCacheDestroyer を ActiveSupport::Notifications ('correct_answer.save' 等) に移行してから config/initializers/newspaper.rb の subscribe を削除/更新。
🤖 Prompt for AI Agents
In app/controllers/api/correct_answers_controller.rb around line 11, removing
Newspaper.publish(:answer_save, ...) breaks the existing
Newspaper.subscribe(:answer_save, answer_cache_destroyer) defined in
config/initializers/newspaper.rb so AnswerCacheDestroyer no longer runs; either
restore the Newspaper.publish(:answer_save, answer: @answer) call here to keep
current subscribers working, or migrate the AnswerCacheDestroyer to listen to
ActiveSupport::Notifications by subscribing to the 'correct_answer.save' event
(update AnswerCacheDestroyer to accept the AS::Notifications payload and change
the initializer to remove or update the Newspaper.subscribe accordingly); ensure
the chosen approach preserves the event payload shape and side effects (cache
invalidation) and update tests if needed.

Copy link
Copy Markdown
Contributor Author

@ryufuta ryufuta Sep 14, 2025

Choose a reason for hiding this comment

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

@coderabbitai
削除したのはNewspaper.publish(:correct_answer_save, { answer: @answer })です。
Newspaper.publish(:answer_save, { answer: @answer })は削除していないので問題ありません。

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

@ryufuta その通りですね。申し訳ありませんでした。

diffを再確認すると、削除されているのは確かに :correct_answer_save イベントのみで、:answer_save イベントは残されていることが分かります。つまり既存の AnswerCacheDestroyer は引き続き正常に動作し、キャッシュ無効化処理も維持されます。

私の前回の分析が間違っていました。この実装は問題ありません。


🧠 Learnings used
Learnt from: matuaya
PR: fjordllc/bootcamp#9108
File: app/models/after_user_retirement.rb:0-0
Timestamp: 2025-09-01T22:31:57.345Z
Learning: fjordllc/bootcampプロジェクトにおいて、`Newspaper.publish(:retirement_create, { user: user })`はUnfinishedDataDestroyer(未チェックProduct・WIP Report削除、career_pathリセット)とTimesChannelDestroyer(Discord分報チャンネル削除)による重要なデータクリーンアップ処理を実行するため、退会のトリガーが何であろうと(admin、hibernation、user)必ず実行する必要がある。

Learnt from: matuaya
PR: fjordllc/bootcamp#9108
File: app/models/after_user_retirement.rb:0-0
Timestamp: 2025-09-01T22:31:57.345Z
Learning: fjordllc/bootcampプロジェクトにおいて、`Newspaper.publish(:retirement_create, { user: user })`は通知処理ではなく、UnfinishedDataDestroyerやTimesChannelDestroyer等による重要なデータクリーンアップ処理を実行するため、管理者による退会(triggered_by: 'admin')の場合でも必ず実行する必要がある。

Learnt from: reckyy
PR: fjordllc/bootcamp#8356
File: app/models/notification.rb:45-47
Timestamp: 2025-07-15T12:58:02.735Z
Learning: fjordllc/bootcampプロジェクトの`app/models/notification.rb`において、`training_completed`通知種別は`TARGETS_TO_KINDS`ハッシュに含めない設計になっている。これは`training_completed`が通知一覧のフィルタ対象ではないためで、意図的な設計判断である。

Learnt from: Miya096jp
PR: fjordllc/bootcamp#9102
File: app/controllers/mentor/buzzes_controller.rb:0-0
Timestamp: 2025-09-04T01:39:22.261Z
Learning: fjordllc/bootcamp プロジェクトでは、更新処理の成功時の通知メッセージについて、I18n を使用せずに日本語文字列を直接記述する方針で一貫性を保っている。

Learnt from: jun-kondo
PR: fjordllc/bootcamp#0
File: :0-0
Timestamp: 2025-07-23T21:11:21.826Z
Learning: fjordllc/bootcampプロジェクトの`app/models/inquiry_notifier.rb`において、`NOTIFICATION_SENDER_NAME`で指定される管理者ユーザーは必ず存在することがシステムの前提条件として保証されているため、senderがnilになることは想定されておらず、エラーハンドリングは不要である。

Learnt from: komagata
PR: fjordllc/bootcamp#9101
File: app/models/graduation_notifier.rb:23-28
Timestamp: 2025-09-12T21:16:47.639Z
Learning: Rails upgrade PRにおいて、configuration systemの変更やwebhook設定の改善提案も、アップグレードに直接関連しない場合は別PRで対応すべきである。PRのスコープ維持が重要。

Copy link
Copy Markdown
Contributor Author

@ryufuta ryufuta left a comment

Choose a reason for hiding this comment

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

@coderabbitai
#9015 (review) のCaution内の指摘については #9155 で既に対応中なので本PRでは対応しません。

@fjordllc fjordllc deleted a comment from coderabbitai bot Sep 14, 2025
@ryufuta
Copy link
Copy Markdown
Contributor Author

ryufuta commented Sep 14, 2025

@matuaya
お疲れ様です!
こちらお手隙の際にレビューをお願いできますか?

@ryufuta ryufuta requested a review from matuaya September 14, 2025 14:03
@matuaya
Copy link
Copy Markdown
Contributor

matuaya commented Sep 14, 2025

@ryufuta
お疲れ様です!
レビュー承りました😊
数日お時間いただけると助かります🙏

Copy link
Copy Markdown
Contributor

@matuaya matuaya left a comment

Choose a reason for hiding this comment

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

遅くなってしまい申し訳ありません💦

動作バッチリ問題ありませんでした😊Approveさせていただきます!

@ryufuta
Copy link
Copy Markdown
Contributor Author

ryufuta commented Sep 19, 2025

@matuaya
レビューありがとうございます🙏
全然遅くないと思いますよ〜

@ryufuta
Copy link
Copy Markdown
Contributor Author

ryufuta commented Sep 19, 2025

@komagata
こちらのレビューをお願いします🙏
(大倉さんは今月はお忙しいと思いますので駒形さんに依頼しています)

@komagata komagata requested review from komagata and removed request for okuramasafumi October 1, 2025 03:47
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 0d44aed into main Oct 1, 2025
26 checks passed
@komagata komagata deleted the chore/replace-newspaper-in-correct_answer-graduation-comeback branch October 1, 2025 03:48
@github-actions github-actions bot mentioned this pull request Oct 1, 2025
16 tasks
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