Skip to content

定期イベントの主催者が追加されたら新しく任命された人に通知する#9593

Closed
yokomaru wants to merge 15 commits intomainfrom
feature/notify-added-organizer-of-regular-event
Closed

定期イベントの主催者が追加されたら新しく任命された人に通知する#9593
yokomaru wants to merge 15 commits intomainfrom
feature/notify-added-organizer-of-regular-event

Conversation

@yokomaru
Copy link
Contributor

@yokomaru yokomaru commented Feb 1, 2026

Issue

概要

  • 新しく追加された定期イベントの主催者に通知(お知らせ+メール)を送るようにした
  • 以下動線の時に通知が発火される
    • イベントの更新時に主催者が追加される場合は追加された主催者全員に通知がいく(イベント更新前と更新後の主催者で差分を取って送信する)
      • 自分自身を追加する場合は通知が行かないようにした
    • ユーザーの退会・休会・研修終了時に定期イベントの主催者が自動的に変更される場合はkomagataさんに通知がいく(念の為この場合もイベント更新前と更新後の主催者で差分を取って送信する)
      • 今まではステータスに関わらずkomagataさんに変更されていたが、このPRで開催中のイベントにスコープを絞る
      • スコープを統一するために主催だけではなく参加イベントも開催中のイベントのみに抜けるように修正した

実装について

退会/休会/研修終了の主催者削除〜通知動線

旧動線(通知追加前)

sequenceDiagram
Controller->>User: delete_and_assign_new_organizer

loop for each organizer
  User->>Organizer: delete_and_assign_new

  activate Organizer
  Organizer->>Organizer: delete
  Organizer->>RegularEvent: assign_admin_as_organizer_if_none
  deactivate Organizer
end
Loading
  • 各モデルの処理自体はシンプルだったが、User→Organizer→RegularEventに処理が分散していたため全体像が追いづらかった
  • 上記の結果、既存の構造を保ったままだと通知を置く適切な場所を探すのが難しかった
    • User起点: 通知に必要な差分情報を返すために全階層のメソッドの戻り値を修正する必要があった
    • Organizer起点: 中間モデルが削除+主催者の追加(他の主催者の存在チェックも含む)+通知まで行うのは責務が多くなり過ぎている
    • RegularEvent起点: 呼び出した場所から深い階層からの発火になるため意図しない副作用(コールバック的な挙動)になってしまう
    • Controller起点: 退会/休会/研修終了など複数箇所に通知ロジックを置く必要が出てしまいDRYにならない
  • メソッド名が具体的な処理名(delete_and_assign_new)だったため、ここに通知も追加すると名前が冗長になってしまう

新動線(通知追加後)

sequenceDiagram
    Controller->>User: hand_over_organizers_of_holding_regular_events

    loop 開催済みのイベントごとに実行
        User->>RegularEvent: hand_over_organizer(organizer, sender)

        activate RegularEvent
        RegularEvent->>RegularEvent: before_organizer_user_idsを取得
        Note right of RegularEvent: 主催者削除前の主催者を取得しておく
        RegularEvent->>Organizer: delete
        RegularEvent->>RegularEvent: assign_admin_as_organizer_if_none
        Note right of RegularEvent: 主催者がいなくなれば管理者を追加

        RegularEvent->>RegularEvent: notify_new_organizer(sender:, before_organizer_user_ids)
        Note right of RegularEvent: 追加した管理者にinstrument('organizer.create') を実行
        deactivate RegularEvent
    end
Loading
  • UserがRegularEventに主催者の引き継ぎという大きな単位(hand_over_organizer)で依頼するようにした
    • 主催者の削除や補填、通知といった処理をカプセル化し、1つのイベントに対する削除・追加・通知の処理はRegularEventが実行する
    • Userはループを回して依頼するだけとなり、詳細な手順は知らなくても良い(hand_over_organizers_of_holding_regular_events)
  • その分hand_over_organizerメソッドの責務が大きくなっているが、今後さらに処理を追加する場合などは別のモデルに切り出すなどの検討も可能

定期イベント更新の通知動線

新動線

sequenceDiagram
    Controller->>RegularEvent: notify_new_organizer(sender:, before_organizer_user_ids)
    Note right of RegularEvent: 主催者の差分を計算しinstrument('organizer.create') を実行
