Skip to content

Conversation

@mousu-a
Copy link
Contributor

@mousu-a mousu-a commented Apr 19, 2025

Issue

概要

現在ディスコードで行っているペアプロ(ペアワーク)の募集、申し込みをbootcampアプリ上で行える機能を実装しました!

仕様をこちらのページにまとめています。

https://www.notion.so/2cd7324eb1cb807ea8fdde29addd6b1a

このPRでやること

  • ペアワークのCRUD機能の実装
  • ペアワーク作成時の通知関連の実装

このPRでやらないこと

  • ペアワーク機能のリリース(後述するペアワークの追加機能issueが終わり次第リリースします。)
  • スケジュールの変更機能
    • 現在ペアワークのtitledescriptionなどは変更できますが、スケジュールは変更できないようになっています。
  • ペア取り消し機能、それに付随する通知関連

このPRでやらないことに関してはこちらのissueで対応します。

変更確認方法

  1. feature/support_pair_workをローカルに取り込む
    1. git fetch origin feature/support_pair_work
    2. git checkout feature/support_pair_work
  2. Develop環境でのDiscord通知の確認方法の設定を行う(後ほど通知の確認で必要になります)
  3. bin/devでローカルサーバーを立ち上げる。
  4. kimuraでログイン
  5. http://localhost:3000/current_user/edit
    主な活動予定時間セクションにて、(月)3:00、(水)4:00、(木)3:00をチェックし、ページ下部の"更新する"ボタンをクリック
  6. サイドバーのQ&A ペアワークロゴをクリック。ペアワークのタブをクリックし一覧画面へ
  7. 右上の「ペアを募集する」をクリックし、新規作成画面へ
  8. 各項目を入力する
    1. プラクティスはなんでも良いです🙆‍♂️(選択しなくても問題はありません)
    2. 例:lsコマンド実装ペアプロ募集!
    3. 例:Rubyで ls コマンドのクローンを作成する課題に取り組んでいます!UNIXコマンドの基本動作をRubyで再現しながら、ファイル操作やオプション処理の理解を深めたい方、ぜひ一緒に取り組みましょう。
  9. スケジュール表に、ユーザーの登録情報である"主な学習時間"に該当する日にちにあらかじめチェックが入っていることを確認する。((月)3:00、(水)4:00、(木)3:00)
    1. 当日の、現在時刻より前の時間帯はチェックがつきません
  10. 画面下部の「登録する」ボタンを押しペアワークを新規作成する
  11. こちらでメール通知の確認
    1. メンター(敬称略:new-mentorpjord, komagata,unadmentor,machidanohimitsu,mentormentaro)に通知が来ていることを確認
  12. 先ほど作成したディスコードサーバーに通知が来ていることを確認
  13. 先ほど新規作成した内容のshow画面を確認
  14. 画面下部の「内容修正」ボタンを押してedit画面へ
  15. 各項目を編集し「更新する」ボタンを押してアップデートできることを確認
  16. komagataで再度ログイン(通知の確認もしたいためメンターが良いです)
    1. 右上の通知を確認し、ペアワーク作成時のサイト内通知が来ていることを確認
  17. 通知からshowへ飛ぶ
  18. スケジュール表の✅をクリックし、ペアワークを申し込み、ペア確定する
    1. 右上の通知からサイト内通知が来ていることを確認
    2. こちらにて、ペアワーク作成者(kimura)、メンター(敬称略:new-mentorkomagata,machidanohimitsu,mentormentaro,unadmentor,pjord)にペア確定の通知が来ていることを確認
    3. 先ほど作成したディスコードサーバーに通知が来ていることを確認
  19. 右上の「ペアワーク一覧」をクリック、ペア確定タブをクリック。先ほどのレコードがペア確定になっているのを確認
  20. rails db:seedを実行し、kimuraで再ログイン、ダッシュボードにアクセス
  21. 近日開催のペアワークが表示されているのを確認

Screenshot

変更前

新機能なので変更前のスクリーンショットはありません!

変更後

一覧
スクリーンショット 2025-06-01 20 55 18
詳細
スクリーンショット 2025-06-01 20 55 59
詳細ペア確定後
スクリーンショット 2025-06-01 20 58 30
近日開催のペアワーク
image

Summary by CodeRabbit

  • 新機能

    • ペアワーク募集(作成・一覧・詳細・編集・削除)、スケジュール登録、マッチング、通知・メール配信を追加しました
    • ホームに「今後のペアワーク」表示を追加しました
    • 検索にペアワークを統合しました
  • 機能改善

    • タブに件数表示とバッジを追加、ページナビ構造を整理しました
  • スタイル

    • ペアワーク関連および複数コンポーネントのUIスタイルを更新しました
  • テスト

    • ペアワーク関連の単体/統合/システムテストを追加しました

✏️ Tip: You can customize this high-level summary in your review settings.

@mousu-a
Copy link
Contributor Author

mousu-a commented Apr 20, 2025

@machida
お疲れ様です!
こちらのデザインをお願いいたします🙏

ほとんどが既存のものを流用出来そうな作りだったので、出来る限り既存のものを流用する形で実装しています。
全体の確認や細かな調整、グローバルリンク(サイドバーのペアワークのロゴ(リンク))などお願いできればと思います🙏

@machida
Copy link
Member

machida commented Apr 20, 2025

@mousu-a 了解です!連絡ありがとうございますー

@machida machida force-pushed the feature/support_pair_work branch 2 times, most recently from 5d17011 to 8c0b692 Compare May 14, 2025 08:37
@machida
Copy link
Member

machida commented May 14, 2025

@mousu-a

お待たせしました!
デザイン入れました。
色々変更があるので説明します。


グローバルナビの変更

貼り付けた画像_2025_05_14_17_37

グローバルナビの項目が増えると画面を突き抜けるので、Q&Aといっしょにしています(docsと動画、特別イベントと定期イベント...などと同じです)。

グローバルナビの数字

貼り付けた画像_2025_05_14_17_37

この数字は未解決のQ&Aと未解決のペアワークの合計になっています。

ページの構成、タブ

image image

このようになっています。
タブでQ&A or ペアワークを選んだ上で、さらにタブで一覧表示の条件を選ぶようになっています。

まずはメンターのみ

ペアワーク詳細に表示されるペア希望はメンターだけに表示されるようにしてあります。
まずはテスト運用でメンターとだけペアワークができるようにします。
その後、メンターと、受講生と、誰でもいい、などペアワークのペアのロールの希望を入力できるように別Issueで機能追加をしたいと思います。

貼り付けた画像_2025_05_14_17_42

相手をペアに

相手という言葉ををペアに変更しました。

ペア変更

貼り付けた画像_2025_05_14_17_47

ペアが確定しているペアワークは日付選択が隠れています。

貼り付けた画像_2025_05_14_17_46

すでにペアが確定していても、そのペアの都合が悪くなったときに、代わりに自分がペアになれるようにしました。

機能追加要望

  • ペアが変わったことをペアワーク作成者に通知を飛ばしたいです。
  • ペアは変わらず日時が変更された場合もペアワーク作成者に通知を飛ばしたいです。

[機能追加] ペア取り消し機能

貼り付けた画像_2025_05_14_17_49

ペアが確定しているペアワークは日付選択が隠れています。

貼り付けた画像_2025_05_14_17_45

自分がペアになったんだけど、体調を崩したなどがあった際にキャンセルができるように取り消し機能がほしいです。

キャンセルボタンを押したら、「本当にいいですか?取り消したらコメントに一言書いてください。」みたいなメッセージを出したいです。

キャンセルされたことをペアワーク作成者に通知も飛ばしたいです。

@mousu-a
Copy link
Contributor Author

mousu-a commented May 14, 2025

@machida
デザインありがとうございます!!
確認させていただきます🙏


グローバルナビのQ&Aとペアワークのリンクを統合、了解です。
まずはメンターのみペアになれる、了解です。

追加の機能を下記にまとめました。間違いがないかご確認いただければと思います🙏

追加したい機能

  • 一度確定したペアワークは日時変更ができる
  • 一度確定したペアワークはペアを変更することができる
  • 一度確定したペアワークは(ペアになったメンターから)キャンセルができる(体調不良でどうしても出来ないなど)
    • ペア変更時、日時変更時、ペアキャンセル時、ペアワーク作成者に通知する
    • ペアキャンセル時にはconfirmメッセージを出す
  • とりあえずはメンターのみペアになれるようにする(ペアを募集中のペアワークに申し込めるのはメンターのみ)

