Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
159 commits
Select commit Hold shift + click to select a range
78e3b14
ペアワーク機能を実装
mousu-a Mar 17, 2025
da07c0b
ペアワークに通知機能を追加
mousu-a Mar 29, 2025
9900546
ペアワークの通知のテストを追加
mousu-a Apr 1, 2025
6955c0e
関係者の近日開催イベント欄にペアワークを表示するように
mousu-a Apr 13, 2025
87c51c5
動作確認用のフィクスチャを作成
mousu-a Apr 14, 2025
382e964
ペアワークのチャンネル選択のカラムを追加
mousu-a Apr 14, 2025
4a0d067
ペアワークのチャンネル選択に関するViewの記述を追加
mousu-a Apr 14, 2025
d891b26
ペアワークのコメントが0で相手が見つかっていないとき、Q&Aのように"コメント"を赤文字で表示する
mousu-a Apr 14, 2025
ff95e1a
ペアワークのヘルパーテストを導入
mousu-a Apr 14, 2025
ccff955
近日開催するペアワークのヘルパーメソッドテストを導入
mousu-a Apr 15, 2025
51699d7
ペアワークのモデルテストを導入
mousu-a Apr 15, 2025
84b3d3c
Rubocopの指摘点を修正
mousu-a Apr 19, 2025
43eea3c
edit画面ではscheduleを表示しないようにした
mousu-a Apr 20, 2025
6659101
重複を削除 頭痛が痛いみたいになっていたので
mousu-a Apr 20, 2025
2f0aaf8
不要な分岐だったので
mousu-a Apr 20, 2025
2659d2f
レイアウト崩れの修正
machida May 8, 2025
8f9aead
ペアワークの相手をペアに名称変更、確定ブロックのベースを作成
machida May 9, 2025
60d157f
デザイン更新
machida May 11, 2025
e23da83
ペアワークをQ&Aとセットにし、デザインを更新した
machida May 14, 2025
051f2b0
ペアワークのシステムテストを実装
mousu-a May 18, 2025
6e641a3
Rubocopの指摘点を修正
mousu-a May 18, 2025
fc0980f
関連付けを使用
mousu-a May 18, 2025
c311b4e
ペアワークのdesctiptionにNotNullを追加
mousu-a May 19, 2025
1d69c4f
ペアワークを本番で非表示にした
machida Jun 3, 2025
d33c12c
:cop:
machida Jun 3, 2025
0eeff70
ペアワークリリース後のTODOコメント追加
machida Jun 3, 2025
71fda62
pair_workのsave時に関連付けを利用してschedulesもsaveするように
mousu-a Jun 13, 2025
2733363
Watch機能の非Vue化に対応
mousu-a Jun 21, 2025
4f96461
_formのリファクタ
mousu-a Jun 21, 2025
ee25c4f
希望日時(schedules)が空の状態ではペアワークのsaveが失敗するように
mousu-a Jun 21, 2025
b87519c
一応proposed_atにpresence trueをつけておく
mousu-a Jun 21, 2025
be1be9f
Rubocopによる指摘点を修正
mousu-a Jun 21, 2025
7403437
テストが通らなくなっていたため
mousu-a Jun 25, 2025
8a94823
newspaperで実装していた部分を置き換え
mousu-a Jun 25, 2025
9f7c6c6
wip作成時の挙動をQ&Aと同じように
mousu-a Jun 25, 2025
2358c02
Q&Aのコメント欄が表示されなくなっていたため
mousu-a Jun 26, 2025
c40280b
フラッシュメッセージを共通化
mousu-a Jun 26, 2025
a20227e
disabledをメソッドで共通化
mousu-a Jun 26, 2025
fc76704
変数名をわかりやすく
mousu-a Jun 26, 2025
1ed0045
不要な記述だったため
mousu-a Jun 26, 2025
0dd9c1e
不要な変更だったため
mousu-a Jun 26, 2025
cce0a1d
心配なのでシステムテストを追加
mousu-a Jun 28, 2025
4881b76
Rubyのメソッドを使わずSQLでフィルタリングする
mousu-a Jun 30, 2025
58b5cb5
誤字修正
mousu-a Jun 30, 2025
226833b
近日開催されるペアワークのテストをわかりやすく、且つ順序に依存しないように修正
mousu-a Jun 30, 2025
0c43ac1
誤って表示していたと思われるリンクを削除
mousu-a Jun 30, 2025
25ae39e
ペアワークのレコードがない時の表示が機能していなかったので修正
mousu-a Jul 1, 2025
3de92f4
既存の実装に合わせてunsolved_badgeを使用
mousu-a Jul 1, 2025
ecc09ee
クエリを無駄に繰り返していたので一回にまとめた
mousu-a Jul 1, 2025
9f9224d
WIP 近日開催のペアワークを仕様変更
mousu-a Jul 9, 2025
9c3f291
挙動をチェックしやすいようにフィクスチャを追加
mousu-a Jul 9, 2025
a2b627a
ダッシュボードのペアワークの表示を整えた
machida Jul 22, 2025
7d9d545
必要なさそうだったのでPresenterの導入をやめた
mousu-a Jul 24, 2025
f9616cb
必要なくなったため削除
mousu-a Jul 24, 2025
155a57b
Rubyの記法にならって変更
mousu-a Jul 24, 2025
fc0fabd
モデルテストを追加
mousu-a Jul 24, 2025
13a047f
変更が不要になったため戻した
mousu-a Jul 24, 2025
48fba89
PRに不要なdiffだったため
mousu-a Jul 24, 2025
9b9732f
update, destroyで権限チェックをするように
mousu-a Jul 24, 2025
2cbff96
コメント消し忘れ
mousu-a Jul 26, 2025
18c69ca
誤字修正
mousu-a Jul 31, 2025
494670d
コンフリクト解消でテストが落ちていたので修正
mousu-a Jul 31, 2025
a9bc903
修正漏れ unsolved_badgeを使うように
mousu-a Aug 22, 2025
9613a94
check_box_tagを使うことで不要なhiddenフィールドが生成されないように
mousu-a Aug 28, 2025
ac8af71
変数名、メソッド名をわかりやすく
mousu-a Aug 28, 2025
167d0bc
Rubocopによる指摘点を修正
mousu-a Aug 28, 2025
93faf85
admin以外のメンターがマッチングできない問題を修正
mousu-a Aug 30, 2025
19ef03d
adminではなくメンターでテストするように
mousu-a Aug 30, 2025
7e54872
不要な記述を修正
mousu-a Aug 30, 2025
9c3f913
wipにデフォルト値を、検索の高速化としてpublished_atにindexを設定
mousu-a Aug 30, 2025
ca00d14
作成者とadminだけが編集できるように
mousu-a Aug 30, 2025
bb5d15e
Rubocopによる指摘点を修正
mousu-a Aug 30, 2025
f457cf0
テストが通るように
mousu-a Aug 31, 2025
77a8df9
わかりやすい変数名に
mousu-a Aug 31, 2025
9c61d98
関連付けを使用して取得するように
mousu-a Aug 31, 2025
c888df7
将来の、ペアワークのスケジュールの変更機能のためallow_destroy: trueをつける
mousu-a Aug 31, 2025
1706ffb
if_not_exists: trueをつけて安全に
mousu-a Aug 31, 2025
1548a43
想定していない日時でのマッチングを拒否するバリデーションを実装
mousu-a Aug 31, 2025
db0de85
どのuserを参照しているかがわかりにくいため
mousu-a Aug 31, 2025
4ba7374
inverse_ofをつけて明示的に
mousu-a Sep 1, 2025
5a04b29
pair_work.userでbuddyの値が返ってきてしまっていたため修正
mousu-a Sep 1, 2025
e9bb3d1
DRYにした
mousu-a Sep 9, 2025
eb80845
partialをcollection形式にした
mousu-a Sep 10, 2025
b576943
ヘルパーメソッドのテストを追加
mousu-a Sep 11, 2025
049e864
不要だったため
mousu-a Sep 11, 2025
b24d59f
汎用性が高いpair_workをフィクスチャで生成するようにした
mousu-a Sep 11, 2025
186fb25
メソッドをよりわかりやすくした
mousu-a Sep 11, 2025
f17ecf4
nilの確認だけで良さそうだったので修正
mousu-a Sep 11, 2025
bcfc519
メソッドをよりわかりやすくした
mousu-a Sep 11, 2025
516d157
ペアワーク作成者の場合の表示を変更、partialを導入し整理した
mousu-a Sep 15, 2025
1de0a7b
メソッド名の変更 紛らわしかったため
mousu-a Sep 15, 2025
ad9fc78
ヘルパーメソッドのテストを追加
mousu-a Sep 15, 2025
345f23c
ユーザー退会時、未実施のペアワークを削除するようにした
mousu-a Sep 20, 2025
c59b1c2
検索機能の実装変更に対応
mousu-a Sep 20, 2025
8b93a6f
コメントが機能していなかったので修正
mousu-a Sep 20, 2025
79a9b16
テストが落ちるようになったため修正
mousu-a Sep 20, 2025
279b1e5
検索機能の変更に伴い、テストが落ちてしまっていたので
mousu-a Sep 20, 2025
edabe77
メソッド修正 buddy_idさえあればペアワークの内容修正が出来てしまうのを修正
mousu-a Sep 21, 2025
6344039
ペア確定後、スケジュール表が見えなくなっていたので修正
mousu-a Sep 22, 2025
a0a51ec
pair_work_user?を削除、意味がなく冗長だったため
mousu-a Sep 22, 2025
cbe48e2
実装変更に伴いテストを修正
mousu-a Sep 22, 2025
0bcf860
Rubocopによる指摘点、誤字を修正
mousu-a Sep 22, 2025
7b75250
検索機能の変更に伴い、テストが落ちてしまっていたので修正
mousu-a Sep 22, 2025
0a2efa1
誤字修正
mousu-a Sep 22, 2025
86a7323
メンターにのみ削除ボタンが表示されるようになっていたので修正
mousu-a Sep 22, 2025
3b9af7c
重複を避けるため変数を定義
mousu-a Oct 16, 2025
b21a6ab
メソッド修正 permissionチェックをまとめた
mousu-a Oct 16, 2025
55ac8e3
ダッシュボードのアイコン変更、左ナビのサイズ微調整
machida Oct 28, 2025
f2b0914
PairWorkモデルのsolved?とimportant?メソッドのテストを追加
machida Oct 28, 2025
cc6fcf0
ペアワークのdatetime属性をISO8601形式に変更
machida Oct 28, 2025
b0a8d3e
upcoming_pair_worksのテストを時間固定で実行するよう修正
machida Oct 28, 2025
dc859ca
PairWorkテストのbuddy_idをbuddyアソシエーションに変更
machida Oct 28, 2025
51beddb
テスト まとめて良さそうだったので
mousu-a Oct 29, 2025
dd07b1e
テスト名を修正
mousu-a Oct 29, 2025
822428d
ペアワークの未解決数をキャッシュ化してパフォーマンスを改善
machida Oct 31, 2025
619d425
インデントを修正
mousu-a Oct 31, 2025
4abb032
マッチング時の確認をより厳格に それに伴いテストも追加
mousu-a Nov 1, 2025
636cf92
ペアワーク作成者がメンターだった場合に重複しないように
mousu-a Nov 7, 2025
feddbbc
他の実装と合わせ1行開けた
mousu-a Nov 12, 2025
9185de2
不要な記述を削除
mousu-a Nov 12, 2025
de5620c
Viewのロジックをhelperに移譲
mousu-a Nov 13, 2025
96635a6
HTMLタグ 短いものは1行に
mousu-a Nov 15, 2025
c321fd3
schedules 名前が衝突しそうなのでpair_work_schedulesに変更
mousu-a Nov 15, 2025
c905852
メソッド修正 命名が抽象的すぎたため
mousu-a Nov 16, 2025
c4f3a5f
変数名の修正 実態に即した形に
mousu-a Nov 16, 2025
457219f
タイポ修正
mousu-a Nov 16, 2025
124e418
schedulesテーブルのリネームでCIが落ちていたので修正
mousu-a Nov 16, 2025
62d9d97
既存の実装と合わせ1行開ける
mousu-a Nov 17, 2025
c3faed2
ペアワークの通知が重複しているため、Callbackでの通知を削除
mousu-a Dec 9, 2025
37a4429
upcoming_pair_works、not_held に当日の開催済みペアワークが入らないように
mousu-a Dec 12, 2025
c4e4d9c
変数名の修正 実態に即した形に
mousu-a Dec 14, 2025
036315d
無駄に繰り返していたため事前に計算する形に
mousu-a Dec 14, 2025
dda6b3f
sassのネームスペース抜け修正
machida Dec 17, 2025
c350096
不要なインデントを削除
machida Dec 17, 2025
1a2831d
sassのネームスペース抜け修正
machida Dec 17, 2025
b268eca
Rails 7.2 / Ransack 4互換性のため
mousu-a Dec 21, 2025
64b7770
テスト修正 当日の開催済みのペアワークは含めないように
mousu-a Dec 21, 2025
072683d
変数修正 より実態に即した形に
mousu-a Dec 21, 2025
d5e4cb3
テスト修正 型の不一致を避けるため
mousu-a Dec 22, 2025
b9ef2a0
テスト修正 よりわかりやすく
mousu-a Dec 22, 2025
4107432
テスト修正 他の人が疑問を抱かないようtravel_toで囲んでおく
mousu-a Dec 22, 2025
554edfd
rebaseミスで混入したdiffを削除
mousu-a Jan 8, 2026
9b18177
edit(編集画面)が誰でも見られるようになっていたので修正
mousu-a Jan 9, 2026
fc1ee13
before_actionで定義する意味がなさそうだったので修正
mousu-a Jan 8, 2026
fe70410
必要な関連をpreloadするように修正
mousu-a Jan 9, 2026
55b43d3
includesに変更 明示してpreloadにする意味がなさそうだったので
mousu-a Jan 9, 2026
7e0ed20
エラーが起きてしまっていたため修正
mousu-a Jan 10, 2026
8fe2e62
preloadする関連を増やした
mousu-a Jan 10, 2026
6aa9f94
Q&Aの実装と合わせ、showではpreloadしない形に変更
mousu-a Jan 10, 2026
d5e8e08
タイポ修正
mousu-a Jan 11, 2026
b5c4cad
ペアワークのスケジュール日時にユニーク制約をつけた
mousu-a Jan 11, 2026
413c8fb
Railsの慣習に従い記述を変更
mousu-a Jan 11, 2026
e573047
不要なファイルを削除
machida Jan 13, 2026
9888a3b
未実装の機能のリンクにTODOコメント追加
machida Jan 13, 2026
009c741
time周りのマークアップミスの修正
machida Jan 14, 2026
d853d59
Railsの慣習に従い記述を変更
mousu-a Jan 11, 2026
bcea6b3
無駄なクエリを走らせていたため修正
mousu-a Jan 12, 2026
1c03b3b
フィクスチャ修正 それぞれの役割をわかりやすく
mousu-a Jan 15, 2026
bfac7e8
アソシエーション名を指定するように
mousu-a Jan 15, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion app/components/page_tabs_component.html.slim
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
.page-tabs
nav.page-tabs
.container
ul.page-tabs__items
- tabs.each do |tab|
Expand Down
5 changes: 5 additions & 0 deletions app/components/sub_tab_component.html.slim
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
li.tab-nav__item
= link_to link, class: "tab-nav__item-link #{active ? 'is-active' : ''}" do
= name
- if count.present?
= " (#{count})"
- if badge&.positive?
.page-tabs__item-count.a-notification-count
.not-solved-count = badge
6 changes: 4 additions & 2 deletions app/components/sub_tab_component.rb
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
# frozen_string_literal: true

