Skip to content

プロフィールとダッシュボードに連続学習記録の表示を追加#9173

Merged
komagata merged 13 commits intomainfrom
feature/add-studying-streak-tracker-in-profile-page
Dec 17, 2025
Merged

プロフィールとダッシュボードに連続学習記録の表示を追加#9173
komagata merged 13 commits intomainfrom
feature/add-studying-streak-tracker-in-profile-page

Conversation

@jun-kondo
Copy link
Copy Markdown
Contributor

@jun-kondo jun-kondo commented Sep 12, 2025

Issue

概要

生徒、もしくは研修生のプロフィールページとダッシュボードに連続学習記録の表示を追加しました。
ユーザーの日報のデータを使い、学習日とそうでない日を判別します。
学習日かどうかの判定の対象は日報の日付であり、作成日や更新日ではありません。

学習日の判別のルール

学習日である

  • 日報が作成されており、wip状態ではない
  • 日報の学習時間の項目に記入がある(例: 18:00 - 20:15)

学習日ではない

  • 日報が作成されていない
  • 日報は作成されているが、wip状態である
  • 日報の学習時間が無い(作成時に「学習時間無し」のボックスにチェックを入れている)

補足

  • 連続記録が途切れてもカウントは0にはならず、日報を提出を再開するとカウント1から再スタートになります。
  • 日付を遡って上記の条件で日報を作成するとその日は学習日としてカウントされます。
  • 学習時間を入力して提出した日報を更新してwipにしたり、学習時間無しにするとその日は学習日扱いではなくなる。

変更確認方法

  1. ブランチをローカルに取り込む
git fetch origin feature/add-studying-streak-tracker-in-profile-page
git checkout feature/add-studying-streak-tracker-in-profile-page
  1. ローカルサーバーの立ち上げ
foreman start -f Procfile.dev
  1. hatsunoの日報データを作成
rails コンソールで日報データを作成
rails c

1日あたり二時間の学習時間を記録した日報データを今日の日付から1週間分作成します。

user = User.find(655153192) # hatsuno

(0..6).each do |days_ago|
    date = Date.current - days_ago
    next if Report.exists?(user_id: user.id, reported_on: date)

    r = Report.new(
        user_id: user.id,
        title: "test #{date}",
        reported_on: date,
        description: 'test',
        wip: false
    )
    r.learning_times << LearningTime.new(
        started_at: "#{date} 00:00:00",
        finished_at: "#{date} 02:00:00"
    )
    r.save!
    puts "Created report for #{date}"