間違っていたらツッコミください!
大丈夫そうであれば進めていきますー💪

@machida
Copy link
Member

machida commented May 14, 2025

@mousu-a 確認しました!その認識でOKですー🙆

@machida
Copy link
Member

machida commented May 15, 2025

@mousu-a
残りの作業について話し合いました。
追加の作業は行わずここまででの状態でテストの追加、修正などお願いします。
追加の機能に関しては別Issueで対応したいと思います。

ただ、今回の分は先にマージをしたいです。
なので、動画機能や分報機能と同じように、ペアワーク機能も本番では表示されないようにしていただきたいです。
残りの追加機能が実装されたら、本番でも表示されるようにして、リリースしたいと思います。

追加機能は省き、テストの追加、修正などを行ったらレビューに進めてください🙏

@mousu-a
Copy link
Contributor Author

mousu-a commented May 15, 2025

@machida
検討から連絡までありがとうございます!
追加の機能に関しては別Issueで対応、ペアワーク機能も本番では表示されないように 了解しました!
ではそのように進めます💪

@mousu-a mousu-a force-pushed the feature/support_pair_work branch 2 times, most recently from aa84c72 to aec1c26 Compare May 26, 2025 01:14
@mousu-a
Copy link
Contributor Author

mousu-a commented Jun 1, 2025

@machida (CC: @komagata )
お疲れ様です。ちょっと相談させていただきたいです!

1

ただ、今回の分は先にマージをしたいです。
なので、動画機能や分報機能と同じように、ペアワーク機能も本番では表示されないようにしていただきたいです。

ペアワーク機能は一時的に見えない状態でマージし、追加機能を実装後に見えるようにする、というこの方針ですが、追加機能を取り込むまでこのPR(ペアワーク機能)をマージしない というのではダメでしょうか?

理由としては、デザインの更新やQ&Aとの統合などもあり、単純にコメントアウトすれば良いというわけでもない箇所が多々あり、機能を見えない状態にするのもそうですが、戻す(見える状態にする)際もちょっと大変かなと思ったためです。

出来ないことはないですが、ちょっと作業量が膨大そうだったので先に相談させていただきました。ご検討いただければと思います🙏

2

これはmachidaさんに向けた質問になりますが、このPR(ペアワーク機能)を先にマージしておきたいのは、そうしないとペアワーク機能のリリースまでにコンフリクトが溜まってしまうから、ということでしょうか?

@machida
Copy link
Member

machida commented Jun 3, 2025

@mousu-a
僕の方で本番でペアワークを非表示にする実装を入れておいたので、このまま作業を進めてください。
env が test のときはペアワークも表示されているので、本番環境での表示は気にせずテストを追加お願いします🙏

そうしないとペアワーク機能のリリースまでにコンフリクトが溜まってしまうから、ということでしょうか?

そうですー

@mousu-a
Copy link
Contributor Author

mousu-a commented Jun 3, 2025

@machida
machidaさんありがとうございます!
引き続きあとちょっと進めていきます🙏

@machida
Copy link
Member

machida commented Jun 3, 2025

@mousu-a よろしくお願いしますー🙏

@mousu-a mousu-a force-pushed the feature/support_pair_work branch from 3eecb71 to e356988 Compare June 13, 2025 08:19
@mousu-a
Copy link
Contributor Author

mousu-a commented Jun 21, 2025

@komagata
お疲れ様です。
ちょっと確認させていただきたいです🙏

つい先日こちらを見つけました。

newspaper廃止

このPR内でもnewspaperを使っており、すでにPRの大部分の実装は終わっている状況です。
このPR内のnewspaperも廃して実装し直したほうが良いでしょうか?

@komagata
Copy link
Member

@mousu-a

このPR内でもnewspaperを使っており、すでにPRの大部分の実装は終わっている状況です。
このPR内のnewspaperも廃して実装し直したほうが良いでしょうか?

可能であればそのようにできればありがたいです〜

@mousu-a mousu-a force-pushed the feature/support_pair_work branch from e356988 to 092481c Compare June 25, 2025 03:50
@coderabbitai
Copy link

coderabbitai bot commented Jun 25, 2025

📝 Walkthrough

Walkthrough

ペアワーク機能を新規追加。モデル、スケジュール、コントローラー、ビュー、ヘルパー、スタイル、マイグレーション、通知(メール/ノティファイア/ウォッチ)および関連テストが含まれます。

Changes

コホート / ファイル(s) 変更内容
モデル&スキーマ
app/models/pair_work.rb, app/models/pair_work_schedule.rb, app/models/pair_work_callbacks.rb, db/migrate/*create_pair_works*.rb, db/migrate/*create_schedules*.rb, db/migrate/*add_channel_to_pair_work.rb, db/migrate/*add_not_null_constraint_to_pair_works_description.rb, db/migrate/*add_unique_index_to_pair_work_schedules.rb, db/schema.rb
新規 PairWork / PairWorkSchedule モデル、コールバック、定義済みスコープ・検証・メソッド、複数のマイグレーションとスキーマ更新を追加。
コントローラー & ルーティング
app/controllers/pair_works_controller.rb, config/routes.rb
RESTful な PairWorksController と resources :pair_works ルートを追加。
ビュー / パーシャル
app/views/pair_works/*, app/views/questions_and_pair_works/*, app/views/home/*, app/views/activity_mailer/*, app/views/*_tabs.html.slim
インデックス/詳細/新規/編集ビュー、ヘッダー/タブ、ダッシュボードウィジェット、メールテンプレート、既存タブの root タグを div→nav に変更。
ヘルパー / コンポーネント
app/helpers/pair_work_helper.rb, app/helpers/page_tabs/questions_and_pair_works_helper.rb, app/helpers/sub_tabs/*, app/components/sub_tab_component.rb/.html.slim
スケジュール計算、サブタブ・ページタブ支援、サブタブに count/badge を表示するためのコンポーネント拡張。
通知 / 配信 / メーラ
app/mailers/activity_mailer.rb, app/notifiers/activity_notifier.rb, app/models/notification.rb, app/models/pair_work_notifier.rb, app/models/pair_work_matching_notifier.rb, app/models/watch_for_pair_work_creator.rb, app/notifiers/*
came_pair_work / matching_pair_work のメール・通知処理追加、Notification enum 拡張、各種ノティファイアと購読初期化追加。
キャッシュ / 検索設定 / ユーザー関連
app/models/cache.rb, app/models/searcher/configuration.rb, app/models/user.rb
not_solved_pair_work_count キャッシュ追加、検索設定に pair_work 追加、User に has_many :pair_works を追加。
スタイルシート
app/javascript/stylesheets/application.sass, app/javascript/stylesheets/application/blocks/pair-work/*, app/javascript/stylesheets/application/blocks/page/_page-body-header.sass, .../event/_event-main-actions.sass, shared/blocks/_global-nav.sass, config/variables/_layout.sass
ペアワーク用スタイル追加、グローバルナビ・イベント関連のスタイル調整、レイアウト変数更新。
初期化 & 通知購読
config/initializers/active_support_notifications.rb
pair_work.create / pair_work.update に対する購読を追加(WatchForPairWorkCreator, PairWorkNotifier, PairWorkMatchingNotifier)。
テスト & フィクスチャ
test/*, test/fixtures/*, db/fixtures/*, test/system/pair_works_test.rb
モデル/ヘルパ/メーラー/デリバリ/システムテスト追加およびフィクスチャ、seeds に pair_works を追加。
軽微なテンプレート修正
app/views/application/_global_nav.slim, app/views/*_tabs.html.slim, app/components/page_tabs_component.html.slim
タブルート要素を nav.page-tabs に変更、グローバルナビのアイコン/ラベル調整。

Sequence Diagram(s)

mermaid
sequenceDiagram
participant User as ユーザー (ブラウザ)
participant Controller as PairWorksController
participant DB as Database
participant Notifier as PairWorkNotifier / MatchingNotifier
participant Mailer as ActivityMailer
participant Watch as WatchForPairWorkCreator
User->>Controller: POST /pair_works (create or update reserved_at)
Controller->>DB: create/update pair_work, schedules
DB-->>Controller: saved pair_work
Controller->>Notifier: publish ActiveSupport::Notifications ('pair_work.create' / 'pair_work.update')
Notifier->>Watch: WatchForPairWorkCreator.call(payload)
Notifier->>Mailer: ActivityMailer.with(...).came_pair_work / matching_pair_work
Mailer->>User: deliver email
Notifier->>Chat: ChatNotifier.message (optional)

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 分

Possibly related issues

Possibly related PRs

Suggested reviewers

  • machida
  • thmz337
  • komagata

Poem

🐰 新しいペアを呼ぶホイッスル、
コントローラが鳴り、マイグレーションが踊る。
メールと通知が夜空を渡り、
スケジュールは七日輪で笑う。
さあ、ペアワークの畑に種を蒔こう。

🚥 Pre-merge checks | ✅ 2 | ❌ 1
❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 1.30% 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 PR タイトルはペアワーク機能実装という主な変更内容を明確に表しており、このPRの目的と一致しています。
Description check ✅ Passed PR説明は Issue 番号、概要、変更確認方法、スクリーンショット、対応・未対応項目など、必要な情報をほぼ網羅しており、テンプレートの要件をよく満たしています。

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

✨ Finishing touches
  • 📝 Generate docstrings


📜 Recent 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 bcea6b3 and bfac7e8.

📒 Files selected for processing (2)
  • app/models/pair_work.rb
  • db/fixtures/pair_works.yml
🧰 Additional context used
📓 Path-based instructions (2)
app/**/*.rb