class SubTabComponent < ViewComponent::Base
def initialize(name:, link:, active: false)
def initialize(name:, link:, active: false, count: nil, badge: nil)
@name = name
@link = link
@active = active
@count = count
@badge = badge
end

private

attr_reader :name, :link, :active
attr_reader :name, :link, :active, :count, :badge
end
5 changes: 5 additions & 0 deletions app/controllers/home_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ def index
if current_user
display_dashboard
display_events_on_dashboard
display_pair_works_on_dashboard
display_welcome_message_for_adviser
set_required_fields
display_products_for_mentor
Expand Down Expand Up @@ -57,6 +58,10 @@ def display_events_on_dashboard
@upcoming_events_groups = UpcomingEvent.upcoming_events_groups
end

def display_pair_works_on_dashboard
@upcoming_pair_works = PairWork.upcoming_pair_works(current_user)
end

def display_welcome_message_for_adviser
@welcome_message_first_time = cookies[:confirmed_welcome_message]
end
Expand Down
79 changes: 79 additions & 0 deletions app/controllers/pair_works_controller.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
# frozen_string_literal: true

class PairWorksController < ApplicationController
before_action :set_my_pair_work, only: %i[edit destroy]
before_action :set_updatable_pair_work, only: %i[update]

PAGER_NUMBER = 10