Loading
  • RegularEvent: notify_new_organizerに更新前の主催者と追加した主催者を加えた差分を計算し、新しく追加された主催者のみに通知を行う

退会/休会/研修終了時に対象となるイベントのスコープを開催中のみに変更

  • 退会画面等で、自身が開催している主催イベントについての注意メッセージが表示されるが、ここは開催中のみのスコープに絞って表示されているが、現状の主催者から削除動線では終了済みのイベントからも削除になっている
  • https://github.com/fjordllc/bootcamp/issues/9258#issuecomment-3749665476にて、 退会/休会/研修終了動線では開催中のイベントのみから離脱するように決定した
    • 退会/休会/研修終了は主催だけではなく通常参加しているイベントからも抜けるようになっている
      • そちらも合わせて開催中のみから抜けるようにこのPRにて修正した(ミーティングでこちらのPRで対応することを同意済み)
  • RegularEventにwhere(finished: false)を定義するスコープが2つあった(holdingnot_finished)

補足

変更確認方法

1. イベント更新時の主催者追加通知

手順

  • komagataでログイン
  • Everyday Rails輪読会: http://localhost:3000/regular_events/470315189 などの自分が参加していないイベントを開く
  • 主催者として以下を追加して内容変更をクリック
    • komagata
    • hatsuno
  • 主催者にkomagata / hatsunoが追加されていること

