백로그
0할 일
0진행 중
0리뷰
0완료 (전체)
2세션 통계 - show 페이지 오늘 현황 카드 + stats 액션 + 테스트
## 목표 QT 세션 show 페이지에 오늘 현황 통계 카드를 추가하고, 별도 stats 액션도 구현 ## 구현 항목 ### 1. Qt::SessionsController show 액션 수정 - 파일: `app/controllers/qt/sessions_controller.rb` - `show` 액션에서 오늘 통계 계산 추가: ```ruby def show # 기존 코드 유지 @session = current_user_sessions.find(params[:id]) @participants = @session.qt_participants.includes(:user).where(is_active: true) # 오늘 통계 추가 theme = @session.qt_theme today = Date.current participant_user_ids = @participants.pluck(:user_id) today_meditations = UserMeditation.joins(:qt_content) .where(qt_contents: { qt_theme_id: theme.id }) .where(meditation_date: today) .where(user_id: participant_user_ids) @today_stats = { total_participants: @participants.count, tongtok_completed: today_meditations.where(is_tongtok_completed: true).count, qt_completed: today_meditations.where.not(personal_meditation: [nil, ""]).count } end ``` ### 2. show.html.erb 뷰 수정 - 파일: `app/views/qt/sessions/show.html.erb` - 기존 세션 정보 카드 아래, 3개 버튼(공유묵상/멤버/랭킹) 위에 "오늘 현황" 카드 추가 - 디자인: - shared/_card 파셜 사용 - 3열 그리드: 참여자 | 통독 완료 | QT 완료 - 각 항목: 숫자 크게 + 라벨 작게 - Tailwind CSS 사용 - 예시: ```erb <%# 오늘 현황 %> <%= render "shared/card" do %> <h3 class="font-semibold text-gray-900 mb-3">오늘 현황</h3> <div class="grid grid-cols-3 gap-4 text-center"> <div> <p class="text-2xl font-bold text-blue-600"><%= @today_stats[:total_participants] %></p> <p class="text-xs text-gray-500">참여자</p> </div> <div> <p class="text-2xl font-bold text-green-600"><%= @today_stats[:tongtok_completed] %></p> <p class="text-xs text-gray-500">통독 완료</p> </div> <div> <p class="text-2xl font-bold text-purple-600"><%= @today_stats[:qt_completed] %></p> <p class="text-xs text-gray-500">QT 완료</p> </div> </div> <% end %> ``` ### 3. 테스트 - 파일: `test/controllers/qt/sessions_controller_test.rb` - 기존 테스트에 추가: ```ruby test "show displays today stats" do sign_in users(:daniel) get qt_session_path(qt_sessions(:active_session)) assert_response :success assert_select ".grid-cols-3" # 오늘 현황 3열 그리드 end ``` ## 주의사항 - 기존 show 뷰의 구조를 깨지 않을 것 - shared 파셜의 strict locals 준수 (variant:, padding: 등) - UUID PK 사용 (ApplicationRecord의 set_uuid 자동 처리) - 전체 테스트 통과 확인: `bin/rails test` - `parallelize(workers: 1)` 테스트 설정 확인
기도 통계 + QT→기도제목 가져오기 - stats/import_from_qt 액션 + 뷰 + 테스트
## 목표 기도 통계 페이지와 QT에서 기도제목 가져오기 기능 구현 ## 구현 항목 ### 1. PrayersController에 stats 액션 추가 - 파일: `app/controllers/prayers_controller.rb` - `stats` 액션 추가: ```ruby def stats prayers = current_user.prayer_requests active_prayers = prayers.where(is_active: true) @prayer_stats = { total: prayers.count, active: active_prayers.count, by_response: { keep_praying: prayers.where(response_type: :keep_praying).count, waiting: prayers.where(response_type: :waiting).count, yes: prayers.where(response_type: :yes).count, no: prayers.where(response_type: :no).count }, answer_rate: calculate_answer_rate(prayers), by_category: { daily: prayers.where(category: :daily).count, weekly: prayers.where(category: :weekly).count }, recent_30days_check_rate: calculate_check_rate(current_user), total_checks: current_user.prayer_check_logs.count } end private def calculate_answer_rate(prayers) total = prayers.count return 0 if total.zero? answered = prayers.where(response_type: [:yes, :no, :waiting]).count (answered * 100.0 / total).round(1) end def calculate_check_rate(user) total_days = 30 checked_days = user.prayer_check_logs .where(check_date: 30.days.ago.to_date..Date.current) .select(:check_date).distinct.count (checked_days * 100.0 / total_days).round(1) end ``` ### 2. PrayersController에 import_from_qt 액션 추가 - `import_from_qt` 액션 (POST): ```ruby def import_from_qt meditation = current_user.user_meditations.find(params[:meditation_id]) if meditation.prayer_topic.blank? redirect_to prayers_path, alert: "가져올 기도제목이 없습니다." return end @prayer = current_user.prayer_requests.build( content: meditation.prayer_topic, category: :daily, response_type: :keep_praying, visibility: :private, is_active: true, sort_order: (current_user.prayer_requests.maximum(:sort_order) || 0) + 1 ) if @prayer.save redirect_to prayers_path, notice: "QT 묵상에서 기도제목을 가져왔습니다." else redirect_to prayers_path, alert: "기도제목 저장에 실패했습니다." end end ``` ### 3. 라우트 수정 - 파일: `config/routes.rb` - 기존 prayers 리소스에 collection 라우트 추가: ```ruby resources :prayers do collection do get :stats post :import_from_qt end # 기존 member 라우트 유지 member do post :check end end ``` - **주의**: 기존 prayers 라우트 구조를 잘 확인하고, 이미 member do ... end가 있으면 그 안에 추가하지 말고 collection do ... end를 별도로 추가 ### 4. 기도 통계 뷰 - 파일: `app/views/prayers/stats.html.erb` (신규) - 디자인: - 상단: 뒤로가기 + "기도 통계" 제목 - 카드 1: 전체 통계 (총 기도수, 활성, 응답률) - 카드 2: 응답 현황 (keep_praying/waiting/yes/no 각각 개수 + 비율) - 카드 3: 카테고리별 (매일/주간) - 카드 4: 기도 실천 (최근 30일 이행률 + 총 체크 수) - shared 파셜 활용: _card, _badge, _progress, _separator ### 5. prayers/index.html.erb 수정 - 기존 index 상단에 "통계 보기" 링크 버튼 추가 ```erb <%= link_to "통계", stats_prayers_path, class: "..." %> ``` ### 6. QT→기도제목 가져오기 UI - UserMeditation의 prayer_topic이 있는 묵상에서 "기도 목록에 추가" 버튼 표시 - 파일: `app/views/qt/_meditation_form.html.erb` 또는 묵상 상세 페이지 - **주의**: 묵상 뷰 파일을 먼저 확인하고, prayer_topic 필드가 어디서 표시되는지 파악한 후 적절한 위치에 버튼 추가 - 버튼은 `button_to import_from_qt_prayers_path(meditation_id: meditation.id), method: :post` 사용 ### 7. 테스트 - 파일: `test/controllers/prayers_controller_test.rb`에 추가 - stats 테스트: ```ruby test "stats shows prayer statistics" do sign_in users(:daniel) get stats_prayers_path assert_response :success end test "stats requires authentication" do get stats_prayers_path assert_redirected_to new_user_session_path end ``` - import_from_qt 테스트: ```ruby test "import_from_qt creates prayer from meditation" do sign_in users(:daniel) meditation = user_meditations(:completed_meditation) # prayer_topic이 있는 fixture assert_difference "PrayerRequest.count", 1 do post import_from_qt_prayers_path, params: { meditation_id: meditation.id } end assert_redirected_to prayers_path end test "import_from_qt rejects blank prayer_topic" do sign_in users(:daniel) meditation = user_meditations(:minimal_meditation) # prayer_topic이 없는 fixture assert_no_difference "PrayerRequest.count" do post import_from_qt_prayers_path, params: { meditation_id: meditation.id } end assert_redirected_to prayers_path end ``` ## 기존 코드 참고 - PrayerRequest 모델: category(daily/weekly), response_type(keep_praying/waiting/yes/no), visibility(private/partners/qt_plan/partners_qt_plan) - PrayerCheckLog: [user_id, prayer_request_id, check_date] 유니크 - UserMeditation: prayer_topic 컬럼 존재 - prayers/index.html.erb: 기존 목록 뷰 확인 후 통계 링크 추가 ## 주의사항 - 기존 prayers 테스트가 깨지지 않게 주의 - fixture 날짜는 과거 고정 날짜 사용 (Date.current 충돌 방지) - shared 파셜의 strict locals 준수 - ERB 멀티라인 주석 사용 금지 (각 줄 단일 라인 주석) - 전체 테스트 통과 확인: `bin/rails test` - `parallelize(workers: 1)` 테스트 설정 확인 - UUID PK 사용