def index
Copy link
Member

Choose a reason for hiding this comment

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

他のところと合わせて1行開けたほうがいいかもです。

Copy link
Contributor Author

Choose a reason for hiding this comment

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

そうですね、1行開けました!

@pair_works = PairWork.by_target(params[:target])
.with_avatar
.includes(:practice, :comments, :user)
.order(:published_at)
.page(params[:page])
.per(PAGER_NUMBER)
@pair_works_property = PairWork.generate_pair_works_property(params[:target])
end

def show
@pair_work = PairWork.find(params[:id])
@comments = @pair_work.comments.order(:created_at)
end

def edit; end

def new
@pair_work = PairWork.new
end

def create
@pair_work = PairWork.new(pair_work_params)
@pair_work.user = current_user
set_wip
if @pair_work.save
ActiveSupport::Notifications.instrument('pair_work.create', pair_work: @pair_work)
redirect_to Redirection.determin_url(self, @pair_work), notice: @pair_work.generate_notice_message(:create)
else
Comment on lines +35 to +37
Copy link

@coderabbitai coderabbitai bot Jul 24, 2025

Choose a reason for hiding this comment

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

⚠️ Potential issue

外部 URL へのリダイレクト脆弱性の可能性
Brakeman が指摘しているとおり、Redirection.determin_url が信頼できない値(例: パラメータ経由で注入されたホスト名)を返すとオープンリダイレクトになります。
最低でもアプリのホスト名内に限定するバリデーションを加えるか、内部パスのみを返す *_path 系ヘルパに切り替えるべきです。