通知の確認(komagata

通知の確認(hatsuno)

  • hatsunoでログイン
    • お知らせ通知ベルや 通知一覧: http://localhost:3000/notifications に主催者に追加された旨の通知が表示されている(まだクリックしない)
    • letter_opener: http://localhost:3000/letter_opener にもメールが送信されている
    • メールの定期イベント詳細へをクリックするとイベント詳細ページに遷移する
    • 通知が既読になっている(通知ベルの未読に表示されず、全ての方に表示される)

2. 退会/休会/研修終了時の主催者引き継ぎ通知

  • 3ケースとも同一ロジックのため退会で詳細確認、休会/研修終了は通知が飛ぶことの確認のみ行う

2-1. 退会

事前準備
  • hajimeでログイン
  • hajimeが主催に含まれる以下の定期イベントを用意
    • 新規作成する必要あり

      • 開催中かつ主催者が1人のイベント
      • 終了済みイベント(主催者は1人でも複数でもOK)
        • 下部のイベント終了にチェックを入れる
    • 既存のイベントを利用可能

  • 適当なイベントに参加する
手順
  • hajimeで退会画面へ遷移
  • 主催中イベント一覧の注意メッセージに以下が表示されている
    • 事前準備で用意した開催中かつ主催者が1人のイベント
    • 事前準備で用意した開催中かつ主催者が複数人のイベント
  • 必須項目を入力して退会処理を実行
退会後の確認(komagata)
  • komagataでログイン
  • 以下を確認
    • 主催イベント
      • 開催中かつ主催者が1人のイベント
        • 主催者がkomagataになっていること
      • 開催中かつ主催者が複数人のイベント:
        • 主催者からhajimeが抜けていること
      • 終了済みイベント(主催者は1人でも複数でもOK)
        • 主催者はhajimeのままになっている
    • 参加イベント
    • 開催中のイベント(独習Git輪読会: http://localhost:3000/users/991528156)
      • 参加者からhajimeが消えている
    • 終了中のイベント(定期イベント8: http://localhost:3000/regular_events/582552593)
      • hajimeは参加者のままになっている

2-2. 休会

手順

  • hatsunoなど適当なアカウントでログイン
  • 主催者が1人の開催中イベントを用意
  • 休会画面に主催中イベントが表示されている
  • 休会処理を実行

確認(komagata

2-3. 研修終了

手順

  • kensyu(研修生)でログイン
  • 主催者が1人の開催中イベントを用意
  • 研修終了画面に主催中イベントが表示されている
  • 研修終了処理を実行

確認(komagata)

Screenshot

通知

お知らせ通知ベル

通知一覧

メール文

Summary by CodeRabbit

  • 新機能

    • 定期イベントの「主催者に追加」通知(メール送信・配信処理・通知購読)を追加しました。
  • 改善

    • 退会/引退時の参加取消と主催者引き継ぎを「未終了イベント(開催中)」に限定し、引き継ぎフローと主催者変更時の通知を強化しました。
  • テスト

    • 追加通知・メール・プレビュー・ハンドオーバーに関するテストを追加・拡充しました。

@coderabbitai
Copy link

coderabbitai bot commented Feb 1, 2026

📝 Walkthrough

Walkthrough

未完了(holding)定期イベントのみを対象に主催者の引き継ぎ処理を導入し、新主催者追加時の通知経路(ActiveSupport::Notifications → OrganizerNotifier → ActivityDelivery → ActivityMailer)と関連テスト/ビューを追加しました。コントローラ/退職・訓練完了フローは呼び出し先を差し替えています。

Changes

Cohort / File(s) Summary
User / Retirement / Controllers
app/models/user.rb, app/models/retirement.rb, app/controllers/hibernation_controller.rb, app/controllers/training_completion_controller.rb
従来の全参加/全主催者向けメソッドを削除し、未完了イベント(holding)対象のcancel_participation_from_holding_regular_eventshand_over_organizers_of_holding_regular_eventsを追加/呼び出し先を差し替え。
RegularEvent & Organizer behavior
app/models/regular_event.rb, app/models/organizer.rb
RegularEvent#hand_over_organizer#notify_new_organizerを追加。assign_admin_as_organizer_if_noneを復帰(private)。Organizerから旧削除メソッドを除き、scope :holdingを追加。
Participation scope
app/models/regular_event_participation.rb
scope :holding を追加し、参加を holding(未完了)イベントで絞れるように。
Notification types & subscription
app/models/notification.rb, config/initializers/active_support_notifications.rb, app/models/organizer_notifier.rb
Notification enum に added_organizer を追加。organizer.add を購読するハンドラ OrganizerNotifier を追加し、新規主催者向け配信を作成。
Notifier / Mailer / Views
app/notifiers/activity_notifier.rb, app/mailers/activity_mailer.rb, app/views/activity_mailer/added_organizer.html.slim
added_organizer 用の notifier/mail メソッドとメールビューを追加。配信制御は既存パターンに準拠。
Controller hook
app/controllers/regular_events_controller.rb
更新前の organizer user_ids を保持し、更新後に notify_new_organizer を呼ぶよう変更(クラスに rubocop:disable コメント追加)。
Delivery / Notifier tests & Mailer previews
test/deliveries/activity_delivery_test.rb, test/notifiers/activity_notifier_test.rb, test/mailers/activity_mailer_test.rb, test/mailers/previews/activity_mailer_preview.rb
.notify(:added_organizer) の配信テスト、notifier テスト、mailer テストとプレビューを追加。
Model & Unit tests updates
test/models/user_test.rb, test/models/regular_event_test.rb, test/models/organizer_notifier_test.rb, test/models/organizer_test.rb
User/RegularEvent の既存テストを holding スコープ/hand_over_* に合わせて更新・拡張。古い Organizer のテストを削除。

Sequence Diagram(s)

sequenceDiagram
    participant RE as RegularEvent
    participant ASN as ActiveSupport::Notifications
    participant ON as OrganizerNotifier
    participant AD as ActivityDelivery
    participant AM as ActivityMailer

    RE->>RE: hand_over_organizer(organizer, sender)
    RE->>ASN: instrument 'organizer.add' (regular_event, sender, new_organizer_users)
    ASN->>ON: deliver payload
    ON->>AD: ActivityDelivery.with(...).notify(:added_organizer)
    AD->>AM: ActivityMailer.added_organizer with(regular_event, receiver, sender)
    AM->>AM: build mail and enqueue/send
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related issues

Possibly related PRs

Suggested reviewers

  • komagata
  • hirokiej

Poem

🐰📣 新しい主催よ、ようこそと跳ぶ僕
未完の場を見守り手をつなぐよ
管理者は影でそっと支え
バトン渡れば通知の風が行く
みんなで祝おう、ぴょんと一声

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 6.45% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed タイトルは、定期イベントの主催者が追加された場合に新しく任命された人に通知を送るという主要な変更内容を正確かつ簡潔に要約しており、変更内容と完全に関連している。
Description check ✅ Passed PRの説明は包括的に記載されており、Issueの参照、詳細な概要、実装内容(シーケンス図含む)、変更確認方法が完備されている。

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feature/notify-added-organizer-of-regular-event

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.

@yokomaru yokomaru self-assigned this Feb 2, 2026
@yokomaru yokomaru force-pushed the feature/notify-added-organizer-of-regular-event branch from c4e93ba to 45cb9a0 Compare February 2, 2026 16:31
@yokomaru yokomaru marked this pull request as ready for review February 2, 2026 16:38
@github-actions github-actions bot requested a review from komagata February 2, 2026 16:38
- 処理の起点となるユーザーには通知しないようにする
- テストも追加
…ganizerを定義して責務を移動した

- テストを追加
- assign_admin_as_organizer_if_noneをprivateに変更したため関連テストを削除
- 不要になったOrganizerのメソッドとテストを削除
- メソッド名が実装詳細に寄っていたため、
主催者の引き継ぎとして処理(削除〜通知)を集約した
- 対象は未終了の定期イベントに限定しテストを追加
- Organizerに未終了の定期イベントに絞るスコープを追加
- 未終了の定期イベント参加を削除する`cancel_participation_from_not_finished_regular_events`を追加
- RegularEventParticipationに`not_finished`スコープを追加
- 終了済みイベントの参加が削除されないことをテストに追加
- 一時的にRubocop:disable Metrics/ClassLengthを追加
- update前に差分用にbefore_user_idsを取得する処理を追加
@yokomaru yokomaru force-pushed the feature/notify-added-organizer-of-regular-event branch from 45cb9a0 to cc9f0d2 Compare February 2, 2026 21:49
@yokomaru
Copy link
Contributor Author

yokomaru commented Feb 2, 2026

@coderabbitai review

@coderabbitai
Copy link

coderabbitai bot commented Feb 2, 2026

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

- User側でループを回して各処理(主催者削除&追加と通知)を個別にRegularEventに依頼していたが、
  引き継ぎ処理という1つのまとまりとしてRegularEventに処理を依頼(hand_over_organizer)し、
  User側では対象イベントのスコープを絞るのみに修正した(hand_over_not_finished_regular_event_organizers)
- 上記に合わせてメソッド名やテストの修正などを行った
- 通知処理のモデルは他のモデルとあわせてとモデル名+Notifier(OrganizerNotifier)に変更した
- 終了済みイベントのタイトルを修正
- 複数イベントが処理されるメソッドのため、各イベントの期待する結果をコメントで追加
- 通知が飛んでいることも確認するためassert_differenceを追加
@yokomaru yokomaru force-pushed the feature/notify-added-organizer-of-regular-event branch from e65fad1 to d5d58b8 Compare February 4, 2026 07:48
@yokomaru yokomaru changed the title 定期イベントの主催者が変更されたら新しく任命された人に通知する 定期イベントの主催者が追加されたら新しく任命された人に通知する Feb 4, 2026
@yokomaru yokomaru requested a review from ryufuta February 5, 2026 01:43
@yokomaru yokomaru closed this Feb 8, 2026
@yokomaru yokomaru reopened this Feb 8, 2026
end

def notify_new_organizer(sender:, before_organizer_user_ids:)
new_organizer_user_ids = (organizers.pluck(:user_id) - before_organizer_user_ids) - [sender.id]
Copy link
Contributor Author

Choose a reason for hiding this comment

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

organizers.pluck(:user_id)を再度呼び出して、更新処理後の最新のuser_idsを取得しその差分を比較しています

def hand_over_organizer(organizer:, sender:)
before_organizer_user_ids = organizers.pluck(:user_id)

organizer.delete
Copy link
Contributor Author

@yokomaru yokomaru Feb 12, 2026

Choose a reason for hiding this comment

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

  • destroyではなくdeleteを使用しているのは既存の処理であるdelete_and_assign_newを参考にしています(本当はdestroyを使う方がいいとは思うのですが、他にいい方法が浮かばず一旦このまま踏襲しています)
    • RegularEventとOrganizersはpresent: true関連があり、organizersが1人しかいない状態でdestroyを行うとバリデーションエラーになるため、deleteを使用し一時的に関連を無視してorganizerを削除後、主催者が0人の場合は管理者(komagata)を追加している
def delete_and_assign_new
    event = regular_event
    delete
    event.assign_admin_as_organizer_if_none
end

Copy link
Contributor

@ryufuta ryufuta Feb 28, 2026

Choose a reason for hiding this comment

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

この機能は削除することになったのでもう関係はないですが、一応コメントします。
懸念している通りdeleteするのは行儀が悪いので避けたいですね。

もっと綺麗に書けるかもしれませんが、以下のような流れでいけると思います。

if organizers.count > 1
  organizer.destory
  return

# 主催者が引数で渡ってきた`organizer`一人だけなので`komagata`を主催者に追加した後`organizer.destory`する処理
# ...

notify_new_organizer(sender:, before_organizer_user_ids:)

@yokomaru
Copy link
Contributor Author

@ryufuta
ご連絡遅くなり申し訳ありません!🙏
口頭では別途依頼させていただいておりましたが、PRの準備ができたためお手隙でレビューをお願いいたします!
急ぎではないのでお時間ある時で大丈夫です。
検証項目多くてお手数おかけいたしますが、よろしくお願いいたします🙇‍♀️

@ryufuta
Copy link
Contributor

ryufuta commented Feb 12, 2026

@yokomaru
2週間以内を目安にレビューを返します!

@yokomaru
Copy link
Contributor Author

@ryufuta
ありがとうございます!
お手数おかけいたしますがよろしくお願いいたします🙌

@yokomaru
Copy link
Contributor Author

#9258 (comment) の経緯のため、こちらのPRは一度closeします!

@yokomaru yokomaru closed this Feb 25, 2026
Copy link
Contributor

@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.

@yokomaru
一応コメントを残しておきます。
現状のこのPRで仕様通り実装できていることは確認済みです👍
お疲れ様でした。(そして面倒なことになって申し訳ないです🙇🏻‍♂️)

コードについても一応コメントしておきました。
全体的な設計については正直私もどうするのがベターかまだ悩んでいます🤔
ご自身で再検討後にモブプロなどで取り組みたいとのことでしたので、コメントに返信は不要ですしなんなら見なくても大丈夫です。


def update
set_wip
before_organizer_user_ids = @regular_event.organizers.pluck(:user_id)
Copy link
Contributor

Choose a reason for hiding this comment

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

before_organizer_user_idsを直訳すると"主催者ユーザーIDの(時間的もしくは位置的に)前に"という意味になり変です。
他の箇所で、更新後の主催者をnew_organizer_usersとしているのでそれとの対比でold_organizer_user_idsとすると良さそうです。

def delete_and_assign_new_organizer
organizers.each(&:delete_and_assign_new)
def cancel_participation_from_holding_regular_events
regular_event_participations.holding.destroy_all
Copy link
Contributor

Choose a reason for hiding this comment

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

ここでの"開催中の"という意味にはactiveが一番しっくり来ると思います。
英語的にも自然で日本語話者にも通じやすいです。
既存のscopeにあるholdingと合わせたのだと思いますが、hold(開催する)をholdingの形で使用することはほとんどないように思います。
holding_regular_eventsだと"定期イベントを開催すること"という意味になりそうです。
他の箇所のholdingactiveに統一すると良いと思います。

Comment on lines +193 to +194
sender = User.find(ActiveRecord::FixtureSet.identify(:kimura))
ActivityMailer.with(regular_event:, receiver:, sender:).added_organizer
Copy link
Contributor

Choose a reason for hiding this comment

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

メール通知では基本的にデフォルトの自動送信用メールアドレスを使用するようになっています。

default from: 'フィヨルドブートキャンプ <noreply@bootcamp.fjord.jp>'

senderは不要では?
ActivityMailer#added_organizer内でもsenderのメールアドレスを使っていないのでデフォルトのものが使われています。
サーバー起動後以下にアクセスすると確認できます。
http://localhost:3000/rails/mailers/activity_mailer/added_organizer

あと大したことではないので修正するほどではないですが、テストデータは実際のシナリオに近いものを選んだ方がわかりやすいです。
regular_event1は開発MTGでkomagataorganizer1として初めから主催者に設定されています。
komagataが新たに主催者に任命されたという通知をテストするのには向かないと思いました。

Comment on lines +1289 to +1290
regular_event = RegularEvent.find(ActiveRecord::FixtureSet.identify(:regular_event1))
receiver = User.find(ActiveRecord::FixtureSet.identify(:komagata))
Copy link
Contributor

Choose a reason for hiding this comment

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

test/mailers/previews/activity_mailer_preview.rbと違ってrequire 'test_helper'を実行しているので以下のような書き方でfixtureを使えます。

Suggested change
regular_event = RegularEvent.find(ActiveRecord::FixtureSet.identify(:regular_event1))
receiver = User.find(ActiveRecord::FixtureSet.identify(:komagata))
regular_event = regular_events(:regular_event1)
receiver = users(:komagata)

こちらの方が可読性が高くて良いと思います。

test 'added_organizer' do
regular_event = RegularEvent.find(ActiveRecord::FixtureSet.identify(:regular_event1))
receiver = User.find(ActiveRecord::FixtureSet.identify(:komagata))
sender = User.find(ActiveRecord::FixtureSet.identify(:kimura))
Copy link
Contributor

Choose a reason for hiding this comment

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

ここもsenderは不要ですね。
実際に削除したところテストはパスしました。

sender = users(:hatsuno)

Organizer.create!(user_id: user.id, regular_event_id: regular_event.id)
Organizer.find_by!(user_id: sender.id, regular_event_id: regular_event.id).destroy!
Copy link
Contributor

Choose a reason for hiding this comment

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

ここでdestroy!をしている理由がわかりませんでした。
またcreate!の戻り値を受け取ってdestroy!を呼ぶ方が効率は良いです。

hold_national_holiday: false,
start_at: Time.zone.local(2020, 1, 1, 21, 0, 0),
end_at: Time.zone.local(2020, 1, 1, 22, 0, 0),
user: users(:kananashi),
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
user: users(:kananashi),
user: ,

置き換え忘れですかね?

@@ -0,0 +1,13 @@
# frozen_string_literal: true

class OrganizerNotifier
Copy link
Contributor

Choose a reason for hiding this comment

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

口頭でも伝えましたが、RegularEvent#notify_new_organizerからのみ呼ばれているのでRegularEventの外にクラスとして処理を切り出す意味はないのではと思いました。

Comment on lines +727 to +728
-> { user.regular_event_participations.holding.count } => -2,
-> { user.regular_event_participations.joins(:regular_event).merge(RegularEvent.where(finished: true)).count } => 0
Copy link
Contributor

Choose a reason for hiding this comment

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

以下の問題点があります。

  1. 開催中の定期イベントから参加者が削除されること、終了した定期イベントからは参加者が削除されないことの2つを同一のテストケースでテストしていてわかりにくい
  2. 参加者が削除されることのテストがusers(:kananashi)に依存した壊れやすいテストになっている
    • 将来的にfixtureにkananashiが参加する定期イベントが作成されると3つ以上のイベントが削除されるので失敗する
  3. テストコードに複雑なロジックが持ち込まれて可読性と保守性が低い
    • 特にこのテストケースの場合はテスト対象のメソッドと類似のロジックを再実装している。DRYでないし、本当にテストできているのかわからない。例えばholdingというscopeに「開催中ではなく終了したイベントを返すバグ」があっても「開催中の定期イベントから参加者が削除されること」のテストはパスします。

以下、解決策の案。
1については普通に2つのテストケースに分ければ問題なし。
試してはいないですが、それぞれのテストケース内で作成したholding_regular_eventfinished_regular_eventに対して.participants.countの値の変化を確認することで2と3の問題は両方解決できそうです。

def hand_over_organizer(organizer:, sender:)
before_organizer_user_ids = organizers.pluck(:user_id)

organizer.delete
Copy link
Contributor

@ryufuta ryufuta Feb 28, 2026

Choose a reason for hiding this comment

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

この機能は削除することになったのでもう関係はないですが、一応コメントします。
懸念している通りdeleteするのは行儀が悪いので避けたいですね。

もっと綺麗に書けるかもしれませんが、以下のような流れでいけると思います。

if organizers.count > 1
  organizer.destory
  return

# 主催者が引数で渡ってきた`organizer`一人だけなので`komagata`を主催者に追加した後`organizer.destory`する処理
# ...

notify_new_organizer(sender:, before_organizer_user_ids:)

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.

2 participants