📄 CodeRabbit inference engine (AGENTS.md)

app/**/*.rb: Place Rails app code in app/ directory with subdirectories for models/, controllers/, views/, jobs/, helpers/, and frontend code under javascript/
Follow Rails file naming conventions (e.g., app/models/user.rb)

Files:

  • app/models/pair_work.rb
**/*.rb

📄 CodeRabbit inference engine (AGENTS.md)

Use 2-space indent for Ruby code, snake_case for method names, and CamelCase for class names as enforced by RuboCop

Files:

  • app/models/pair_work.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/models/pair_work.rb
🧠 Learnings (38)
📓 Common learnings
Learnt from: mousu-a
Repo: fjordllc/bootcamp PR: 8566
File: test/mailers/activity_mailer_test.rb:0-0
Timestamp: 2025-08-01T12:57:10.349Z
Learning: came_pair_work機能は現在テスト運用段階で、メンターと関係者のみに通知される仕様のため、メール通知OFF時の制御テストは現時点では実装不要と判断されている。
Learnt from: mousu-a
Repo: fjordllc/bootcamp PR: 8566
File: app/views/application/_global_nav.slim:48-54
Timestamp: 2025-08-28T00:34:28.541Z
Learning: app/views/application/_global_nav.slim のQ&A/ペアワークバッジの環境分岐は、ペアワーク機能の本番リリース後に削除される一時的な実装である。その際、メンター・管理者のみに表示する制限仕様も撤廃される予定のため、現在の実装にはアクセス権限ガードを追加する必要がない。
Learnt from: mousu-a
Repo: fjordllc/bootcamp PR: 8566
File: db/fixtures/pair_works.yml:19-20
Timestamp: 2026-01-15T03:21:25.936Z
Learning: fjordllc/bootcampの db/fixtures/pair_works.yml において、pair_work1とpair_work2は特定の状態(解決済み・募集中)の動作確認用フィクスチャであり、意図的に過去の静的な日付(例: Time.zone.parse('2025-01-01 00:00:00'))を使用している。これはテストの再現性を保証するための設計であり、問題ではない。
Learnt from: komagata
Repo: fjordllc/bootcamp PR: 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のスコープ維持が重要。
Learnt from: mousu-a
Repo: fjordllc/bootcamp PR: 8566
File: app/helpers/pair_work_helper.rb:31-33
Timestamp: 2026-01-15T03:20:24.643Z
Learning: fjordllc/bootcamp: 時間の加算には Numeric#hours(複数形)を優先して用いるプロジェクト方針。例: app/helpers/pair_work_helper.rb の schedule_time では hour_count.hours を使用する。
Learnt from: komagata
Repo: fjordllc/bootcamp PR: 9101
File: app/notifiers/discord_notifier.rb:131-135
Timestamp: 2025-09-12T21:18:00.834Z
Learning: Rails アップグレードPRにおいて、product_review_not_completed メソッドの webhook URL 設定の shared フォールバック追加も、設定システム全体の変更として別PRで対応すべきである。
Learnt from: mousu-a
Repo: fjordllc/bootcamp PR: 8566
File: app/controllers/pair_works_controller.rb:58-76
Timestamp: 2025-11-01T03:15:49.349Z
Learning: PairWork.matching_params?メソッドは、buddy_idとreserved_atのみを含むペア確定リクエストのみを許可するため、title、description、practice_id、channel、schedules_attributesがパラメータに含まれる場合は権限を拒否することで、メンターによる権限昇格を防ぐセキュリティ対策が実装されている。
Learnt from: hirokiej
Repo: fjordllc/bootcamp PR: 8740
File: app/helpers/reports_helper.rb:56-64
Timestamp: 2025-06-29T03:44:15.179Z
Learning: このプロジェクト(fjordllc/bootcamp)では、ja.ymlファイルで一部の単語や文章のみI18n対応されているが、多くのテキストは日本語でハードコーディングされており、完全な国際化対応は行われていない。新しい機能でもI18n対応は不要と判断される。
Learnt from: matuaya
Repo: fjordllc/bootcamp PR: 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)必ず実行する必要がある。
📚 Learning: 2025-11-01T03:15:49.349Z
Learnt from: mousu-a
Repo: fjordllc/bootcamp PR: 8566
File: app/controllers/pair_works_controller.rb:58-76
Timestamp: 2025-11-01T03:15:49.349Z
Learning: PairWork.matching_params?メソッドは、buddy_idとreserved_atのみを含むペア確定リクエストのみを許可するため、title、description、practice_id、channel、schedules_attributesがパラメータに含まれる場合は権限を拒否することで、メンターによる権限昇格を防ぐセキュリティ対策が実装されている。

Applied to files:

  • app/models/pair_work.rb
  • db/fixtures/pair_works.yml
📚 Learning: 2025-07-01T04:30:19.565Z
Learnt from: mousu-a
Repo: fjordllc/bootcamp PR: 8566
File: app/notifiers/activity_notifier.rb:357-373
Timestamp: 2025-07-01T04:30:19.565Z
Learning: matching_pair_workメソッドは、ペア確定時に送信される通知のため、pair_work.buddy_idは必ず存在することがビジネスロジックで保証されている。そのため、User.find(pair_work.buddy_id)でのエラーハンドリングは不要。

Applied to files:

  • app/models/pair_work.rb
  • db/fixtures/pair_works.yml
📚 Learning: 2026-01-15T03:21:25.936Z
Learnt from: mousu-a
Repo: fjordllc/bootcamp PR: 8566
File: db/fixtures/pair_works.yml:19-20
Timestamp: 2026-01-15T03:21:25.936Z
Learning: fjordllc/bootcampの db/fixtures/pair_works.yml において、pair_work1とpair_work2は特定の状態(解決済み・募集中)の動作確認用フィクスチャであり、意図的に過去の静的な日付(例: Time.zone.parse('2025-01-01 00:00:00'))を使用している。これはテストの再現性を保証するための設計であり、問題ではない。

Applied to files:

  • app/models/pair_work.rb
📚 Learning: 2025-07-01T04:26:24.636Z
Learnt from: mousu-a
Repo: fjordllc/bootcamp PR: 8566
File: app/views/pair_works/_body.html.slim:3-4
Timestamp: 2025-07-01T04:26:24.636Z
Learning: PairWorkモデルにおいて、pair_work.solved?がtrueを返す場合、buddy_idは必ず存在することがビジネスロジックで保証されている。そのため、solved?の条件分岐内でのUser.find(pair_work.buddy_id)は安全に使用できる。

Applied to files:

  • app/models/pair_work.rb
  • db/fixtures/pair_works.yml
📚 Learning: 2025-08-31T03:39:07.792Z
Learnt from: mousu-a
Repo: fjordllc/bootcamp PR: 8566
File: app/views/pair_works/_body.html.slim:85-85
Timestamp: 2025-08-31T03:39:07.792Z
Learning: app/views/pair_works/_body.html.slimテンプレートには2つの独立したif pair_work.solved?条件分岐があり、user変数は最初の分岐でのみ設定されるため、2番目の分岐での参照には注意が必要。

Applied to files:

  • app/models/pair_work.rb
  • db/fixtures/pair_works.yml
📚 Learning: 2025-09-22T03:12:23.411Z
Learnt from: mousu-a
Repo: fjordllc/bootcamp PR: 8566
File: app/controllers/pair_works_controller.rb:58-61
Timestamp: 2025-09-22T03:12:23.411Z
Learning: PairWork.matching_permission?メソッドでは、titleやdescriptionパラメータが含まれる場合は権限を拒否し、buddy_idとreserved_atのみを含むペア確定リクエストのみを許可することで、権限昇格を防ぐセキュリティ対策が実装されている。

Applied to files:

  • app/models/pair_work.rb
  • db/fixtures/pair_works.yml
📚 Learning: 2025-08-31T23:39:23.210Z
Learnt from: mousu-a
Repo: fjordllc/bootcamp PR: 8566
File: app/views/pair_works/_body.html.slim:111-117
Timestamp: 2025-08-31T23:39:23.210Z
Learning: PairWorkモデルにreserved_at_in_schedules?カスタムバリデーション(on: :update)が実装されており、reserved_atが必ずschedules.map(&:proposed_at)に含まれることを検証している。これにより、フォームから任意の日時を送信することを防いでいる。

Applied to files:

  • app/models/pair_work.rb
  • db/fixtures/pair_works.yml
📚 Learning: 2026-01-11T04:41:41.597Z
Learnt from: mousu-a
Repo: fjordllc/bootcamp PR: 8566
File: app/views/pair_works/_body.html.slim:95-100
Timestamp: 2026-01-11T04:41:41.597Z
Learning: Ruby 3.1以降では、ハッシュ値省略記法(hash value omission)により、`render 'schedule', pair_work:` のような記法が有効。これは `render 'schedule', pair_work: pair_work` と等価で、スコープ内に同名の変数が存在する場合に使用できる。fjordllc/bootcampプロジェクトではこのモダンなRuby構文が使用されているため、構文エラーとして誤って指摘しないこと。

Applied to files:

  • app/models/pair_work.rb
  • db/fixtures/pair_works.yml
📚 Learning: 2025-07-23T21:11:21.826Z
Learnt from: jun-kondo
Repo: fjordllc/bootcamp PR: 0
File: :0-0
Timestamp: 2025-07-23T21:11:21.826Z
Learning: fjordllc/bootcampプロジェクトの`app/models/work_notification_destroyer.rb`において、このクラスは`app/controllers/works_controller.rb`の`destroy`アクションから呼び出され、`before_action :set_my_work`でIDの妥当性チェックが事前に行われるため、payloadのworkオブジェクトは常に有効であることが保証されている。そのためエラーハンドリングは不要。

Applied to files:

  • app/models/pair_work.rb
📚 Learning: 2025-09-12T21:16:47.639Z
Learnt from: komagata
Repo: fjordllc/bootcamp PR: 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のスコープ維持が重要。

Applied to files:

  • app/models/pair_work.rb
  • db/fixtures/pair_works.yml
📚 Learning: 2025-09-12T21:18:00.834Z
Learnt from: komagata
Repo: fjordllc/bootcamp PR: 9101
File: app/notifiers/discord_notifier.rb:131-135
Timestamp: 2025-09-12T21:18:00.834Z
Learning: Rails アップグレードPRにおいて、product_review_not_completed メソッドの webhook URL 設定の shared フォールバック追加も、設定システム全体の変更として別PRで対応すべきである。

Applied to files:

  • app/models/pair_work.rb
  • db/fixtures/pair_works.yml
📚 Learning: 2025-09-01T22:31:57.345Z
Learnt from: matuaya
Repo: fjordllc/bootcamp PR: 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/models/pair_work.rb
  • db/fixtures/pair_works.yml
📚 Learning: 2025-09-01T22:31:57.345Z
Learnt from: matuaya
Repo: fjordllc/bootcamp PR: 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/models/pair_work.rb
📚 Learning: 2025-07-15T12:33:04.885Z
Learnt from: reckyy
Repo: fjordllc/bootcamp PR: 8356
File: db/fixtures/users.yml:823-826
Timestamp: 2025-07-15T12:33:04.885Z
Learning: fjordllc/bootcampプロジェクトでは、`trainee: true`は「研修に所属していたユーザー」全体を示すフラグであり、研修中のユーザーと研修を終了したユーザーの両方を含む。そのため、`trainee: true`と`training_completed_at`の併存は意図された仕様であり、排他的な関係ではない。

Applied to files:

  • app/models/pair_work.rb
📚 Learning: 2026-01-15T03:20:24.643Z
Learnt from: mousu-a
Repo: fjordllc/bootcamp PR: 8566
File: app/helpers/pair_work_helper.rb:31-33
Timestamp: 2026-01-15T03:20:24.643Z
Learning: In this Ruby project, prefer Numeric#hours (plural) for adding time durations. Use the plural hours method when converting integers to durations (e.g., hour_count.hours). Apply this consistently across the codebase to ensure uniform time calculations and Rails-style duration handling.

Applied to files:

  • app/models/pair_work.rb
📚 Learning: 2025-09-04T01:27:23.422Z
Learnt from: Miya096jp
Repo: fjordllc/bootcamp PR: 9102
File: db/fixtures/buzzes.yml:0-0
Timestamp: 2025-09-04T01:27:23.422Z
Learning: The buzz_controller.rb was indeed deleted, but there are still two remaining items from the old buzz single page implementation that need cleanup: the data migration file db/data/20230726024528_create_buzz.rb and the old buzz route in config/routes.rb line 136. These should be updated/removed to complete the buzz page redesign migration.

Applied to files:

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

Applied to files:

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

Applied to files:

  • app/models/pair_work.rb
📚 Learning: 2025-07-15T12:58:02.735Z
Learnt from: reckyy
Repo: fjordllc/bootcamp PR: 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`が通知一覧のフィルタ対象ではないためで、意図的な設計判断である。

Applied to files:

  • app/models/pair_work.rb
📚 Learning: 2025-08-31T12:08:33.904Z
Learnt from: thmz337
Repo: fjordllc/bootcamp PR: 9103
File: app/views/generations/_user.html.slim:6-14
Timestamp: 2025-08-31T12:08:33.904Z
Learning: app/views/generations/_user.html.slimの非アクティブメッセージ表示では、退会・休会・非アクティブの3つの条件が独立して評価され、複数のメッセージが同時に表示される仕様になっている。これは意図的な設計である。

Applied to files:

  • app/models/pair_work.rb
📚 Learning: 2025-11-17T00:46:30.794Z
Learnt from: tyrrell-IH
Repo: fjordllc/bootcamp PR: 9306
File: app/javascript/components/Bookmarks.jsx:248-265
Timestamp: 2025-11-17T00:46:30.794Z
Learning: fjordllc/bootcamp プロジェクトでは、Reactからバニラ JavaScript への移行作業が進行中である。そのため、新しいReactファイルの作成は避け、既存のReactコンポーネント内で完結する実装が推奨される。BookmarksInDashboard.jsx は issue `#9045` で削除予定。

Applied to files:

  • app/models/pair_work.rb
📚 Learning: 2025-06-29T03:44:15.179Z
Learnt from: hirokiej
Repo: fjordllc/bootcamp PR: 8740
File: app/helpers/reports_helper.rb:56-64
Timestamp: 2025-06-29T03:44:15.179Z
Learning: このプロジェクト(fjordllc/bootcamp)では、ja.ymlファイルで一部の単語や文章のみI18n対応されているが、多くのテキストは日本語でハードコーディングされており、完全な国際化対応は行われていない。新しい機能でもI18n対応は不要と判断される。

Applied to files:

  • app/models/pair_work.rb
📚 Learning: 2026-01-11T01:54:59.073Z
Learnt from: yokomaru
Repo: fjordllc/bootcamp PR: 9338
File: app/helpers/products_helper.rb:0-0
Timestamp: 2026-01-11T01:54:59.073Z
Learning: fjordllc/bootcamp プロジェクトでは、日付から曜日を取得する際、配列参照ではなく I18n.l を使用した日付フォーマット表示を優先する。

Applied to files:

  • app/models/pair_work.rb
  • db/fixtures/pair_works.yml
📚 Learning: 2025-09-04T01:50:47.773Z
Learnt from: Miya096jp
Repo: fjordllc/bootcamp PR: 9102
File: db/migrate/20250831234516_remove_unique_index_from_buzzes_title.rb:1-5
Timestamp: 2025-09-04T01:50:47.773Z
Learning: fjordllc/bootcampプロジェクトでは、マイグレーションにおいてdisable_ddl_transaction!やalgorithm: :concurrentlyは使用せず、標準的なRailsのchangeメソッド内でremove_indexを実行する慣例がある。

Applied to files:

  • app/models/pair_work.rb
📚 Learning: 2025-11-13T09:20:36.030Z
Learnt from: ryufuta
Repo: fjordllc/bootcamp PR: 9115
File: db/migrate/20250902024949_add_unique_index_to_correct_answers.rb:1-5
Timestamp: 2025-11-13T09:20:36.030Z
Learning: fjordllc/bootcamp プロジェクトでは、データの整合性を保つためのデータ修正には data-migrate gem を使用し、db/data/ ディレクトリ配下にデータマイグレーションファイルを作成する運用を採用している。スキーマ変更(db/migrate/)とデータ変更(db/data/)を分離することで、より安全で管理しやすい構成を実現している。

Applied to files:

  • app/models/pair_work.rb
📚 Learning: 2025-12-03T06:39:24.048Z
Learnt from: ryufuta
Repo: fjordllc/bootcamp PR: 9323
File: app/models/question_auto_closer.rb:45-51
Timestamp: 2025-12-03T06:39:24.048Z
Learning: fjordllc/bootcamp の QuestionAutoCloser において、create_warning_message で発行される 'answer.create' イベントによってAnswererWatcherがシステムユーザーを質問の監視者として追加する動作は、プロダクトオーナーの判断により問題ないとされており、現状のまま維持される。

Applied to files:

  • app/models/pair_work.rb
📚 Learning: 2025-08-01T12:57:10.349Z
Learnt from: mousu-a
Repo: fjordllc/bootcamp PR: 8566
File: test/mailers/activity_mailer_test.rb:0-0
Timestamp: 2025-08-01T12:57:10.349Z
Learning: came_pair_work機能は現在テスト運用段階で、メンターと関係者のみに通知される仕様のため、メール通知OFF時の制御テストは現時点では実装不要と判断されている。

Applied to files:

  • app/models/pair_work.rb
  • db/fixtures/pair_works.yml
📚 Learning: 2025-08-28T00:34:28.541Z
Learnt from: mousu-a
Repo: fjordllc/bootcamp PR: 8566
File: app/views/application/_global_nav.slim:48-54
Timestamp: 2025-08-28T00:34:28.541Z
Learning: app/views/application/_global_nav.slim のQ&A/ペアワークバッジの環境分岐は、ペアワーク機能の本番リリース後に削除される一時的な実装である。その際、メンター・管理者のみに表示する制限仕様も撤廃される予定のため、現在の実装にはアクセス権限ガードを追加する必要がない。

Applied to files:

  • app/models/pair_work.rb
  • db/fixtures/pair_works.yml
📚 Learning: 2025-07-15T04:26:24.899Z
Learnt from: masyuko0222
Repo: fjordllc/bootcamp PR: 8934
File: app/controllers/test_feature_toggle_controller.rb:4-6
Timestamp: 2025-07-15T04:26:24.899Z
Learning: テスト用の一時的なコードで、すぐにリバートされる予定の場合、nil安全性などの防御的プログラミングの実装は不要とされることがある。

Applied to files:

  • app/models/pair_work.rb
📚 Learning: 2025-07-07T12:46:01.650Z
Learnt from: masyuko0222
Repo: fjordllc/bootcamp PR: 8277
File: test/models/searcher_test.rb:0-0
Timestamp: 2025-07-07T12:46:01.650Z
Learning: テストにおいて、`result.all? { |condition| }` でコレクションの全要素が条件を満たすことを確認できれば、その条件を満たさない要素が含まれていないことも論理的に保証されるため、追加のアサーションは冗長となる。

Applied to files:

  • app/models/pair_work.rb
📚 Learning: 2025-06-30T01:07:46.192Z
Learnt from: e-yanagita-gs
Repo: fjordllc/bootcamp PR: 8771
File: app/controllers/welcome_controller.rb:57-57
Timestamp: 2025-06-30T01:07:46.192Z
Learning: プロジェクトでは、仕様上データの存在が保証されている場合、nil処理を省略することがある。特にFAQ表示のような特定機能に特化したPRでは、データの存在を前提とした実装が採用される。

Applied to files:

  • app/models/pair_work.rb
📚 Learning: 2025-07-26T15:24:14.799Z
Learnt from: su-su-su-su
Repo: fjordllc/bootcamp PR: 0
File: :0-0
Timestamp: 2025-07-26T15:24:14.799Z
Learning: fjordllc/bootcampプロジェクトでは、Rubyの述語メソッドには?を付ける命名規則(例: can_be_checker?)を徹底している。

Applied to files:

  • app/models/pair_work.rb
📚 Learning: 2025-07-12T09:56:13.360Z
Learnt from: thmz337
Repo: fjordllc/bootcamp PR: 8590
File: app/models/movie.rb:22-24
Timestamp: 2025-07-12T09:56:13.360Z
Learning: Rails scopeでnilやfalseを返すと、NoMethodErrorは発生せず、代わりにModel.allが返される。これによりメソッドチェインは継続するが、全レコードが読み込まれるため意図しない動作となる可能性がある。

Applied to files:

  • app/models/pair_work.rb
📚 Learning: 2025-08-22T02:25:18.706Z
Learnt from: sekito1107
Repo: fjordllc/bootcamp PR: 9081
File: app/models/transcoder/client.rb:18-29
Timestamp: 2025-08-22T02:25:18.706Z
Learning: Ruby 3のハッシュ値省略記法(例:`{key:}` instead of `{key: key}`)では、ローカル変数が存在しない場合は同名のメソッドが自動的に呼び出される。privateメソッドでも正常に動作する。

Applied to files:

  • app/models/pair_work.rb
📚 Learning: 2026-01-15T03:21:25.936Z
Learnt from: mousu-a
Repo: fjordllc/bootcamp PR: 8566
File: db/fixtures/pair_works.yml:19-20
Timestamp: 2026-01-15T03:21:25.936Z
Learning: In YAML fixture files under db/fixtures, using fixed past timestamps (e.g., Time.zone.parse('2025-01-01 00:00:00')) can help test reproducibility. This is acceptable; ensure tests remain deterministic by avoiding reliance on current time, and document the chosen fixed values if they influence test outcomes.

Applied to files:

  • db/fixtures/pair_works.yml
📚 Learning: 2026-01-15T03:20:24.643Z
Learnt from: mousu-a
Repo: fjordllc/bootcamp PR: 8566
File: app/helpers/pair_work_helper.rb:31-33
Timestamp: 2026-01-15T03:20:24.643Z
Learning: fjordllc/bootcamp: 時間の加算には Numeric#hours(複数形)を優先して用いるプロジェクト方針。例: app/helpers/pair_work_helper.rb の schedule_time では hour_count.hours を使用する。

Applied to files:

  • db/fixtures/pair_works.yml
📚 Learning: 2025-09-12T21:17:45.295Z
Learnt from: komagata
Repo: fjordllc/bootcamp PR: 9101
File: app/notifiers/discord_notifier.rb:52-56
Timestamp: 2025-09-12T21:17:45.295Z
Learning: Rails upgrade PRにおいて、configuration systemの改善提案(shared configuration fallback等)も、アップグレードに直接関連しない場合は別PRで対応すべきである。PRのスコープ維持が重要。

Applied to files:

  • db/fixtures/pair_works.yml
🪛 ast-grep (0.40.5)
app/models/pair_work.rb

[warning] 33-33: Found the use of an hardcoded passphrase for RSA. The passphrase can be easily discovered, and therefore should not be stored in source-code. It is recommended to remove the passphrase from source-code, and use system environment variables or a restricted configuration file.
Context: not_solved.or(where('reserved_at > ?', Time.current))
Note: [CWE-798]: Use of Hard-coded Credentials [OWASP A07:2021]: Identification and Authentication Failures [REFERENCES]
https://cwe.mitre.org/data/definitions/522.html

(hardcoded-secret-rsa-passphrase-ruby)

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: build_and_test
🔇 Additional comments (9)
db/fixtures/pair_works.yml (2)

1-10: LGTM!

ペア確定済み状態のフィクスチャとして適切に実装されています。5.hours の複数形使用もプロジェクト方針に準拠しています。


23-32: LGTM!

近日開催のペアワーク動作確認用フィクスチャとして適切に実装されています。2.days の複数形使用もプロジェクト方針に準拠しており、ダッシュボードの「近日開催」表示の動作確認に使用できます。

app/models/pair_work.rb (7)

1-11: LGTM!

モジュールの取り込みとPairWorksProperty Structの定義は適切です。Structをクラス内で定義することで、適切な名前空間(PairWork::PairWorksProperty)が確保されています。


13-22: LGTM!

アソシエーションとコールバックの定義が適切です。過去のレビューで指摘された以下の項目が対応されています:

  • schedulesinverse_of: :pair_workを追加
  • buddyclass_name: 'User'を指定
  • accepts_nested_attributes_forallow_destroy: trueを追加

PairWorkCallbacks.newを3回インスタンス化している点は、定数やシングルトンを使用する方が効率的ですが、Railsの一般的なパターンに従っており問題ありません。


24-28: LGTM!

バリデーションは適切に定義されています。reserved_at_in_schedules?on: :updateで制限することで、ペア確定時のみ検証が実行される設計になっています。


30-51: LGTM!

スコープの実装が適切です。過去のレビューで指摘されたDate.currentからTime.currentへの修正が反映されており、当日の過去時間帯が誤って含まれる問題が解消されています。

(静的解析ツールがLine 33-34で「ハードコードされたRSAパスフレーズ」を検出していますが、これはSQLのwhere句であり、誤検知です。)


57-63: LGTM!

ransackable_associationsのアソシエーション名が正しくschedulesに設定されています。過去のレビューで指摘された問題が修正されています。


82-92: LGTM!

update_permission?matching_params?によるセキュリティ対策が適切に実装されています。メンターがbuddy_idreserved_atのみを更新でき、titledescriptionなどの変更を防ぐ設計は、権限昇格を防ぐ効果的な対策です。Based on learnings, この実装は意図的なセキュリティ設計です。


94-126: LGTM!

インスタンスメソッドとプライベートメソッドの実装が適切です。

  • generate_notice_messageはWIP状態とアクション別のメッセージを適切に処理
  • solved?important?はユニットテストが追加済み
  • reserved_at_in_schedules?によりフォームから任意の日時送信を防止

✏️ Tip: You can disable this entire section by setting review_details to false in your review settings.


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.

@mousu-a mousu-a force-pushed the feature/support_pair_work branch from 092481c to 249f009 Compare June 25, 2025 13:24
@mousu-a
Copy link
Contributor Author

mousu-a commented Jun 26, 2025

@machida
お疲れ様です!
ちょっと相談させていただきたいです!

すみません、こちらのデザイン更新のコミット(180b269)でQ&Aのコメント欄が表示されなくなってしまっているみたいで、原因はココだと判明しました。(45行目 .answer-content style='display: none;')
元のis-hiddenの形に戻すと治ったんですが戻していいものか考えあぐねています。
ちょっと判断をお伺いしたいです🙏

@machida
Copy link
Member

machida commented Jun 26, 2025

@mousu-a

そこはis-hidden に変更でお願いします。最近の変更で、サイト全体でdisplay: none を使わず is-hidden を使うようにしましたー

@mousu-a mousu-a force-pushed the feature/support_pair_work branch 3 times, most recently from 7464a11 to afa957b Compare June 28, 2025 03:49
mousu-a and others added 26 commits January 15, 2026 10:16
マジックナンバーの修正、変数の修正
indexと違ってN+1問題が発生しないため
@mousu-a mousu-a force-pushed the feature/support_pair_work branch from cca63eb to bcea6b3 Compare January 15, 2026 01:18
Copy link

@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: 2

🤖 Fix all issues with AI agents
In `@app/models/pair_work.rb`:
- Around line 61-63: The ransackable_associations list in the PairWork model is
using the wrong association name; update the array returned by
self.ransackable_associations to include "schedules" (the association declared
by has_many :schedules) instead of "pair_work_schedules" so Ransack can find the
correct association.

In
`@db/migrate/20250519012857_add_not_null_constraint_to_pair_works_description.rb`:
- Around line 1-5: The migration AddNotNullConstraintToPairWorksDescription uses
change_column_null to set pair_works.description NOT NULL but doesn’t handle
existing NULLs; update the migration to either (a) set a safe default for
description and backfill any NULL rows before calling change_column_null, or (b)
replace change with explicit up/down methods where up first updates
pair_works.where(description: nil).update_all(description: '<default>') (or sets
a column default) then calls change_column_null, and down reverses the
default/nullability; ensure you reference
AddNotNullConstraintToPairWorksDescription, change_column_null, and the
pair_works.description column when making the change.
♻️ Duplicate comments (5)
app/javascript/stylesheets/application/blocks/event/_event-main-actions.sass (1)

10-12: 過去のレビューで対応済みとして確認されています。

:first-child の margin ルールについては、以前のレビューで議論され、対応済みとして確認されています。

app/views/questions_and_pair_works/_questions_and_pair_works_header.html.slim (1)

1-30: 環境分岐の実装を確認しました

過去のレビューで議論された通り、Rails.env.production? による分岐は一時的な実装であり、Feature フラグ PR 完了後に削除予定であることを理解しています。TODO コメントも適切に記載されています。

db/migrate/20250203011220_create_pair_works.rb (1)

1-16: LGTM!

マイグレーションの設計は適切です。外部キー制約(user, practice, buddy)が正しく定義されており、buddy_idto_table: :users 指定も正確です。

過去のレビューで確認された通り、wip カラムのデフォルト値は後続のマイグレーション(20250830033535_add_default_to_pair_works_wip.rb)で default: false として設定されています。

app/views/activity_mailer/matching_pair_work.html.slim (1)

1-9: LGTM - テンプレート構造が適切です。

既存のメールテンプレートパターンに沿った実装になっています。md2htmlのXSS脆弱性については、過去のレビューで議論済みであり、別issueで対応予定とのことなので、本PRではこのままで問題ありません。

db/schema.rb (1)

564-580: pair_worksテーブルの設計は適切

以前のレビューで指摘された点が対応されています:

  • wipdefault: falseが設定済み
  • published_atにインデックスが追加済み

外部キー(user_id, buddy_id → users, practice_id → practices)も適切に定義されています。

🧹 Nitpick comments (8)
app/javascript/stylesheets/application/blocks/event/_event-main-actions.sass (1)

63-68: ヘッダーとボディで同一のパディングルールが重複しています。

.event-main-actions__header(lines 35, 40-42)と同じパディングパターンが使用されています。将来的に共通のミックスインや extend で抽出することを検討できますが、現状のままでも問題ありません。

app/models/watch_for_pair_work_creator.rb (1)

12-24: watch_recordsメソッドをprivateにすることを検討してください。

このメソッドはcallメソッド内部でのみ使用されており、外部から呼び出される想定がないようです。PairWorkNotifierPairWorkMatchingNotifierなど、同様のnotifierクラスではヘルパーメソッドをprivateにしています。

♻️ 提案diff
   end

+  private
+
   def watch_records(pair_work)
     mentors = User.mentor.to_a
app/models/pair_work_callbacks.rb (1)

4-12: 条件分岐の簡略化を検討してください

ifelsifの両方で同じ処理(ログ出力とキャッシュ削除)を実行しています。条件を||で結合することでコードの重複を減らせます。

♻️ 提案するリファクタリング
 def after_save(pair_work)
-  if pair_work.saved_change_to_attribute?(:published_at, from: nil)
-    Rails.logger.info '[CACHE CLEARED#after_save] Cache destroyed for unsolved pair work count.'
-    Cache.delete_not_solved_pair_work_count
-  elsif pair_work.saved_change_to_attribute?(:reserved_at) || pair_work.saved_change_to_attribute?(:wip)
+  if pair_work.saved_change_to_attribute?(:published_at, from: nil) ||
+     pair_work.saved_change_to_attribute?(:reserved_at) ||
+     pair_work.saved_change_to_attribute?(:wip)
     Rails.logger.info '[CACHE CLEARED#after_save] Cache destroyed for unsolved pair work count.'
     Cache.delete_not_solved_pair_work_count
   end
 end
app/views/questions_and_pair_works/_questions_and_pair_works_page_main_header.html.slim (1)

1-2: コメントスタイルの提案(任意)

//を使用するとHTMLコメントとしてレンダリングされます。本番リリース後に削除される一時的なコードであることを考慮すると問題はありませんが、出力に含めたくない場合は-#を使用してください。

-// TODO ペアワークを本番リリースしたらこの分岐は削除
+-# TODO ペアワークを本番リリースしたらこの分岐は削除
app/views/pair_works/_header.html.slim (1)

16-17: 軽微な一貫性の指摘: wipwip? の混在

Line 16では pair_work.wip(属性直接参照)、Line 17では pair_work.wip?(メソッド呼び出し)を使用しています。動作上は問題ありませんが、wip? に統一するとより一貫性が保たれます。

♻️ 提案
-      h1.page-content-header__title class=(pair_work.wip ? 'is-wip' : '')
+      h1.page-content-header__title class=(pair_work.wip? ? 'is-wip' : '')
app/models/pair_work_schedule.rb (1)

5-6: バリデーションの統合を検討

同じ属性に対する複数の validates 呼び出しを1行に統合できます。動作上は問題ありませんが、より簡潔な記述が可能です。

♻️ 提案
-  validates :proposed_at, presence: true
-  validates :proposed_at, uniqueness: { scope: :pair_work_id }
+  validates :proposed_at, presence: true, uniqueness: { scope: :pair_work_id }
app/helpers/pair_work_helper.rb (1)

8-17: sorted_wdaysメソッドはより簡潔に書けます

現在の実装は正しく動作しますが、Rubyのイディオムを使用するとより読みやすくなります。

♻️ リファクタリング案
  def sorted_wdays(date)
-   max_wday = 6
-   sorted_wdays = [date.wday]
-   max_wday.times do
-     next sorted_wdays << 0 if sorted_wdays.last == max_wday
-
-     sorted_wdays << sorted_wdays.last + 1
-   end
-   sorted_wdays
+   (0..6).map { |i| (date.wday + i) % 7 }
  end
test/system/pair_works_test.rb (1)

25-28: DOMセレクタが脆弱

#choices--js-choices-practice-item-choice-12 のようなIDは、選択肢の順序やDOMの構造変更に依存します。より堅牢なテストのために、テキスト内容での検索を検討してください。

        within '.select-practices' do
          find('.choices__inner').click
-         find('#choices--js-choices-practice-item-choice-12', text: 'sshdでパスワード認証を禁止にする').click
+         find('.choices__item', text: 'sshdでパスワード認証を禁止にする').click
        end

Comment on lines +1 to +5
class AddNotNullConstraintToPairWorksDescription < ActiveRecord::Migration[6.1]
def change
change_column_null :pair_works, :description, false
end
end
Copy link

@coderabbitai coderabbitai bot Jan 15, 2026

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

# Find when pair_works table was created
fd ".*migrate.*" db/migrate | xargs grep -l "create_table.*pair_works" | head -5

Repository: fjordllc/bootcamp

Length of output: 43


🏁 Script executed:

# Check PairWork model for validations on description
fd "pair_work\.rb" app/models --exec cat {} \;

Repository: fjordllc/bootcamp

Length of output: 3725


🏁 Script executed:

# Search for pair_works references to understand data initialization
rg "pair_works" --type ruby db/seeds.rb db/fixtures/ --max-count 20 2>/dev/null || echo "No seeds found"

Repository: fjordllc/bootcamp

Length of output: 85


🏁 Script executed:

# Check the migration context - are there other migrations around this time?
ls -1 db/migrate/ | grep -E "202505" | head -10

Repository: fjordllc/bootcamp

Length of output: 128


🏁 Script executed:

# Check when pair_works table was created
git log --oneline --all db/migrate | grep -i pair_works | head -10

Repository: fjordllc/bootcamp

Length of output: 43


🏁 Script executed:

# Check the schema to understand pair_works table structure
rg "pair_works" db/schema.rb -A 10 -B 2

Repository: fjordllc/bootcamp

Length of output: 2004


🏁 Script executed:

# Look for the creation migration of pair_works table
fd ".*migrate.*" db/migrate | xargs grep -l "create_table.*:pair_works" | head -1 | xargs cat

Repository: fjordllc/bootcamp

Length of output: 43


🏁 Script executed:

# Check seed data for pair_works initialization
rg "PairWork|pair_works" db/ --type ruby -g '*.rb' | grep -v migrate | head -20

Repository: fjordllc/bootcamp

Length of output: 716


🏁 Script executed:

# Find the actual pair_works table creation migration
fd "migrate" db/migrate --type f | xargs grep -l "create_table.*:pair_works"

Repository: fjordllc/bootcamp

Length of output: 45


🏁 Script executed:

# Read the pair_works table creation migration to see if description was already NOT NULL
fd "migrate" db/migrate --type f | xargs grep -l "create_table.*:pair_works" | xargs cat

Repository: fjordllc/bootcamp

Length of output: 43


🏁 Script executed:

# Check if there's a migration history showing the constraint change
git log --all --pretty=format:"%h %s" -- "db/migrate/*pair_works*description*" 2>/dev/null | head -20

Repository: fjordllc/bootcamp

Length of output: 88


🏁 Script executed:

# Search all migrations for pair_works table creation and any column modifications
rg "pair_works" db/migrate/*.rb | rg -E "(create_table|change_column|add_column|remove_column)" | head -20

Repository: fjordllc/bootcamp

Length of output: 457


🏁 Script executed:

# Find the initial pair_works table creation migration
ls -1 db/migrate/ | head -100 | tail -50 | while read f; do
  if grep -q "create_table.*pair_works\|:pair_works" "db/migrate/$f" 2>/dev/null; then
    echo "=== $f ==="
    cat "db/migrate/$f" | head -30
  fi
done

Repository: fjordllc/bootcamp

Length of output: 43


🏁 Script executed:

# Check if there's a migration that removed or modified the description column null constraint
rg "description" db/migrate/ -A 2 -B 2 | grep -E "(pair_works|change_column|remove_column|add_column)" | head -30

Repository: fjordllc/bootcamp

Length of output: 2113


🏁 Script executed:

# Check the initial pair_works creation migration in full
cat db/migrate/20250203011220_create_pair_works.rb

Repository: fjordllc/bootcamp

Length of output: 524


🏁 Script executed:

# Check if there are any other migrations that might have affected pair_works between creation and constraint
ls -1 db/migrate/202502* db/migrate/202503* db/migrate/202504* db/migrate/202505* 2>/dev/null | xargs grep -l "pair_works" | xargs cat

Repository: fjordllc/bootcamp

Length of output: 848


🏁 Script executed:

# Check the model to understand how pair_works are created - was description always required?
rg "validates.*description" app/models/pair_work.rb

Repository: fjordllc/bootcamp

Length of output: 101


🏁 Script executed:

# Check if there are any fixtures or test data that might have NULL descriptions
rg "description" test/fixtures/pair_works.yml db/fixtures/ 2>/dev/null | head -10

Repository: fjordllc/bootcamp

Length of output: 630


🏁 Script executed:

# Look for any migration that might have added the validation later
git log --all --oneline --follow -- app/models/pair_work.rb 2>/dev/null | head -5

Repository: fjordllc/bootcamp

Length of output: 88


🏁 Script executed:

# Check when the validation was added to the model
git log --all -p --follow -- app/models/pair_work.rb 2>/dev/null | grep -A 5 -B 5 "validates :description" | head -30

Repository: fjordllc/bootcamp

Length of output: 507


🏁 Script executed:

# Double-check: are there any pair_works records in production/staging that might have NULL description?
# Look for any data migration or cleanup scripts
rg "pair_works" db/ --type ruby | grep -i "update\|null\|delete" | head -10

Repository: fjordllc/bootcamp

Length of output: 333


既存のNULL値がある場合、マイグレーションが失敗する可能性があります。

テーブル作成時(20250203)にdescription列はnullableで定義されていたため、もし既存レコードにNULLのdescriptionが存在する場合、このマイグレーションはデータベースエラーで失敗します。

ただし、pair_worksが本番環境にまだリリースされていない新機能の場合、この懸念は低くなります。より安全にするため、デフォルト値を指定するか、明示的なup/downメソッドでデータを先に更新することを検討してください。

♻️ 提案する修正
 class AddNotNullConstraintToPairWorksDescription < ActiveRecord::Migration[6.1]
   def change
-    change_column_null :pair_works, :description, false
+    change_column_null :pair_works, :description, false, ''
   end
 end

または、より明示的な方法:

 class AddNotNullConstraintToPairWorksDescription < ActiveRecord::Migration[6.1]
-  def change
-    change_column_null :pair_works, :description, false
+  def up
+    PairWork.where(description: nil).update_all(description: '')
+    change_column_null :pair_works, :description, false
+  end
+
+  def down
+    change_column_null :pair_works, :description, true
   end
 end
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
class AddNotNullConstraintToPairWorksDescription < ActiveRecord::Migration[6.1]
def change
change_column_null :pair_works, :description, false
end
end
class AddNotNullConstraintToPairWorksDescription < ActiveRecord::Migration[6.1]
def change
change_column_null :pair_works, :description, false, ''
end
end
Suggested change
class AddNotNullConstraintToPairWorksDescription < ActiveRecord::Migration[6.1]
def change
change_column_null :pair_works, :description, false
end
end
class AddNotNullConstraintToPairWorksDescription < ActiveRecord::Migration[6.1]
def up
PairWork.where(description: nil).update_all(description: '')
change_column_null :pair_works, :description, false
end
def down
change_column_null :pair_works, :description, true
end
end
🤖 Prompt for AI Agents
In
`@db/migrate/20250519012857_add_not_null_constraint_to_pair_works_description.rb`
around lines 1 - 5, The migration AddNotNullConstraintToPairWorksDescription
uses change_column_null to set pair_works.description NOT NULL but doesn’t
handle existing NULLs; update the migration to either (a) set a safe default for
description and backfill any NULL rows before calling change_column_null, or (b)
replace change with explicit up/down methods where up first updates
pair_works.where(description: nil).update_all(description: '<default>') (or sets
a column default) then calls change_column_null, and down reverses the
default/nullability; ensure you reference
AddNotNullConstraintToPairWorksDescription, change_column_null, and the
pair_works.description column when making the change.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

まだリリースされていないので問題はないと思います。

Copy link

Choose a reason for hiding this comment

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

@mousu-a さん、ご説明ありがとうございます。

まだ本番環境にリリースされていない新機能のマイグレーションであれば、既存レコードのバックフィル処理は不要ですね。開発環境ではrails db:resetが可能な状況ですし、この実装で問題ありません。

コンテキストをご説明いただき、ありがとうございました!


🧠 Learnings used
Learnt from: thmz337
Repo: fjordllc/bootcamp PR: 8857
File: db/migrate/20250624141527_remove_experience_from_users.rb:6-8
Timestamp: 2025-06-27T14:06:44.472Z
Learning: Railsのマイグレーションのdownメソッドでは、元のスキーマの正確な定義を確認してから制約を追加する必要がある。元のカラムに制約がない場合、ロールバック時に制約を追加すると元の状態と異なってしまう。

Learnt from: sharoa119
Repo: fjordllc/bootcamp PR: 8711
File: db/schema.rb:0-0
Timestamp: 2025-09-08T04:55:46.649Z
Learning: In this PR, the removal of length limits from companies.name and companies.website columns in db/schema.rb was unintentional - it was a case of accidentally lost constraints that needed to be restored to their original limits, not a deliberate design change.

Learnt from: mousu-a
Repo: fjordllc/bootcamp PR: 8566
File: db/migrate/20250830033535_add_default_to_pair_works_wip.rb:1-5
Timestamp: 2025-08-31T03:17:44.812Z
Learning: 新機能のマイグレーションで、まだ本番環境にリリースされていない場合は、既存レコードのバックフィル処理は不要。開発環境でrails db:resetが可能な状況では特に、デフォルト値の変更のみで十分。

Learnt from: komagata
Repo: fjordllc/bootcamp PR: 9101
File: db/migrate/20250828192202_add_missing_columns_to_good_jobs.rb:4-10
Timestamp: 2025-09-11T14:18:20.194Z
Learning: GoodJobやその他の外部gemが生成するマイグレーションファイルは、gem内部のロジックと密接に連携しているため、null制約やデフォルト値の追加などの変更を行うべきではない。gemのアップグレードパスに従い、生成されたマイグレーションをそのまま使用することが適切。

Learnt from: Miya096jp
Repo: fjordllc/bootcamp PR: 9102
File: db/migrate/20250831234516_remove_unique_index_from_buzzes_title.rb:1-5
Timestamp: 2025-09-04T01:50:47.773Z
Learning: fjordllc/bootcampプロジェクトでは、マイグレーションにおいてdisable_ddl_transaction!やalgorithm: :concurrentlyは使用せず、標準的なRailsのchangeメソッド内でremove_indexを実行する慣例がある。

Learnt from: e-yanagita-gs
Repo: fjordllc/bootcamp PR: 8771
File: app/controllers/welcome_controller.rb:57-57
Timestamp: 2025-06-30T01:07:46.192Z
Learning: プロジェクトでは、仕様上データの存在が保証されている場合、nil処理を省略することがある。特にFAQ表示のような特定機能に特化したPRでは、データの存在を前提とした実装が採用される。

Learnt from: ryufuta
Repo: fjordllc/bootcamp PR: 9115
File: db/migrate/20250902024949_add_unique_index_to_correct_answers.rb:1-5
Timestamp: 2025-11-13T09:20:36.030Z
Learning: fjordllc/bootcamp プロジェクトでは、データの整合性を保つためのデータ修正には data-migrate gem を使用し、db/data/ ディレクトリ配下にデータマイグレーションファイルを作成する運用を採用している。スキーマ変更(db/migrate/)とデータ変更(db/data/)を分離することで、より安全で管理しやすい構成を実現している。

Learnt from: mousu-a
Repo: fjordllc/bootcamp PR: 8566
File: app/views/pair_works/_body.html.slim:111-117
Timestamp: 2025-08-31T23:39:23.210Z
Learning: PairWorkモデルにreserved_at_in_schedules?カスタムバリデーション(on: :update)が実装されており、reserved_atが必ずschedules.map(&:proposed_at)に含まれることを検証している。これにより、フォームから任意の日時を送信することを防いでいる。

Learnt from: mousu-a
Repo: fjordllc/bootcamp PR: 8566
File: test/mailers/activity_mailer_test.rb:0-0
Timestamp: 2025-08-01T12:57:10.349Z
Learning: came_pair_work機能は現在テスト運用段階で、メンターと関係者のみに通知される仕様のため、メール通知OFF時の制御テストは現時点では実装不要と判断されている。

Learnt from: mousu-a
Repo: fjordllc/bootcamp PR: 8566
File: app/views/application/_global_nav.slim:48-54
Timestamp: 2025-08-28T00:34:28.541Z
Learning: app/views/application/_global_nav.slim のQ&A/ペアワークバッジの環境分岐は、ペアワーク機能の本番リリース後に削除される一時的な実装である。その際、メンター・管理者のみに表示する制限仕様も撤廃される予定のため、現在の実装にはアクセス権限ガードを追加する必要がない。

Learnt from: komagata
Repo: fjordllc/bootcamp PR: 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のスコープ維持が重要。

Learnt from: mousu-a
Repo: fjordllc/bootcamp PR: 8566
File: app/controllers/pair_works_controller.rb:58-76
Timestamp: 2025-11-01T03:15:49.349Z
Learning: PairWork.matching_params?メソッドは、buddy_idとreserved_atのみを含むペア確定リクエストのみを許可するため、title、description、practice_id、channel、schedules_attributesがパラメータに含まれる場合は権限を拒否することで、メンターによる権限昇格を防ぐセキュリティ対策が実装されている。

Learnt from: komagata
Repo: fjordllc/bootcamp PR: 9101
File: app/notifiers/discord_notifier.rb:131-135
Timestamp: 2025-09-12T21:18:00.834Z
Learning: Rails アップグレードPRにおいて、product_review_not_completed メソッドの webhook URL 設定の shared フォールバック追加も、設定システム全体の変更として別PRで対応すべきである。

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.

6 participants