- redirect_to Redirection.determin_url(self, @pair_work), notice: @pair_work.generate_notice_message(:create)
+ redirect_to Redirection.determine_path(self, @pair_work), notice: @pair_work.generate_notice_message(:create)

上記のように 絶対 URL ではなくパスを返す メソッドへ置換し、Redirection クラス側で URI.parse 等を使ったホスト検証を必ず行ってください。

Also applies to: 40-42

🧰 Tools
🪛 Brakeman (7.0.2)

[high] 31-31: Possible unprotected redirect
Type: Redirect
Confidence: High
More info: https://brakemanscanner.org/docs/warning_types/redirect/

(Redirect)

🤖 Prompt for AI Agents
In app/controllers/pair_works_controller.rb around lines 30 to 32 and also lines
40 to 42, the use of Redirection.determin_url returns an absolute URL that may
be untrusted, causing an open redirect vulnerability. Replace this method call
with one that returns only internal path helpers (e.g., *_path) to ensure
redirects stay within the app. Additionally, update the Redirection class to
validate the host using URI parsing to confirm it matches the app's domain
before returning any URL.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

determin_urlはbootcamp内で実装しているもので、Railsのヘルパーではないです

Copy link

Choose a reason for hiding this comment

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

🧩 Analysis chain

@mousu-a ご指摘ありがとうございます。カスタム実装のRedirection.determin_urlメソッドを確認させていただきます。