end
  1. 任意のユーザーでログイン
  2. hatsunoのプロフィールページ(http://localhost:3000/users/655153192) に移動し、「学習連続記録」の表示が出ているか確認
  3. hatsunoのダッシュボード(http://localhost:3000) に移動し、「学習連続記録」の表示が出ているか確認

Screenshot

変更前

ダッシュボード プロフィールページ
表示無し 表示無し

変更後

ダッシュボード プロフィールページ
Image from Gyazo Image from Gyazo

Summary by CodeRabbit

  • 新機能

    • 学習の連続記録(現在の連続日数・最長連続日数)を表示するトラッカーを追加。ダッシュボードとユーザープロフィールに学習時間がある場合のみ表示。
  • スタイル

    • レスポンシブ対応の学習連続記録UIスタイルを追加・調整。
  • テスト

    • モデル/コンポーネントの包括的なユニットテストとテスト用ヘルパーを追加。

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

@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Sep 12, 2025

Walkthrough

学習連続記録機能を追加。User に学習時間付きレポート取得メソッドを追加し、StudyStreak モデルで現在/最長ストリークを算出、ViewComponent と SASS で表示、コントローラーはビューで使用する @study_streak を初期化。テストとテストヘルパーも追加。

Changes

Cohort / File(s) Change Summary
Model Layer
app/models/user.rb, app/models/study_streak.rb
User#reports_with_learning_times を追加(learning_times を結合して日付順に取得)。新規 StudyStreak クラスを追加し、報告日の連続日数をチャンク化して current/longest ストリークを算出(WIP 除外オプション)。
Controller Layer
app/controllers/home_controller.rb, app/controllers/users_controller.rb
ダッシュボードとユーザー表示で @study_streak を初期化(StudyStreak.new(..., include_wip: false) を設定)。
View Templates
app/views/home/index.html.slim, app/views/users/show.html.slim
学習時間が正のときに StudyStreak::StudyStreakTrackerComponent を条件付きでレンダリング。users/show に表示順や既存ブロックの調整あり。
Component Layer
app/components/study_streak/study_streak_tracker_component.rb, app/components/study_streak/study_streak_tracker_component.html.slim
新規 ViewComponent を追加。study_streak を受け取り、current/longest の日数と期間文字列を算出してレンダリング。期間フォーマットに年判定ロジックあり。
Styling
app/javascript/stylesheets/application.sass, app/javascript/stylesheets/application/blocks/user/_user-study-streak-tracker.sass
application.sass にインポート追加。新規 SASS ファイルで .streak-card 等のクラスとレスポンシブスタイルを定義。
Test Support
test/supports/report_helper.rb
テスト用ヘルパー create_report_data_with_learning_times を追加(Report と LearningTime を生成)。
Tests
test/models/user_test.rb, test/models/study_streak_test.rb, test/components/study_streak/study_streak_tracker_component_test.rb
User メソッド、StudyStreak ロジック、コンポーネント表示に関する単体テストを追加。WIP 処理・年跨ぎフォーマット・タイブレイク等を検証。

Sequence Diagram

sequenceDiagram
    participant Browser as ブラウザ
    participant Controller as Controller (Home/Users)
    participant UserModel as User (reports_with_learning_times)
    participant StudyStreak as StudyStreak (モデル)
    participant Component as StudyStreak::StudyStreakTrackerComponent
    participant UI as 表示 (HTML/CSS)

    Browser->>Controller: ダッシュボード/プロフィール要求
    Controller->>UserModel: reports_with_learning_times
    UserModel-->>Controller: レポート一覧(学習時間付き)
    Controller->>StudyStreak: StudyStreak.new(reports, include_wip: false)
    StudyStreak->>StudyStreak: 日付抽出→連続日チャンク化→current/longest 計算
    StudyStreak-->>Controller: StudyStreak オブジェクト
    Controller->>Component: render(study_streak: `@study_streak`)
    Component->>Component: current?/longest? 判定・format_period 呼び出し
    Component-->>UI: HTML(ストリーク数・期間)
    UI-->>Browser: レンダリング
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~30 minutes

  • 注目箇所:
    • StudyStreak#streak_periods の chunk_while ロジックと最長選定(同長のタイブレイク)
    • Component の format_period における年判定と I18n フォーマット選定
    • テストの time travel と WIP フラグ周りの期待値設定

Possibly related PRs

Suggested reviewers

  • machida
  • komagata

Poem

🐰 連続数えてぴょんぴょんと、
今日の学びはひとつの光、
日が積もればストリーク伸びる、
カードに刻む小さな誇り、
ニンジンで祝おう、ポンッ! 🥕

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed プルリクエストのタイトルは、プロフィールとダッシュボードに連続学習記録表示を追加する主要な変更を明確かつ簡潔に要約しており、変更セット全体の主要な目的を適切に反映している。
Description check ✅ Passed 説明はテンプレートの全セクションを網羅しており、Issue番号、詳細な概要、学習日の判別ルール、変更確認手順、スクリーンショットなど必要な情報が完備されている。
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feature/add-studying-streak-tracker-in-profile-page

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.

@jun-kondo jun-kondo changed the title UserStudyStreakクラスを新規作成し、学習継続期間と最長期間を計算するロジックを実装 プロフィールページに連続学習機能の表示を追加 Sep 12, 2025
@jun-kondo jun-kondo self-assigned this Sep 12, 2025
@jun-kondo
Copy link
Copy Markdown
Contributor Author

jun-kondo commented Sep 12, 2025

@machida
お疲れ様です🍵
プロフィールページに連続学習記録を表示するように致しました。
デザインの方をお願い致します🙇‍♂️

デザイン対象のHTMLファイルが app/components/study_streak/user_study_streak_tracker_component.html.slim
仮のCSSファイルがapp/javascript/stylesheets/application/blocks/user/_user-study-streak-tracker.sass になります。

デザインを確認する際に日報データを作成する必要があるのですが、コンソールで作成できるよう手順をプルリクエスト本文の変更確認手順に記載しました。
お手数おかけしますが、宜しくお願い致します🙇‍♂️

@jun-kondo jun-kondo changed the title プロフィールページに連続学習機能の表示を追加 プロフィールページに連続学習記録の表示を追加 Sep 12, 2025
@jun-kondo
Copy link
Copy Markdown
Contributor Author

@machida
4d96d3f
の内容確認致しました。色々考慮不足な箇所を修正して頂きありがとうございます🙇‍♂️
確認なのですが、machidaさん側の作業は終了していますか?👀

@machida
Copy link
Copy Markdown
Member

machida commented Oct 9, 2025

@jun-kond
確認ありがとうございます!!
今テストを通したので作業が終わりましたー

@jun-kondo jun-kondo force-pushed the feature/add-studying-streak-tracker-in-profile-page branch from 1c55f5b to d3e1f80 Compare October 10, 2025 15:02
@jun-kondo jun-kondo marked this pull request as ready for review October 10, 2025 15:32
@github-actions github-actions bot requested a review from komagata October 10, 2025 15:32
Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (5)
app/javascript/stylesheets/application/blocks/user/_user-study-streak-tracker.sass (1)

34-34: 色の値をCSS変数に置き換えてください。

#f7941d がハードコードされていますが、同じファイル内の他の箇所(Line 50)では var(--muted-text) のようにCSS変数を使用しています。テーマの一貫性と保守性を向上させるため、この色もCSS変数として定義することを推奨します。

次のように修正できます:

 .streak-item__number
   font-weight: 700
-  color: #f7941d
+  color: var(--streak-number-color)
   +media-breakpoint-up(md)
     +text-block(2.5rem 1)
   +media-breakpoint-down(sm)
     +text-block(2rem 1)

そして、対応するCSS変数を定義ファイルに追加してください。

test/supports/report_helper.rb (1)

48-58: 時間生成と永続化オプションを見直してください

  • Time.zone.parse の文字列パースより Time.zone.local + on.to_date を使う方が堅牢で高速です。
  • 「学習時間なし(no_learn)の日報をDBに存在させたい」ケースに備え、no_learn 時も任意で保存できるオプションがあると便利です(現状は保存されないため再現できません)。

以下のような修正を提案します:

-def create_report_data_with_learning_times(user:, on:, wip: false, no_learn: false, durations: [[9, 12]])
-  report = Report.new(user:, title: "test #{on}", emotion: 2, description: 'desc', reported_on: on, wip:, no_learn:)
-  unless no_learn
-    durations.each do |(s, e)|
-      report.learning_times << LearningTime.new(report:, started_at: Time.zone.parse("#{on} #{format('%02d:00:00', s)}"),
-                                                finished_at: Time.zone.parse("#{on} #{format('%02d:00:00', e)}"))
-    end
-    report.save!
-  end
-  report
-end
+def create_report_data_with_learning_times(user:, on:, wip: false, no_learn: false, durations: [[9, 12]], persist_when_no_learn: false)
+  on_date = on.to_date
+  report = Report.new(user:, title: "test #{on_date}", emotion: 2, description: 'desc', reported_on: on_date, wip:, no_learn:)
+  if no_learn
+    report.save! if persist_when_no_learn
+  else
+    durations.each do |(s, e)|
+      report.learning_times << LearningTime.new(
+        report:,
+        started_at: Time.zone.local(on_date.year, on_date.month, on_date.day, s, 0, 0),
+        finished_at: Time.zone.local(on_date.year, on_date.month, on_date.day, e, 0, 0)
+      )
+    end
+    report.save!
+  end
+  report
+end
app/models/user_study_streak.rb (1)

21-24: distinct を追加して重複日付の混入を防止

引数の reports が distinct でない場合、同日の重複が chunk_while の連続日評価を乱す可能性があります。ここで distinct を噛ませておくと安全です(既に distinct 済みでも冪等)。

 def report_dates(reports)
-  reports = reports.not_wip unless include_wip
-  reports.order(reported_on: :asc).pluck(:reported_on)
+  reports = reports.not_wip unless include_wip
+  reports.distinct.order(reported_on: :asc).pluck(:reported_on)
 end
test/models/user_study_streak_test.rb (1)

65-85: テスト名の英語を簡潔に

可読性のため、以下へリネームを提案します。

-test 'study streak should include wip report days when include wip option be true report' do
+test 'includes WIP days when include_wip is true' do
app/components/study_streak/user_study_streak_tracker_component.rb (1)

42-53: ローカル変数の割り当てを簡略化できます

45-46行目のstart_dateend_dateへの割り当ては不要です。start_onend_onを直接使用できます。

次のように簡略化できます:

 def format_period(days:, start_on:, end_on:)
   return '' if days.to_i.zero? || start_on.nil? || end_on.nil?
 
-  start_date = start_on
-  end_date = end_on
   current_year = Time.zone.today.year
-  if start_date.year == end_date.year && start_date.year == current_year
-    "#{start_date.strftime('%m/%d')} 〜 #{end_date.strftime('%m/%d')}"
+  if start_on.year == end_on.year && start_on.year == current_year
+    "#{start_on.strftime('%m/%d')} 〜 #{end_on.strftime('%m/%d')}"
   else
-    "#{start_date.strftime('%Y/%m/%d')} 〜 #{end_date.strftime('%Y/%m/%d')}"
+    "#{start_on.strftime('%Y/%m/%d')} 〜 #{end_on.strftime('%Y/%m/%d')}"
   end
 end
📜 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 26ad439 and d3e1f80.

📒 Files selected for processing (14)
  • app/components/study_streak/user_study_streak_tracker_component.html.slim (1 hunks)
  • app/components/study_streak/user_study_streak_tracker_component.rb (1 hunks)
  • app/controllers/home_controller.rb (1 hunks)
  • app/controllers/users_controller.rb (1 hunks)
  • app/javascript/stylesheets/application.sass (1 hunks)
  • app/javascript/stylesheets/application/blocks/user/_user-study-streak-tracker.sass (1 hunks)
  • app/models/user.rb (1 hunks)
  • app/models/user_study_streak.rb (1 hunks)
  • app/views/home/index.html.slim (1 hunks)
  • app/views/users/show.html.slim (2 hunks)
  • test/components/study_streak/user_study_streak_tracker_component_test.rb (1 hunks)
  • test/models/user_study_streak_test.rb (1 hunks)
  • test/models/user_test.rb (1 hunks)
  • test/supports/report_helper.rb (1 hunks)
🧰 Additional context used
📓 Path-based instructions (2)
**/*.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/user.rb
  • app/controllers/home_controller.rb
  • test/supports/report_helper.rb
  • app/models/user_study_streak.rb
  • app/controllers/users_controller.rb
  • test/models/user_test.rb
  • app/components/study_streak/user_study_streak_tracker_component.rb
  • test/components/study_streak/user_study_streak_tracker_component_test.rb
  • test/models/user_study_streak_test.rb
test/**/*

⚙️ CodeRabbit configuration file

test/**/*: # Test

  • TestCase名は英語で書く。
  • どうしても避けられない時以外にsystem testでsleepは使わない。

Unit Test

model, helper, decorator, view_componentについてはメソッドを追加した場合は必ず対応したUnit TestのTestCaseを1つは書く。

Files:

  • test/supports/report_helper.rb
  • test/models/user_test.rb
  • test/components/study_streak/user_study_streak_tracker_component_test.rb
  • test/models/user_study_streak_test.rb
🧬 Code graph analysis (5)
app/controllers/home_controller.rb (1)
app/models/user.rb (1)
  • reports_with_learning_times (929-931)
app/controllers/users_controller.rb (1)
app/models/user.rb (1)
  • reports_with_learning_times (929-931)
test/models/user_test.rb (1)
app/models/user.rb (1)
  • reports_with_learning_times (929-931)
test/components/study_streak/user_study_streak_tracker_component_test.rb (3)
test/models/user_study_streak_test.rb (1)
  • include (6-85)
test/supports/report_helper.rb (1)
  • create_report_data_with_learning_times (48-58)
app/models/user.rb (1)
  • reports_with_learning_times (929-931)
test/models/user_study_streak_test.rb (2)
test/supports/report_helper.rb (1)
  • create_report_data_with_learning_times (48-58)
app/models/user.rb (1)
  • reports_with_learning_times (929-931)
🔇 Additional comments (10)
app/javascript/stylesheets/application.sass (1)

124-124: LGTM!

新しいスタイルシートのインポートが適切に追加されています。他のユーザーブロックのインポートと同じセクションに配置されており、一貫性があります。

app/views/home/index.html.slim (1)

41-42: LGTM!

学習時間が存在する場合のみコンポーネントを描画する条件分岐が適切です。ViewComponentパターンに従っており、コーディングガイドラインに準拠しています。

app/models/user.rb (1)

929-931: LGTM!

学習時間を持つ日報を効率的に取得するメソッドが適切に実装されています。joins を使用することでN+1クエリを回避し、distinct で重複を排除し、reported_on で昇順にソートしています。

app/controllers/users_controller.rb (1)

48-49: 空のレポートコレクションに対する動作を確認してください。

HomeController と同様に、reports_with_learning_times が空の結果を返した場合でも UserStudyStreak が適切に処理できることを確認してください。

HomeControllerで提案したスクリプトを実行して、UserStudyStreak の実装を確認してください。

app/components/study_streak/user_study_streak_tracker_component.html.slim (1)

1-31: LGTM!

学習連続記録を表示するコンポーネントテンプレートが適切に実装されています。以下の点が優れています:

  • 意味的に明確なHTML構造
  • SASSファイルで定義されたCSSクラスとの整合性
  • 期間情報の条件付き表示(Lines 17-19, 29-31)
  • わかりやすい日本語ラベル

ViewComponentパターンに従っており、コーディングガイドラインに準拠しています。

test/models/user_test.rb (1)

60-73: LGTM!

#reports_with_learning_times メソッドのテストが包括的に実装されています。以下のシナリオを適切にカバーしています:

  • 初期状態(空のコレクション)
  • 学習時間を持つ日報の取得
  • no_learn: true の日報の除外

テスト名が英語であることもコーディングガイドラインに準拠しています。

app/controllers/home_controller.rb (1)

13-13: UserStudyStreak は空のレポートを正しく処理します
空の reports_with_learning_times を渡した場合でも内部で空配列や nil を扱うため、追加の検証や null チェックは不要です。

app/views/users/show.html.slim (2)

67-68: 描画条件は妥当ですが、@study_streak のセットを確認してください

UsersController#show(およびダッシュボード側)で必ず @study_streak をセットしていることをご確認ください。ガードはあるため未設定時でも例外にはなりませんが、将来の変更で意図せず参照されるリスクを減らせます。


101-120: 管理者向けカードの移動 OK

表示条件と構造は問題ありません。career_path が nil の場合の表示についてだけ、翻訳キーの存在/フォールバックをご確認ください(translation missing が出ないこと)。

app/components/study_streak/user_study_streak_tracker_component.rb (1)

3-38: ViewComponentのパターンに沿った適切な実装です

コンポーネントの構造は明確で、各メソッドが単一の責務を持っています。study_streakオブジェクトへの委譲と、防御的な.to_iによる変換も適切です。

@jun-kondo jun-kondo force-pushed the feature/add-studying-streak-tracker-in-profile-page branch from d3e1f80 to ce55112 Compare October 10, 2025 16:48
Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

📜 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 d3e1f80 and ce55112.

📒 Files selected for processing (2)
  • app/components/study_streak/user_study_streak_tracker_component.rb (1 hunks)
  • test/components/study_streak/user_study_streak_tracker_component_test.rb (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • app/components/study_streak/user_study_streak_tracker_component.rb
🧰 Additional context used
📓 Path-based instructions (2)
**/*.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:

  • test/components/study_streak/user_study_streak_tracker_component_test.rb
test/**/*

⚙️ CodeRabbit configuration file

test/**/*: # Test

  • TestCase名は英語で書く。
  • どうしても避けられない時以外にsystem testでsleepは使わない。

Unit Test

model, helper, decorator, view_componentについてはメソッドを追加した場合は必ず対応したUnit TestのTestCaseを1つは書く。

Files:

  • test/components/study_streak/user_study_streak_tracker_component_test.rb
🧬 Code graph analysis (1)
test/components/study_streak/user_study_streak_tracker_component_test.rb (3)
test/models/user_study_streak_test.rb (1)
  • include (6-85)
test/supports/report_helper.rb (1)
  • create_report_data_with_learning_times (48-58)
app/models/user.rb (1)
  • reports_with_learning_times (929-931)
⏰ 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 (1)
test/components/study_streak/user_study_streak_tracker_component_test.rb (1)

24-26: teardown の追加、LGTM!

以前のレビューで指摘された travel_to のクリーンアップが適切に実装されています。テスト間の時刻リークを防ぐことができます。

@jun-kondo jun-kondo force-pushed the feature/add-studying-streak-tracker-in-profile-page branch from ce55112 to 629c96b Compare October 10, 2025 17:54
Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

🧹 Nitpick comments (1)
app/components/study_streak/user_study_streak_tracker_component.rb (1)

45-46: 冗長な変数代入を削除可能

start_onend_on をローカル変数 start_dateend_date に代入していますが、パラメータを直接使用できます。

以下の diff を適用して簡潔にできます:

   def format_period(days:, start_on:, end_on:)
     return '' if days.to_i.zero? || start_on.nil? || end_on.nil?
 
-    start_date = start_on
-    end_date = end_on
     current_year = Time.zone.today.year
-    if start_date.year == end_date.year && start_date.year == current_year
-      "#{start_date.strftime('%m/%d')} 〜 #{end_date.strftime('%m/%d')}"
+    if start_on.year == end_on.year && start_on.year == current_year
+      "#{start_on.strftime('%m/%d')} 〜 #{end_on.strftime('%m/%d')}"
     else
-      "#{start_date.strftime('%Y/%m/%d')} 〜 #{end_date.strftime('%Y/%m/%d')}"
+      "#{start_on.strftime('%Y/%m/%d')} 〜 #{end_on.strftime('%Y/%m/%d')}"
     end
   end
📜 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 ce55112 and 629c96b.

📒 Files selected for processing (2)
  • app/components/study_streak/user_study_streak_tracker_component.rb (1 hunks)
  • test/components/study_streak/user_study_streak_tracker_component_test.rb (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • test/components/study_streak/user_study_streak_tracker_component_test.rb
🧰 Additional context used
📓 Path-based instructions (1)
**/*.rb

⚙️ CodeRabbit configuration file

**/*.rb: # refactoring

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

Rails Patterns

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

Files:

  • app/components/study_streak/user_study_streak_tracker_component.rb
⏰ 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 (1)
app/components/study_streak/user_study_streak_tracker_component.rb (1)

3-53: LGTM! ViewComponent の実装は適切です

このコンポーネントの設計は以下の点で良好です:

  • コーディングガイドラインに従い、partial の代わりに ViewComponent を使用している
  • 表示ロジックをコンポーネントに集約し、責務が明確
  • format_period メソッドで期間フォーマットのロジックを一箇所にまとめている
  • .to_i を使用した防御的なコーディングにより、nil 値を安全に扱っている
  • タイムゾーンを考慮して Time.zone.today を使用している

連続学習記録の表示機能として、適切に実装されています。

@jun-kondo jun-kondo force-pushed the feature/add-studying-streak-tracker-in-profile-page branch from 629c96b to 244a441 Compare October 11, 2025 08:33
Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

📜 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 629c96b and 244a441.

📒 Files selected for processing (14)
  • app/components/study_streak/user_study_streak_tracker_component.html.slim (1 hunks)
  • app/components/study_streak/user_study_streak_tracker_component.rb (1 hunks)
  • app/controllers/home_controller.rb (1 hunks)
  • app/controllers/users_controller.rb (1 hunks)
  • app/javascript/stylesheets/application.sass (1 hunks)
  • app/javascript/stylesheets/application/blocks/user/_user-study-streak-tracker.sass (1 hunks)
  • app/models/user.rb (1 hunks)
  • app/models/user_study_streak.rb (1 hunks)
  • app/views/home/index.html.slim (1 hunks)
  • app/views/users/show.html.slim (2 hunks)
  • test/components/study_streak/user_study_streak_tracker_component_test.rb (1 hunks)
  • test/models/user_study_streak_test.rb (1 hunks)
  • test/models/user_test.rb (1 hunks)
  • test/supports/report_helper.rb (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (9)
  • test/supports/report_helper.rb
  • app/models/user_study_streak.rb
  • app/javascript/stylesheets/application/blocks/user/_user-study-streak-tracker.sass
  • test/models/user_study_streak_test.rb
  • test/components/study_streak/user_study_streak_tracker_component_test.rb
  • app/controllers/home_controller.rb
  • app/javascript/stylesheets/application.sass
  • app/controllers/users_controller.rb
  • app/components/study_streak/user_study_streak_tracker_component.html.slim
🧰 Additional context used
📓 Path-based instructions (2)
**/*.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:

  • test/models/user_test.rb
  • app/models/user.rb
  • app/components/study_streak/user_study_streak_tracker_component.rb
test/**/*

⚙️ CodeRabbit configuration file

test/**/*: # Test

  • TestCase名は英語で書く。
  • どうしても避けられない時以外にsystem testでsleepは使わない。

Unit Test

model, helper, decorator, view_componentについてはメソッドを追加した場合は必ず対応したUnit TestのTestCaseを1つは書く。

Files:

  • test/models/user_test.rb
🧬 Code graph analysis (2)
test/models/user_test.rb (1)
app/models/user.rb (1)
  • reports_with_learning_times (929-931)
app/components/study_streak/user_study_streak_tracker_component.rb (1)
app/javascript/dateFormatter.js (1)
  • year (9-9)
⏰ 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

@jun-kondo jun-kondo force-pushed the feature/add-studying-streak-tracker-in-profile-page branch from 244a441 to e798f39 Compare October 11, 2025 09:03
@jun-kondo jun-kondo changed the title プロフィールページに連続学習記録の表示を追加 プロフィールとダッシュボードに連続学習記録の表示を追加 Oct 11, 2025
Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

♻️ Duplicate comments (1)
app/components/study_streak/user_study_streak_tracker_component.rb (1)

45-47: 年比較のバグは解消済みで OK

start_on.year と Time.zone.today.year の比較に修正されており、意図通りです。

🧹 Nitpick comments (3)
test/supports/report_helper.rb (1)

48-58: no_learn:true 時も常に保存し、時刻生成を safer にしましょう

  • no_learn:true の場合に未保存の Report を返すのは挙動が揺れてテストの落とし穴になりがちです。常に保存を推奨。
  • 時刻は文字列 parse より Time.zone.local の方が DST に強く、意図が明確です。
-  def create_report_data_with_learning_times(user:, on:, wip: false, no_learn: false, durations: [[9, 12]])
-    report = Report.new(user:, title: "test #{on}", emotion: 2, description: 'desc', reported_on: on, wip:, no_learn:)
-    unless no_learn
-      durations.each do |(s, e)|
-        report.learning_times << LearningTime.new(report:, started_at: Time.zone.parse("#{on} #{format('%02d:00:00', s)}"),
-                                                  finished_at: Time.zone.parse("#{on} #{format('%02d:00:00', e)}"))
-      end
-      report.save!
-    end
-    report
-  end
+  def create_report_data_with_learning_times(user:, on:, wip: false, no_learn: false, durations: [[9, 12]])
+    report = Report.new(user:, title: "test #{on}", emotion: 2, description: 'desc', reported_on: on, wip:, no_learn:)
+    unless no_learn
+      durations.each do |(s, e)|
+        # s < e を前提。必要なら guard を追加。
+        started = Time.zone.local(on.year, on.month, on.day, s, 0, 0)
+        finished = Time.zone.local(on.year, on.month, on.day, e, 0, 0)
+        report.learning_times.build(started_at: started, finished_at: finished)
+      end
+    end
+    report.save!
+    report
+  end
app/views/users/show.html.slim (1)

101-120: 「卒業後の進路」カードの重複表示がないか再確認

同様のカードが他の分岐や部分テンプレートでも表示されていないか確認してください。重複なら片方へ統一を。

app/controllers/home_controller.rb (1)

13-13: 必要時のみ @study_streak を生成して無駄を削減

表示条件に合わせて生成を条件分岐すると軽量です。

-      @study_streak = UserStudyStreak.new(current_user.reports_with_learning_times, include_wip: false)
+      if current_user.total_learning_time.positive?
+        @study_streak = UserStudyStreak.new(current_user.reports_with_learning_times, include_wip: false)
+      end
📜 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 244a441 and e798f39.

📒 Files selected for processing (11)
  • app/components/study_streak/user_study_streak_tracker_component.html.slim (1 hunks)
  • app/components/study_streak/user_study_streak_tracker_component.rb (1 hunks)
  • app/controllers/home_controller.rb (1 hunks)
  • app/javascript/stylesheets/application.sass (1 hunks)
  • app/javascript/stylesheets/application/blocks/user/_user-study-streak-tracker.sass (1 hunks)
  • app/views/home/index.html.slim (1 hunks)
  • app/views/users/show.html.slim (2 hunks)
  • test/components/study_streak/user_study_streak_tracker_component_test.rb (1 hunks)
  • test/models/user_study_streak_test.rb (1 hunks)
  • test/models/user_test.rb (1 hunks)
  • test/supports/report_helper.rb (1 hunks)
✅ Files skipped from review due to trivial changes (1)
  • app/javascript/stylesheets/application.sass
🚧 Files skipped from review as they are similar to previous changes (2)
  • app/javascript/stylesheets/application/blocks/user/_user-study-streak-tracker.sass
  • test/models/user_test.rb
🧰 Additional context used
📓 Path-based instructions (2)
**/*.rb

⚙️ CodeRabbit configuration file

**/*.rb: # refactoring

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

Rails Patterns

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

Files:

  • app/controllers/home_controller.rb
  • app/components/study_streak/user_study_streak_tracker_component.rb
  • test/components/study_streak/user_study_streak_tracker_component_test.rb
  • test/models/user_study_streak_test.rb
  • test/supports/report_helper.rb
test/**/*

⚙️ CodeRabbit configuration file

test/**/*: # Test

  • TestCase名は英語で書く。
  • どうしても避けられない時以外にsystem testでsleepは使わない。

Unit Test

model, helper, decorator, view_componentについてはメソッドを追加した場合は必ず対応したUnit TestのTestCaseを1つは書く。

Files:

  • test/components/study_streak/user_study_streak_tracker_component_test.rb
  • test/models/user_study_streak_test.rb
  • test/supports/report_helper.rb
🧬 Code graph analysis (4)
app/controllers/home_controller.rb (1)
app/models/user.rb (1)
  • reports_with_learning_times (929-931)
app/components/study_streak/user_study_streak_tracker_component.rb (1)
app/javascript/dateFormatter.js (1)
  • year (9-9)
test/components/study_streak/user_study_streak_tracker_component_test.rb (3)
test/models/user_study_streak_test.rb (1)
  • include (6-85)
test/supports/report_helper.rb (1)
  • create_report_data_with_learning_times (48-58)
app/models/user.rb (1)
  • reports_with_learning_times (929-931)
test/models/user_study_streak_test.rb (2)
test/supports/report_helper.rb (1)
  • create_report_data_with_learning_times (48-58)
app/models/user.rb (1)
  • reports_with_learning_times (929-931)
⏰ 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 (5)
app/views/home/index.html.slim (1)

41-42: 表示条件と Controller の初期化が整合しており問題なし

total_learning_time > 0 の条件下での表示で妥当です。

app/views/users/show.html.slim (1)

67-68: @study_streak は show アクションで必ず初期化されているため、ビューでの presence ガードは不要です。

app/components/study_streak/user_study_streak_tracker_component.html.slim (1)

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

ViewComponent のテンプレートとして適切な実装です。条件付きレンダリング(lines 17-19, 29-31)により、連続記録が0日の場合に期間を表示しないようにしており、良い設計です。

test/models/user_study_streak_test.rb (1)

1-85: LGTM! 包括的なテストカバレッジです

UserStudyStreak モデルのテストとして優れた実装です:

  • 連続記録の期間計算、最長記録の判定(同率時は最新を選択)、学習日なしのケース、WIP日報の扱いなど、重要なシナリオが網羅されています
  • ReportHelper を活用したテストデータ作成により、テストの可読性と保守性が高まっています
  • private メソッド streak_periods への send() によるアクセスは、テストコンテキストでは許容される手法です
test/components/study_streak/user_study_streak_tracker_component_test.rb (1)

1-93: LGTM! ViewComponent の表示ロジックが十分にテストされています

StudyStreak::UserStudyStreakTrackerComponent のテストとして優れた実装です:

  • レンダリング結果の検証(現在の記録、最長記録、ゼロ状態)が適切に行われています
  • CSS クラス構造の検証により、スタイリングの安定性が担保されています
  • 日付フォーマットのテスト(当年・過去年・年跨ぎ)により、表示ロジックの正確性が確認されています
  • teardown での travel_back により、テスト間の時刻リークが防止されています

@jun-kondo jun-kondo force-pushed the feature/add-studying-streak-tracker-in-profile-page branch 2 times, most recently from 6abe43f to 21a4b8d Compare October 12, 2025 03:40
Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

📜 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 6abe43f and 21a4b8d.

📒 Files selected for processing (7)
  • app/components/study_streak/user_study_streak_tracker_component.html.slim (1 hunks)
  • app/components/study_streak/user_study_streak_tracker_component.rb (1 hunks)
  • app/controllers/home_controller.rb (1 hunks)
  • app/javascript/stylesheets/application/blocks/user/_user-study-streak-tracker.sass (1 hunks)
  • app/views/home/index.html.slim (1 hunks)
  • app/views/users/show.html.slim (2 hunks)
  • test/components/study_streak/user_study_streak_tracker_component_test.rb (1 hunks)
✅ Files skipped from review due to trivial changes (1)
  • app/components/study_streak/user_study_streak_tracker_component.html.slim
🚧 Files skipped from review as they are similar to previous changes (1)
  • app/views/home/index.html.slim
🧰 Additional context used
📓 Path-based instructions (2)
**/*.rb

⚙️ CodeRabbit configuration file

**/*.rb: # refactoring

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

Rails Patterns

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

Files:

  • app/controllers/home_controller.rb
  • app/components/study_streak/user_study_streak_tracker_component.rb
  • test/components/study_streak/user_study_streak_tracker_component_test.rb
test/**/*

⚙️ CodeRabbit configuration file

test/**/*: # Test

  • TestCase名は英語で書く。
  • どうしても避けられない時以外にsystem testでsleepは使わない。

Unit Test

model, helper, decorator, view_componentについてはメソッドを追加した場合は必ず対応したUnit TestのTestCaseを1つは書く。

Files:

  • test/components/study_streak/user_study_streak_tracker_component_test.rb
🧬 Code graph analysis (2)
app/controllers/home_controller.rb (1)
app/models/user.rb (1)
  • reports_with_learning_times (929-931)
test/components/study_streak/user_study_streak_tracker_component_test.rb (3)
test/models/user_study_streak_test.rb (1)
  • include (6-85)
test/supports/report_helper.rb (1)
  • create_report_data_with_learning_times (48-58)
app/models/user.rb (1)
  • reports_with_learning_times (929-931)
⏰ 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

@jun-kondo
Copy link
Copy Markdown
Contributor Author

@smallmonkeykey
お疲れ様です🍵
お手隙の際にレビューお願い致します🙇‍♂️

@smallmonkeykey
Copy link
Copy Markdown
Contributor

@jun-kondo
承知しました!
1週間ほどお時間いただいてよろしいですか?🙇‍♂️

@jun-kondo
Copy link
Copy Markdown
Contributor Author

@smallmonkeykey
ありがとうございます🙏

1週間ほどお時間いただいてよろしいですか?🙇‍♂️

了解しましたー。何卒よろしくお願いいたします🙇‍♂️
新機能なので、わからないことあれば気軽にきいてください🙋‍♂️

@machida machida removed their assignment Oct 16, 2025
@smallmonkeykey
Copy link
Copy Markdown
Contributor

@jun-kondo
新機能開発お疲れさまです!!
クラスもとても読みやすくて、知らないRubyのメソッドもいっぱい知れて感謝です🙏
ありがとうございます〜🙏

一点、動作確認の際に気になったのですが、日報を作成したときに画像のエラーが出るようでした。
Userモデルにsad_streakカラムがない状態で、sad_streak=メソッドを呼んでいるのが原因のようです。
一度mainブランチを rebaseしていただければ、
sad_streak関連の変更が解消され、エラーが解消するかと思います🙏
ご確認よろしくお願いします。
image

@jun-kondo jun-kondo requested a review from komagata December 8, 2025 11:27
@jun-kondo
Copy link
Copy Markdown
Contributor Author

@komagata
お疲れ様です🍵
テスト修正ありがとうございます🙇‍♂️
前回コメントいただいた箇所を修正してコメント返信致しました。ご確認よろしくお願い致します🙇‍♂️

- 日報を学習時間で関連付けて取得
- 昇順でソートされたユニークな結果を返す
- UserStudyStreakインスタンスを作成し@study_streakに設定
- reports_with_learning_timesメソッドを使用
- 学習時間データを含む日報を作成するヘルパーメソッドを追加しテストで使用する
- user-study-streak-tracker用のSassファイルを新規作成し、スタイルを定義
- application.sassにインポートを追加
@jun-kondo jun-kondo force-pushed the feature/add-studying-streak-tracker-in-profile-page branch from 9cdc059 to 19cc1ba Compare December 12, 2025 19:23
Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (1)
app/controllers/home_controller.rb (1)

38-54: @study_streak 初期化は表示条件に合わせてガードしたい(無駄クエリ/負荷)

Line 53 は常に current_user.reports_with_learning_times(JOIN + DISTINCT + ORDER)を発行するので、ダッシュボード側でストリークを表示しないユーザー(例: メンター/管理者/学習時間0)でもコストが発生します。表示条件がビュー側にある前提なら、コントローラ側も同条件で包む(または遅延初期化)方が安全です。

 def display_dashboard
   ...
-  @study_streak = StudyStreak.new(current_user.reports_with_learning_times, include_wip: false)
+  if current_user.student_or_trainee? && current_user.total_learning_time.positive?
+    @study_streak = StudyStreak.new(current_user.reports_with_learning_times, include_wip: false)
+  end
 end
📜 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 9cdc059 and 19cc1ba.

📒 Files selected for processing (10)
  • app/components/study_streak/study_streak_tracker_component.html.slim (1 hunks)
  • app/components/study_streak/study_streak_tracker_component.rb (1 hunks)
  • app/controllers/home_controller.rb (1 hunks)
  • app/controllers/users_controller.rb (1 hunks)
  • app/javascript/stylesheets/application.sass (1 hunks)
  • app/javascript/stylesheets/application/blocks/user/_user-study-streak-tracker.sass (1 hunks)
  • app/models/study_streak.rb (1 hunks)
  • app/models/user.rb (1 hunks)
  • app/views/home/index.html.slim (1 hunks)
  • app/views/users/show.html.slim (2 hunks)
🚧 Files skipped from review as they are similar to previous changes (8)
  • app/models/user.rb
  • app/javascript/stylesheets/application.sass
  • app/components/study_streak/study_streak_tracker_component.html.slim
  • app/controllers/users_controller.rb
  • app/components/study_streak/study_streak_tracker_component.rb
  • app/javascript/stylesheets/application/blocks/user/_user-study-streak-tracker.sass
  • app/models/study_streak.rb
  • app/views/home/index.html.slim
🧰 Additional context used
📓 Path-based instructions (3)
app/**/*.{rb,js,ts,jsx,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

Rails app code should be organized in app/ directory with subdirectories: models/, controllers/, views/, jobs/, helpers/, and frontend code under javascript/ (Shakapacker)

Files:

  • app/controllers/home_controller.rb
**/*.rb

📄 CodeRabbit inference engine (AGENTS.md)

Ruby code should use 2-space indentation, snake_case for method names, and CamelCase for class names, enforced by RuboCop (.rubocop.yml)

Files:

  • app/controllers/home_controller.rb

⚙️ CodeRabbit configuration file

**/*.rb: # refactoring

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

Rails Patterns

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

Files:

  • app/controllers/home_controller.rb
**/*.slim

📄 CodeRabbit inference engine (AGENTS.md)

Slim templates should be linted according to config/slim_lint.yml

Files:

  • app/views/users/show.html.slim
🧠 Learnings (4)
📚 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/views/users/show.html.slim
📚 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/views/users/show.html.slim
📚 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/views/users/show.html.slim
📚 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/views/users/show.html.slim
🧬 Code graph analysis (1)
app/controllers/home_controller.rb (1)
app/models/user.rb (1)
  • reports_with_learning_times (956-958)
🔇 Additional comments (1)
app/views/users/show.html.slim (1)

67-68: 削除推奨:@study_streakは正しく@userベースで初期化されており、懸念は根拠がありません

UsersController#showではreports = @user.reports_with_learning_timesとして明示的に@userのレポートから初期化され、その直後に@study_streak = StudyStreak.new(reports, include_wip: false)として設定されています。加えて、StudyStreak::StudyStreakTrackerComponentは.to_i.positive?.blank?による防御的なチェックを備えており、nil値に対して安全に処理されます。変数のスコープと初期化の流れは正確で、別ユーザーのデータが混入するリスクはありません。

Likely an incorrect or invalid review comment.

@jun-kondo jun-kondo force-pushed the feature/add-studying-streak-tracker-in-profile-page branch from 19cc1ba to 03aa758 Compare December 12, 2025 20:16
Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

♻️ Duplicate comments (1)
app/views/users/show.html.slim (1)

101-107: career_path が nil/空のときに MissingTranslation になり得ます(ガード or default を追加してください)

過去コメントと同様、t("activerecord.enums.user.career_path.#{@user.career_path}")@user.career_path が未設定だとコケやすいです。default:present? ガードを入れるのが安全です。

-                    | (#{t("activerecord.enums.user.career_path.#{@user.career_path}")})
+                    - career_path_key = @user.career_path.presence && "activerecord.enums.user.career_path.#{@user.career_path}"
+                    | (#{career_path_key ? t(career_path_key) : '未設定'})
🧹 Nitpick comments (2)
test/models/study_streak_test.rb (1)

31-41: send(:streak_periods) 依存は将来のリファクタで壊れやすいので、可能なら公開API経由に寄せたいです

内部実装変更に引きずられやすいので、もし StudyStreak 側に期間一覧を返す読み取り専用の public メソッドを用意できるなら、そこ経由での検証にすると安定します(将来的な話でOK)。

test/components/study_streak/study_streak_tracker_component_test.rb (1)

72-95: travel_to の入れ子が増えると読みづらくなるので、ブロック形式に寄せるのも手です

現状でも teardown があるので壊れませんが、読みやすさ重視ならこの形も検討できます。

-  test 'date format follows "yyyy/mm/dd 〜 yyyy/mm/dd" pattern for a past year' do
-    travel_to Time.zone.local(2025, 1, 1)
-    render_inline(StudyStreak::StudyStreakTrackerComponent.new(study_streak: @study_streak))
-    assert_selector '.streak-item__period', text: '2024/08/20 〜 2024/08/22'
-  end
+  test 'date format follows "yyyy/mm/dd 〜 yyyy/mm/dd" pattern for a past year' do
+    travel_to Time.zone.local(2025, 1, 1) do
+      render_inline(StudyStreak::StudyStreakTrackerComponent.new(study_streak: @study_streak))
+      assert_selector '.streak-item__period', text: '2024/08/20 〜 2024/08/22'
+    end
+  end
📜 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 19cc1ba and 03aa758.

📒 Files selected for processing (10)
  • app/components/study_streak/study_streak_tracker_component.html.slim (1 hunks)
  • app/components/study_streak/study_streak_tracker_component.rb (1 hunks)
  • app/controllers/home_controller.rb (1 hunks)
  • app/controllers/users_controller.rb (1 hunks)
  • app/javascript/stylesheets/application/blocks/user/_user-study-streak-tracker.sass (1 hunks)
  • app/models/study_streak.rb (1 hunks)
  • app/views/home/index.html.slim (1 hunks)
  • app/views/users/show.html.slim (2 hunks)
  • test/components/study_streak/study_streak_tracker_component_test.rb (1 hunks)
  • test/models/study_streak_test.rb (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (5)
  • app/controllers/home_controller.rb
  • app/views/home/index.html.slim
  • app/models/study_streak.rb
  • app/controllers/users_controller.rb
  • app/javascript/stylesheets/application/blocks/user/_user-study-streak-tracker.sass
🧰 Additional context used
📓 Path-based instructions (6)
app/**/*.{rb,js,ts,jsx,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

Rails app code should be organized in app/ directory with subdirectories: models/, controllers/, views/, jobs/, helpers/, and frontend code under javascript/ (Shakapacker)

Files:

  • app/components/study_streak/study_streak_tracker_component.rb
**/*.rb

📄 CodeRabbit inference engine (AGENTS.md)

Ruby code should use 2-space indentation, snake_case for method names, and CamelCase for class names, enforced by RuboCop (.rubocop.yml)

Files:

  • app/components/study_streak/study_streak_tracker_component.rb
  • test/models/study_streak_test.rb
  • test/components/study_streak/study_streak_tracker_component_test.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/components/study_streak/study_streak_tracker_component.rb
  • test/models/study_streak_test.rb
  • test/components/study_streak/study_streak_tracker_component_test.rb
**/*.slim

📄 CodeRabbit inference engine (AGENTS.md)

Slim templates should be linted according to config/slim_lint.yml

Files:

  • app/views/users/show.html.slim
  • app/components/study_streak/study_streak_tracker_component.html.slim
test/**/*_test.rb

📄 CodeRabbit inference engine (AGENTS.md)

test/**/*_test.rb: Test suite should use Minitest with structure: system/, models/, controllers/, and fixtures in test/fixtures/; test files should be named *_test.rb
Use Minitest + Capybara for system tests; place unit and integration tests under matching test/* directories

Files:

  • test/models/study_streak_test.rb
  • test/components/study_streak/study_streak_tracker_component_test.rb
test/**

📄 CodeRabbit inference engine (AGENTS.md)

Keep tests deterministic and use fixtures stored in test/fixtures/ for test data

Files:

  • test/models/study_streak_test.rb
  • test/components/study_streak/study_streak_tracker_component_test.rb
test/**/*

⚙️ CodeRabbit configuration file

test/**/*: # Test

  • TestCase名は英語で書く。
  • どうしても避けられない時以外にsystem testでsleepは使わない。

Unit Test

model, helper, decorator, view_componentについてはメソッドを追加した場合は必ず対応したUnit TestのTestCaseを1つは書く。

Files:

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

Applied to files:

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

Applied to files:

  • app/components/study_streak/study_streak_tracker_component.rb
  • test/components/study_streak/study_streak_tracker_component_test.rb
📚 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/views/users/show.html.slim
📚 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/views/users/show.html.slim
📚 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/views/users/show.html.slim
📚 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/views/users/show.html.slim
📚 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/views/users/show.html.slim
📚 Learning: 2025-11-26T08:23:30.927Z
Learnt from: CR
Repo: fjordllc/bootcamp PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-11-26T08:23:30.927Z
Learning: Applies to test/**/*_test.rb : Test suite should use Minitest with structure: `system/`, `models/`, `controllers/`, and fixtures in `test/fixtures/`; test files should be named `*_test.rb`

Applied to files:

  • test/models/study_streak_test.rb
  • test/components/study_streak/study_streak_tracker_component_test.rb
📚 Learning: 2025-11-26T08:23:30.927Z
Learnt from: CR
Repo: fjordllc/bootcamp PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-11-26T08:23:30.927Z
Learning: Applies to test/**/*_test.rb : Use Minitest + Capybara for system tests; place unit and integration tests under matching `test/*` directories

Applied to files:

  • test/models/study_streak_test.rb
  • test/components/study_streak/study_streak_tracker_component_test.rb
📚 Learning: 2025-11-26T08:23:30.927Z
Learnt from: CR
Repo: fjordllc/bootcamp PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-11-26T08:23:30.927Z
Learning: Applies to test/** : Keep tests deterministic and use fixtures stored in `test/fixtures/` for test data

Applied to files:

  • test/components/study_streak/study_streak_tracker_component_test.rb
🧬 Code graph analysis (3)
app/components/study_streak/study_streak_tracker_component.rb (1)
app/models/study_streak.rb (1)
  • initialize (6-19)
test/models/study_streak_test.rb (2)
test/supports/report_helper.rb (1)
  • create_report_data_with_learning_times (86-96)
app/models/user.rb (1)
  • reports_with_learning_times (956-958)
test/components/study_streak/study_streak_tracker_component_test.rb (2)
test/supports/report_helper.rb (1)
  • create_report_data_with_learning_times (86-96)
app/models/user.rb (1)
  • reports_with_learning_times (956-958)
⏰ 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 (6)
app/components/study_streak/study_streak_tracker_component.html.slim (1)

1-31: テンプレート構造は分かりやすく、条件付き表示も適切です

current_streak? / longest_streak? で期間要素を出し分けていて、0日のときに余計な表示が出ない構造になっていて良いです。文言の日本語ハードコードも本プロジェクト方針に沿っています(learningsより)。

test/models/study_streak_test.rb (1)

9-29: テストデータの掃除と生成が明確で、決定的になっています

reported_on を固定して delete_all→生成 の流れが読みやすく、意図が伝わります。

test/components/study_streak/study_streak_tracker_component_test.rb (1)

9-29: time travel の後始末が teardown で担保されていて安心です

app/components/study_streak/study_streak_tracker_component.rb (2)

8-38: コンポーネントの公開APIが薄くまとまっていて良いです

View からの参照メソッドが明示されていて、to_i で表示を安定させている点も良いです。


42-51: :sm / :short の I18n フォーマット定義は config/locales/ja.yml に存在するため問題ありません

date.formats.sm'%m/%d')、date.formats.short'%Y/%m/%d')、time.formats.short'%Y/%m/%d %H:%M')が ja.yml で定義されており、アプリケーションのデフォルトロケールが :ja に設定されているため、このコードは例外を発生させることはありません。

app/views/users/show.html.slim (1)

67-68: コントローラ側で確認したところ、UsersController#showの第49行で@study_streakは条件に関わらず常に初期化されているため、ビューでの使用は安全です。このレビュー指摘は不要です。

@jun-kondo
Copy link
Copy Markdown
Contributor Author

@komagata
お疲れ様です🍵
テスト修正ありがとうございます🙇‍♂️
前回コメントいただいた箇所を修正してコメント返信致しました。ご確認よろしくお願い致します🙇‍♂️

Comment on lines +26 to +28
teardown do
travel_back
end
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

teardownは最後の処理なので、setupの次に書くか、ファイルの最後に書くのがわかりやすいとおもいます。(他のテストもほとんどそうなっているとおもいます)

Copy link
Copy Markdown
Contributor Author

@jun-kondo jun-kondo Dec 17, 2025

Choose a reason for hiding this comment

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

すみません。setupのブロックが長くなっていて分かり辛いのですが、このテストファイルではsetupの次にteardownを書いています。
他のファイル(例えばtest/system/announcements/notification_test.rb)でも同様にsetupの次に書かれていて、そのような書き方に揃えたつもりなのですが...

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

@jun-kondo すみません、読み間違っていました。

Copy link
Copy Markdown
Member

@komagata komagata left a comment

Choose a reason for hiding this comment

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

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

Comment on lines +26 to +28
teardown do
travel_back
end
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

@jun-kondo すみません、読み間違っていました。

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.

4 participants