🏁 Script executed:

#!/bin/bash
# Find the Redirection class implementation
fd -t f -e rb | xargs rg -l "class Redirection" -A 5

Length of output: 107


🏁 Script executed:

#!/bin/bash
# Examine the Redirection class implementation
cat app/models/redirection.rb

Length of output: 444


@mousu-a 実装を確認いたしました。Redirection.determin_urlの実装を見ると、実際にはセキュリティ上の問題はないと判断されます。

実装内容:

def determin_url
  @resource.wip? ? @controller.polymorphic_url(@resource, action: :edit) : @controller.polymorphic_url(@resource)
end

この実装が安全な理由:

  1. Railsの標準メソッドを使用: polymorphic_urlはRailsの組み込みヘルパーで、ActiveRecordモデルから安全にURLを生成します
  2. ユーザー入力を直接使用していない: リダイレクト先はリソースオブジェクト(@pair_work)のみから決定され、外部入力は関与していません
  3. 内部ルートのみ: wip?の状態に応じて詳細ページか編集ページの2つの内部ルートから選択するだけです

Brakemanの警告は、静的解析ツールの性質上、redirect_toと外部メソッド呼び出しの組み合わせを検出した際の誤検知(false positive)と考えられます。

なお、メソッド名のdetermin_urldetermine_urlの誤字のようですが、これは機能に影響しない軽微な問題です。

セキュリティ上の修正は不要ですが、もしBrakemanの警告を回避したい場合は、以下のようにインライン化することも可能です:

redirect_to @pair_work.wip? ? edit_pair_work_path(@pair_work) : pair_work_path(@pair_work), notice: @pair_work.generate_notice_message(:create)

ただし、現在の実装で十分安全であり、コードの可読性も良いため、変更の必要性は低いと思われます。


🧠 Learnings used
Learnt from: mousu-a
PR: fjordllc/bootcamp#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)でのエラーハンドリングは不要。

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

Learnt from: mousu-a
PR: fjordllc/bootcamp#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)は安全に使用できる。

Learnt from: su-su-su-su
PR: fjordllc/bootcamp#0
File: :0-0
Timestamp: 2025-07-07T05:28:03.676Z
Learning: fjordllc/bootcampプロジェクトでは、fixtureファイル内のERB構文で改行制御文字(-)は使用せず、標準的な<% %>と<%= %>のみを使用する方針が統一されている。<% -%>や<%- %>を使用するとSyntaxErrorが発生する。

Learnt from: tyrrell-IH
PR: fjordllc/bootcamp#8807
File: app/views/welcome/job_support.html.slim:391-392
Timestamp: 2025-06-21T22:30:20.116Z
Learning: このプロジェクトにはRailsの組み込みmarkdownヘルパが利用できないため、markdownのHTML変換には自前でヘルパを実装する必要がある。

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

Learnt from: jun-kondo
PR: fjordllc/bootcamp#8977
File: app/controllers/reports_controller.rb:63-63
Timestamp: 2025-07-23T20:31:13.816Z
Learning: fjordllc/bootcampプロジェクトの`app/controllers/reports_controller.rb`において、`create`と`update`アクションは両方とも`@report.save_uniquely`を使用し、同じ`:report_save`イベントと`'report.save'`イベントを発行する。これは両方とも本質的に「レポートの保存」操作であり、作成と更新を区別する必要がないためである。

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: jun-kondo
PR: fjordllc/bootcamp#0
File: :0-0
Timestamp: 2025-07-23T20:42:19.928Z
Learning: fjordllc/bootcampプロジェクトでは、hタグ(見出し)の文言は日本語でハードコーディングする方針が確立されており、I18n対応は行わない。例:app/views/welcome/logo.html.slimでh2、h3タグが日本語でハードコーディングされている。

render :new
end
end

def update
set_wip
if @pair_work.update(pair_work_params)
ActiveSupport::Notifications.instrument('pair_work.update', pair_work: @pair_work)
redirect_to Redirection.determin_url(self, @pair_work), notice: @pair_work.generate_notice_message(:update)
else
render :edit
end
end

def destroy
@pair_work.destroy
redirect_to pair_works_url, notice: @pair_work.generate_notice_message(:destroy)
end

private

def pair_work_params
params.require(:pair_work).permit(:practice_id, :title, :description, :reserved_at, :buddy_id, :channel,
schedules_attributes: %i[id proposed_at _destroy])
end

def set_my_pair_work
@pair_work = current_user.admin? ? PairWork.find(params[:id]) : current_user.pair_works.find(params[:id])
end

def set_updatable_pair_work
@pair_work = if PairWork.update_permission?(current_user, params[:pair_work])
PairWork.find(params[:id])
else
current_user.pair_works.find(params[:id])
end
end
Comment on lines +68 to +74
Copy link

@coderabbitai coderabbitai bot Dec 12, 2025

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

params[:pair_work] 欠落時に500にならないようガード推奨
悪意/事故で pair_work が無い PATCH が来ると update_permission? 側で落ちる可能性があるので、最低限 params.fetch(:pair_work, {}) を渡す形にしておくと堅いです。

 def set_updatable_pair_work
-  @pair_work = if PairWork.update_permission?(current_user, params[:pair_work])
+  raw_pair_work_params = params.fetch(:pair_work, {})
+  @pair_work = if PairWork.update_permission?(current_user, raw_pair_work_params)
                  PairWork.find(params[:id])
                else
                  current_user.pair_works.find(params[:id])
                end
 end
🤖 Prompt for AI Agents
In app/controllers/pair_works_controller.rb around lines 72 to 78, passing
params[:pair_work] into PairWork.update_permission? can raise when the key is
missing; change the call to pass params.fetch(:pair_work, {}) (or otherwise
default to an empty Hash) so update_permission? always receives a hash and does
not raise on missing params, keeping the existing conditional logic and record
lookup intact.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

pair_work が無い PATCHというのはどういう状況で考えられますか?

Copy link

Choose a reason for hiding this comment

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

@mousu-a さん、良い質問ですね!

通常のフォーム送信では pair_work パラメータは必ず含まれるので、このケースは確かに稀です。ただし、以下のような状況で pair_work が欠落する可能性があります:

  1. 直接的なAPIコール: cURLやPostmanなどのツールで手動でPATCHリクエストを送信する場合、パラメータの構造を間違える可能性があります

  2. 悪意のあるリクエスト: ブラウザの開発者ツールやプロキシツールを使って、意図的にパラメータを削除・改ざんするケース

  3. JavaScriptのバグ: カスタムAJAXリクエストを実装している場合、バグによってパラメータが正しく送信されないことがあります

  4. 自動テスト: テストコードで不完全なリクエストを送信するケース

実際のリスク評価:

params[:pair_work]nil の場合、Rails は即座にエラーを起こしません。問題が発生するのは、PairWork.update_permission? メソッド内で params[:pair_work] に対してメソッド呼び出しを行う場合です(例: params[:pair_work][:title].keys など)。

update_permission? の実装が nil チェックを含んでいれば問題ありませんが、含まれていない場合は NoMethodError が発生します。

推奨:

fetch(:pair_work, {}) のガードは防御的プログラミングの観点から有用ですが、必須ではありません。もし以下のいずれかに該当する場合は追加を検討してください:

  • update_permission? が nil チェックを行っていない
  • APIとして外部に公開される可能性がある
  • より堅牢なエラーハンドリングを望む

現在のコードで問題が発生していなければ、このまま進めても大丈夫だと思います。優先度は低めです。


🧠 Learnings used
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: 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)でのエラーハンドリングは不要。

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オブジェクトは常に有効であることが保証されている。そのためエラーハンドリングは不要。

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のみを含むペア確定リクエストのみを許可することで、権限昇格を防ぐセキュリティ対策が実装されている。

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: 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)は安全に使用できる。

Learnt from: komagata
Repo: fjordllc/bootcamp PR: 9101
File: app/notifiers/discord_notifier.rb:19-23
Timestamp: 2025-09-12T21:17:26.029Z
Learning: Rails アップグレードPRにおいて、config_for(:secrets) を使った webhook URL 設定の shared セクション未参照問題は、設定システム全体の変更として別PRで対応すべきである。

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/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番目の分岐での参照には注意が必要。

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

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: 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対応は不要と判断される。

Copy link
Contributor Author

@mousu-a mousu-a Dec 12, 2025

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 さん、承知しました!現在の実装で問題なく動作しているのであれば、このままで大丈夫です。ご判断ありがとうございました。


🧠 Learnings used
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: 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)でのエラーハンドリングは不要。

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オブジェクトは常に有効であることが保証されている。そのためエラーハンドリングは不要。

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のみを含むペア確定リクエストのみを許可することで、権限昇格を防ぐセキュリティ対策が実装されている。

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: 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: 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: komagata
Repo: fjordllc/bootcamp PR: 9101
File: app/notifiers/discord_notifier.rb:19-23
Timestamp: 2025-09-12T21:17:26.029Z
Learning: Rails アップグレードPRにおいて、config_for(:secrets) を使った webhook URL 設定の shared セクション未参照問題は、設定システム全体の変更として別PRで対応すべきである。

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)は安全に使用できる。

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

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対応は不要と判断される。


def set_wip
@pair_work.wip = params[:commit] == 'WIP'
end
end
23 changes: 23 additions & 0 deletions app/helpers/page_tabs/questions_and_pair_works_helper.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
# frozen_string_literal: true

module PageTabs
module QuestionsAndPairWorksHelper
def questions_and_pair_works_page_tabs
tabs = []
tabs << { name: 'Q&A', link: questions_path(target: 'not_solved'), badge: Question.unsolved_badge(current_user:, practice_id: params[:practice_id]) }
tabs << { name: 'ペアワーク', link: pair_works_path(target: 'not_solved'), badge: PairWork.unsolved_badge(current_user:) }
render PageTabsComponent.new(tabs:, active_tab: question_and_pair_work_active_tab)
end

private

def question_and_pair_work_active_tab
case request.path
when %r{\A/questions}
'Q&A'
when %r{\A/pair_works}
'ペアワーク'
end
end
end
end
38 changes: 38 additions & 0 deletions app/helpers/pair_work_helper.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
# frozen_string_literal: true

module PairWorkHelper
def schedule_dates(date)
(0..6).map { |i| date.to_date + i.days }
end

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
end

def disabled?(target_time, pair_work: nil)
if pair_work
target_time < Time.current || pair_work.user_id == current_user.id
else
target_time < Time.current
end
end

def learning_time_frame_checked?(target_time, id)
!disabled?(target_time) && current_user.learning_time_frame_ids.include?(id)
end

def schedule_time(day_count, hour_count)
Time.current.beginning_of_day + day_count.days + hour_count.hours
end

def schedule_check_box_id(target_time)
"schedule_ids_#{target_time.strftime('%Y%m%d%H%M')}"
end
end
26 changes: 26 additions & 0 deletions app/helpers/sub_tabs/pair_works_helper.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
# frozen_string_literal: true

module SubTabs
module PairWorksHelper
def pair_works_sub_tabs
tabs = []
tabs << { name: 'ペア募集中', link: pair_works_path(target: 'not_solved'), badge: PairWork.unsolved_badge(current_user:) }
tabs << { name: 'ペア確定', link: pair_works_path(target: 'solved') }
tabs << { name: '全て', link: pair_works_path }
render SubTabsComponent.new(tabs:, active_tab: pair_work_active_tab)
end

private

def pair_work_active_tab
case params[:target]
when 'not_solved'
'ペア募集中'
when 'solved'
'ペア確定'
else
'全て'
end
end
end
end
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
# frozen_string_literal: true

module PageTabs
module SubTabs
module QuestionsHelper
def questions_page_tabs
def questions_sub_tabs
unsolved_badge = Question.unsolved_badge(current_user:, practice_id: params[:practice_id])
tabs = []
tabs << { name: '未解決', link: questions_path(target: 'not_solved'), badge: unsolved_badge }
tabs << { name: '解決済み', link: questions_path(target: 'solved') }
tabs << { name: '全て', link: questions_path }
render PageTabsComponent.new(tabs:, active_tab: question_active_tab)
render SubTabsComponent.new(tabs:, active_tab: question_active_tab)
end

private
Expand Down
4 changes: 4 additions & 0 deletions app/javascript/stylesheets/application.sass
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@
@use "application/blocks/page/page"
@use "application/blocks/page/page-filter"
@use "application/blocks/page/page-main-filter"
@use "application/blocks/page/page-body-header"

@use "application/blocks/page-content/page-content"
@use "application/blocks/page-content/page-content-header-actions"
Expand Down Expand Up @@ -131,6 +132,9 @@
@use "application/blocks/coding-test/result-table"
@use "application/blocks/coding-test/coding-tests-item"

@use "application/blocks/pair-work/pair-work-info"
@use "application/blocks/pair-work/pair-work-schedule-dates"

@use "application/blocks/micro-report/micro-reports"
@use "application/blocks/micro-report/micro-report"
@use "application/blocks/micro-report/micro-report-form"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,14 @@

.event-main-actions
+position.position(relative, 1)
padding-block: .75rem
margin-inline: 1rem
border-radius: 4px
&:first-child
margin-top: 1rem
margin-bottom: 0
+break-points.media-breakpoint-up(md)
padding-inline: 2rem
margin-bottom: 1.5rem
+break-points.media-breakpoint-down(sm)
padding-inline: .75rem
margin-bottom: 1rem
&.is-participationed
background-color: #f8fff2
Expand All @@ -31,6 +31,42 @@
background-color: var(--danger-tint)
color: var(--danger)

.event-main-actions__header
padding-block: .75rem
display: flex
justify-content: space-between
align-items: center
+break-points.media-breakpoint-up(md)
padding-inline: 1rem
+break-points.media-breakpoint-down(sm)
padding-inline: .75rem
.is-participationed &
border-bottom: 1px solid var(--success)
color: #4e732e
.is-unparticipationed.is-available &
border-bottom: 1px solid var(--primary)
color: #116e94
.is-unparticipationed.is-capacity-over &
border-bottom: 1px solid var(--warning)
color: #6f5819
.is-non-participationed &
border-bottom: 1px solid var(--danger)
color: var(--danger)
.a-button
margin-block: -.5rem

.event-main-actions__title
+text.text-block(.875rem 1.4)
font-weight: 700
text-align: center

.event-main-actions__body
padding-block: .75rem
+break-points.media-breakpoint-up(md)
padding-inline: 1rem
+break-points.media-breakpoint-down(sm)
padding-inline: .75rem

.event-main-actions__description
+text.text-block(.875rem 1.4)
margin-bottom: .75em
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
@use "../../../config/mixins/text"

.page-body-header__inner
display: flex
align-items: center
gap: 1rem
margin-bottom: 1rem

.page-body-header__title
+text.text-block(1rem 1.4, 700)
color: var(--main)
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
@use "../../../config/mixins/break-points"
@use "../../../config/mixins/position"
@use "../../../config/mixins/size"
@use "../../../config/mixins/text"

.pair-work-info
display: flex
gap: .75rem
Comment on lines +6 to +8
Copy link

@coderabbitai coderabbitai bot Aug 21, 2025

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

絶対配置の基準要素を明示してバッジの位置ズレを防止

.pair-badgeposition: absolute で配置されていますが、同一ブロック内(もしくは意図した親要素)に position: relative が無いと、祖先の別コンテナを基準に計算されレイアウトが不安定になります。.pair-work-info を配置コンテキストにするのが安全です。

 .pair-work-info
   display: flex
   gap: .75rem
+  position: relative
📝 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
.pair-work-info
display: flex
gap: .75rem
.pair-work-info
display: flex
gap: .75rem
position: relative
🤖 Prompt for AI Agents
In app/javascript/stylesheets/application/blocks/pair-work/_pair-work-info.sass
around lines 1–3, the .pair-badge uses position: absolute but the containing
block is not defined, causing badges to be positioned relative to an unintended
ancestor; fix this by adding position: relative to the .pair-work-info block so
it becomes the positioning context for .pair-badge, ensuring consistent badge
placement within the component.

Copy link
Contributor Author

@mousu-a mousu-a Aug 28, 2025

Choose a reason for hiding this comment

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

@machida
すみません、coderabbitのデザイン部分に関する指摘になります。
こちらいかがでしょうか🙏

Copy link

Choose a reason for hiding this comment

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

Seems like the humans are having a chat. I'll hop back into my burrow for now. If you need me again, just tag @CodeRabbit in a new comment, and I'll come hopping out!

Copy link
Member

Choose a reason for hiding this comment

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

@coderabbitai

.page-content-header で position: relative を指定してあるので、意図通りの表示ができています。

Copy link

Choose a reason for hiding this comment

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

@machida ご指摘いただき、ありがとうございます!

.page-content-header で既に position: relative が設定されているため、.pair-badge の絶対配置は意図通りに動作するということですね。より広いコンテキストでの配置構成を見落としていました。

現在の実装で正しく表示されているのであれば、追加の変更は不要ですね。貴重な情報をありがとうございました。


✏️ Learnings added
Learnt from: machida
PR: fjordllc/bootcamp#8566
File: app/javascript/stylesheets/application/blocks/pair-work/_pair-work-info.sass:1-3
Timestamp: 2025-09-14T17:37:33.058Z
Learning: app/javascript/stylesheets/application/blocks/pair-work/_pair-work-info.sass において、.pair-badge の絶対配置は .page-content-header で設定されている position: relative を基準として動作する設計になっている。

Note: Learnings are effective only in the context of similar code segments. To apply general coding guidelines, please configure review instructions. You can manage existing learnings in the app.


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

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のスコープ維持が重要。


.pair-work-info__user-icon
+size.size(3.5rem)

.pair-work-info__end
flex: 1

.pair-badge
font-family: serif
border: double .1875rem var(--stamp-color)
border-radius: .75rem
+size.size(4rem 3.5rem)
padding: .125rem
+position.position(absolute, right 0, top -.125rem, 1)
transform: rotate(25deg)
+text.text-block(1.125rem 1.1, flex center)
font-weight: 800
color: var(--stamp-color)
flex-direction: column
align-items: center
justify-content: center
pointer-events: none
+break-points.media-breakpoint-down(sm)
+position.position(absolute, left 80%, top 0)
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
@use "../../../config/mixins/text"

.pair-work-schedule-dates
&.is-solved
.pair-work-schedule-dates__table
display: none
input:checked + .pair-work-schedule-dates__table
display: block

.pair-work-schedule-dates__action-items
display: flex
justify-content: center

.pair-work-schedule-dates__action-item
min-width: 20rem

.pair-work-schedule-dates__action-item-description
margin-top: .25rem
+text.text-block(.75rem 1.4, center)

.pair-work-schedule-dates__title
+text.text-block(1rem 1.4, 600)
margin-bottom: 1rem

.pair-work-schedule-dates__table
.pair-work-schedule-dates__action + .pair-work-schedule-dates__table-container &
margin-top: 1rem

.pair-work-schedule-dates__cancel
display: flex
justify-content: center
margin-bottom: 1rem

.pair-work-schedule-dates__cancel-action
min-width: 20rem
Loading