From efe9f6499dcef0b19ff61afc9f981670c378de4f Mon Sep 17 00:00:00 2001 From: djkazunoko Date: Mon, 4 May 2026 23:22:35 +0900 Subject: [PATCH 01/13] =?UTF-8?q?=E6=97=A2=E5=AD=98=E3=82=AB=E3=83=86?= =?UTF-8?q?=E3=82=B4=E3=83=AA=E3=81=AE=E7=B5=A6=E4=BB=98=E9=87=91=E3=82=B3?= =?UTF-8?q?=E3=83=BC=E3=82=B9=E3=81=B8=E3=81=AE=E7=B4=90=E3=81=A5=E3=81=91?= =?UTF-8?q?=E3=82=92=E5=89=8A=E9=99=A4(=E6=9C=AC=E7=95=AA=E7=92=B0?= =?UTF-8?q?=E5=A2=83=E3=81=A8=E7=B5=B1=E4=B8=80=E3=81=99=E3=82=8B=E3=81=9F?= =?UTF-8?q?=E3=82=81)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 本番環境ではlib/tasks/bootcamp.rakeのcopy_practicesタスクにより新たなカテゴリが作成され、作成されたカテゴリが給付金コースに紐づけられる。 他のコースに紐づいている既存カテゴリを給付金コースに紐付けることをやめて、新たに作成したカテゴリを給付金コースに紐づけることで本番環境と統一した。 --- db/fixtures/courses_categories.yml | 94 +----------------------------- 1 file changed, 2 insertions(+), 92 deletions(-) diff --git a/db/fixtures/courses_categories.yml b/db/fixtures/courses_categories.yml index 6f3b3313df3..f782760b558 100644 --- a/db/fixtures/courses_categories.yml +++ b/db/fixtures/courses_categories.yml @@ -135,100 +135,10 @@ courses_category27: courses_category28: course: course5 - category: category1 + category: category24 position: 1 courses_category29: - course: course5 - category: category2 - position: 2 - -courses_category30: - course: course5 - category: category3 - position: 3 - -courses_category31: - course: course5 - category: category4 - position: 4 - -courses_category32: - course: course5 - category: category5 - position: 5 - -courses_category33: - course: course5 - category: category6 - position: 6 - -courses_category34: - course: course5 - category: category7 - position: 7 - -courses_category35: - course: course5 - category: category8 - position: 8 - -courses_category36: - course: course5 - category: category9 - position: 9 - -courses_category37: - course: course5 - category: category10 - position: 10 - -courses_category38: - course: course5 - category: category11 - position: 11 - -courses_category39: - course: course5 - category: category12 - position: 12 - -courses_category40: - course: course5 - category: category13 - position: 13 - -courses_category41: - course: course5 - category: category14 - position: 14 - -courses_category42: - course: course5 - category: category15 - position: 15 - -courses_category43: - course: course5 - category: category16 - position: 16 - -courses_category44: - course: course5 - category: category22 - position: 17 - -courses_category45: - course: course5 - category: category23 - position: 18 - -courses_category46: - course: course5 - category: category24 - position: 19 - -courses_category47: course: course5 category: category25 - position: 20 + position: 2 From c8c21b4bc9f92fc15aaa29261fe52045ccc190f4 Mon Sep 17 00:00:00 2001 From: djkazunoko Date: Mon, 4 May 2026 23:27:09 +0900 Subject: [PATCH 02/13] =?UTF-8?q?=E4=B8=8D=E8=A6=81=E3=81=AA=E3=83=97?= =?UTF-8?q?=E3=83=A9=E3=82=AF=E3=83=86=E3=82=A3=E3=82=B9=E3=82=92=E5=89=8A?= =?UTF-8?q?=E9=99=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- db/fixtures/categories_practices.yml | 9 ++------- db/fixtures/practices.yml | 8 +------- 2 files changed, 3 insertions(+), 14 deletions(-) diff --git a/db/fixtures/categories_practices.yml b/db/fixtures/categories_practices.yml index dcfedcee5a9..2b1482f5c2d 100644 --- a/db/fixtures/categories_practices.yml +++ b/db/fixtures/categories_practices.yml @@ -362,17 +362,12 @@ categories_practice67: category: category24 position: 16 -categories_practice68: - practice: practice114 - category: category24 - position: 17 - categories_practice69: - practice: practice115 + practice: practice114 category: category25 position: 1 categories_practice70: - practice: practice116 + practice: practice115 category: category25 position: 2 diff --git a/db/fixtures/practices.yml b/db/fixtures/practices.yml index f33cfd19470..2ee1a04547d 100644 --- a/db/fixtures/practices.yml +++ b/db/fixtures/practices.yml @@ -772,18 +772,12 @@ practice113: source_practice: practice23 practice114: - title: "rbenvをインストールする(Reスキル)" - description: "Railsコースのプラクティスをコピーした給付金コースのプラクティスです。" - goal: "goal..." - source_practice: practice24 - -practice115: title: "OS X Mountain Lionをクリーンインストールする(Reスキル)" description: "Railsコースのプラクティスをコピーしたプラクティスです。" goal: "goal..." source_id: <%= ActiveRecord::FixtureSet.identify(:practice1) %> -practice116: +practice115: title: "Terminalの基礎を覚える(Reスキル)" description: "Railsコースのプラクティスをコピーしたプラクティスです。" goal: "goal..." From 87a6ec1c55c8b36c1cd706f5eae3d572db2a0172 Mon Sep 17 00:00:00 2001 From: djkazunoko Date: Mon, 4 May 2026 23:29:29 +0900 Subject: [PATCH 03/13] =?UTF-8?q?categories=5Fpractices.yml=E3=81=AEfixtur?= =?UTF-8?q?e=E5=90=8D=E3=82=92=E9=80=9A=E3=81=97=E7=95=AA=E5=8F=B7?= =?UTF-8?q?=E3=81=AB=E7=B5=B1=E4=B8=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 通し番号の方がfixture名の規則が分かりやすく、追加時にも連番で管理しやすいため。 --- db/fixtures/categories_practices.yml | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/db/fixtures/categories_practices.yml b/db/fixtures/categories_practices.yml index 2b1482f5c2d..dfcd7d7896a 100644 --- a/db/fixtures/categories_practices.yml +++ b/db/fixtures/categories_practices.yml @@ -317,57 +317,57 @@ categories_practice64: practice: practice64 category: category10 -categories_practice111_1: +categories_practice65: practice: practice111 category: category6 position: 14 -categories_practice111_2: +categories_practice66: practice: practice111 category: category23 position: 2 -categories_practice112_1: +categories_practice67: practice: practice112 category: category6 position: 15 -categories_practice112_2: +categories_practice68: practice: practice112 category: category23 position: 3 -categories_practice65_1: +categories_practice69: practice: practice65 category: category6 position: 14 -categories_practice65_2: +categories_practice70: practice: practice65 category: category22 position: 2 -categories_practice66_1: +categories_practice71: practice: practice66 category: category6 position: 15 -categories_practice66_2: +categories_practice72: practice: practice66 category: category22 position: 3 -categories_practice67: +categories_practice73: practice: practice113 category: category24 position: 16 -categories_practice69: +categories_practice74: practice: practice114 category: category25 position: 1 -categories_practice70: +categories_practice75: practice: practice115 category: category25 position: 2 From 8bc10890999d14e547d8e13105a10d165b183cab Mon Sep 17 00:00:00 2001 From: djkazunoko Date: Sat, 9 May 2026 15:13:20 +0900 Subject: [PATCH 04/13] =?UTF-8?q?=E7=B5=A6=E4=BB=98=E9=87=91=E3=82=B3?= =?UTF-8?q?=E3=83=BC=E3=82=B9=E3=81=AE=E3=83=97=E3=83=A9=E3=82=AF=E3=83=86?= =?UTF-8?q?=E3=82=A3=E3=82=B9=E3=81=A8=E5=85=83=E3=82=B3=E3=83=BC=E3=82=B9?= =?UTF-8?q?=E3=81=AE=E3=83=97=E3=83=A9=E3=82=AF=E3=83=86=E3=82=A3=E3=82=B9?= =?UTF-8?q?=E3=81=AE=E8=B3=AA=E5=95=8F=E3=82=92=E8=BF=BD=E5=8A=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- db/fixtures/correct_answers.yml | 12 ++++++++++++ db/fixtures/questions.yml | 32 ++++++++++++++++++++++++++++++++ 2 files changed, 44 insertions(+) diff --git a/db/fixtures/correct_answers.yml b/db/fixtures/correct_answers.yml index eb314f039d2..46d7c4baf51 100644 --- a/db/fixtures/correct_answers.yml +++ b/db/fixtures/correct_answers.yml @@ -15,3 +15,15 @@ correct_answer3: user: machida question: question1 type: "CorrectAnswer" + +correct_answer4: + description: ベストアンサーです。 + user: machida + question: question57 + type: "CorrectAnswer" + +correct_answer5: + description: ベストアンサーです。 + user: machida + question: question59 + type: "CorrectAnswer" diff --git a/db/fixtures/questions.yml b/db/fixtures/questions.yml index 0a3b8e44a5a..44972b730b1 100644 --- a/db/fixtures/questions.yml +++ b/db/fixtures/questions.yml @@ -160,3 +160,35 @@ question55: created_at: <%= Time.current - 3.month %> updated_at: <%= Time.current - 3.month %> published_at: <%= Time.current - 3.month %> + +question56: + title: 給付金コースのプラクティスの質問 + description: 給付金コースのプラクティスの質問です。 + user: grant-course + practice: practice113 + created_at: "2026-05-15" + published_at: "2026-05-15" + +question57: + title: 給付金コースのプラクティスの質問(解決済み) + description: 解決済みです。 + user: grant-course + practice: practice113 + created_at: "2026-05-15" + published_at: "2026-05-15" + +question58: + title: 給付金コースのコピー元プラクティスの質問 + description: 給付金コースのコピー元プラクティスの質問 + user: grant-course + practice: practice23 + created_at: "2026-05-15" + published_at: "2026-05-15" + +question59: + title: 給付金コースのコピー元プラクティスの質問(解決済み) + description: 解決済みです。 + user: grant-course + practice: practice23 + created_at: "2026-05-15" + published_at: "2026-05-15" From 9fc83cdd6266dc71e3b6f9c3bb7b1afa35668b8c Mon Sep 17 00:00:00 2001 From: djkazunoko Date: Sat, 9 May 2026 16:03:05 +0900 Subject: [PATCH 05/13] =?UTF-8?q?=E7=B5=A6=E4=BB=98=E9=87=91=E3=82=B3?= =?UTF-8?q?=E3=83=BC=E3=82=B9=E3=81=AE=E8=B3=AA=E5=95=8F=E4=B8=80=E8=A6=A7?= =?UTF-8?q?=E3=81=AB=E5=85=83=E3=82=B3=E3=83=BC=E3=82=B9=E3=81=AE=E8=B3=AA?= =?UTF-8?q?=E5=95=8F=E3=82=92=E8=A1=A8=E7=A4=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../practices/questions_controller.rb | 18 +++- app/views/practices/questions/index.html.slim | 16 +++- test/fixtures/correct_answers.yml | 12 +++ test/fixtures/questions.yml | 32 +++++++ test/system/practice/questions_test.rb | 91 +++++++++++++++++++ 5 files changed, 161 insertions(+), 8 deletions(-) diff --git a/app/controllers/practices/questions_controller.rb b/app/controllers/practices/questions_controller.rb index 2a5727d579c..e65c3619508 100644 --- a/app/controllers/practices/questions_controller.rb +++ b/app/controllers/practices/questions_controller.rb @@ -5,11 +5,19 @@ def index @practice = Practice.find(params[:practice_id]) allowed_targets = %w[solved not_solved].freeze target = allowed_targets.include?(params[:target]) ? params[:target] : nil - @questions = @practice.questions - .includes(%i[correct_answer answers]) - .by_target(target) - .order(created_at: :desc) - .page(params[:page]) + allowed_scopes = %w[grant_course].freeze + scope = allowed_scopes.include?(params[:scope]) ? params[:scope] : nil + practices = + if scope == 'grant_course' + @practice + else + [@practice, @practice.source_practice].compact + end + @questions = Question.where(practice: practices) + .includes(%i[correct_answer answers]) + .by_target(target) + .order(created_at: :desc) + .page(params[:page]) @empty_message = empty_message end diff --git a/app/views/practices/questions/index.html.slim b/app/views/practices/questions/index.html.slim index 29382f7f371..178d380b2ac 100644 --- a/app/views/practices/questions/index.html.slim +++ b/app/views/practices/questions/index.html.slim @@ -13,15 +13,25 @@ nav.tab-nav .container ul.tab-nav__items li.tab-nav__item - = link_to '全ての質問', practice_questions_path(@practice), + = link_to '全ての質問', practice_questions_path(@practice, scope: params[:scope]), class: "tab-nav__item-link #{%w[not_solved solved].include?(params[:target]) ? '' : 'is-active'}" li.tab-nav__item - = link_to '解決済み', practice_questions_path(@practice, target: 'solved'), + = link_to '解決済み', practice_questions_path(@practice, target: 'solved', scope: params[:scope]), class: "tab-nav__item-link #{params[:target] == 'solved' ? 'is-active' : ''}" li.tab-nav__item - = link_to '未解決', practice_questions_path(@practice, target: 'not_solved'), + = link_to '未解決', practice_questions_path(@practice, target: 'not_solved', scope: params[:scope]), class: "tab-nav__item-link #{params[:target] == 'not_solved' ? 'is-active' : ''}" +- if @practice.source_id.present? + nav.pill-nav + ul.pill-nav__items + li.pill-nav__item + = link_to '全て', practice_questions_path(@practice, target: params[:target]), + class: "pill-nav__item-link #{params[:scope] == 'grant_course' ? '' : 'is-active'}" + li.pill-nav__item + = link_to '給付金コース', practice_questions_path(@practice, target: params[:target], scope: 'grant_course'), + class: "pill-nav__item-link #{params[:scope] == 'grant_course' ? 'is-active' : ''}" + .page-body .container.is-md = render 'questions/questions', questions: @questions, empty_message: @empty_message diff --git a/test/fixtures/correct_answers.yml b/test/fixtures/correct_answers.yml index f7e809ac41e..cf18afa1f43 100644 --- a/test/fixtures/correct_answers.yml +++ b/test/fixtures/correct_answers.yml @@ -9,3 +9,15 @@ correct_answer2: user: advijirou question: question12 type: "CorrectAnswer" + +correct_answer3: + description: ベストアンサーです。 + user: machida + question: question18 + type: "CorrectAnswer" + +correct_answer4: + description: ベストアンサーです。 + user: machida + question: question20 + type: "CorrectAnswer" diff --git a/test/fixtures/questions.yml b/test/fixtures/questions.yml index b187b615930..1c559cd1112 100644 --- a/test/fixtures/questions.yml +++ b/test/fixtures/questions.yml @@ -143,3 +143,35 @@ question16: practice: practice1 created_at: "2022-01-18" published_at: "2022-01-18" + +question17: + title: 給付金コースのプラクティスの質問 + description: 給付金コースのプラクティスの質問です。 + user: grant-course + practice: practice64 + created_at: "2026-05-15" + published_at: "2026-05-15" + +question18: + title: 給付金コースのプラクティスの質問(解決済み) + description: 解決済みです。 + user: grant-course + practice: practice64 + created_at: "2026-05-15" + published_at: "2026-05-15" + +question19: + title: 給付金コースのコピー元プラクティスの質問 + description: 給付金コースのコピー元プラクティスの質問 + user: grant-course + practice: practice23 + created_at: "2026-05-15" + published_at: "2026-05-15" + +question20: + title: 給付金コースのコピー元プラクティスの質問(解決済み) + description: 解決済みです。 + user: grant-course + practice: practice23 + created_at: "2026-05-15" + published_at: "2026-05-15" diff --git a/test/system/practice/questions_test.rb b/test/system/practice/questions_test.rb index 07e235a1515..b4e914a6f6a 100644 --- a/test/system/practice/questions_test.rb +++ b/test/system/practice/questions_test.rb @@ -18,4 +18,95 @@ class Practice::QuestionsTest < ApplicationSystemTestCase assert_no_text 'wipテスト用の質問(wip中)' assert_selector('a.tab-nav__item-link.is-active', text: '未解決') end + + test 'show grant course filter tabs only for grant course practices' do + visit_with_auth "/practices/#{practices(:practice64).id}/questions", 'grant-course' + assert_selector '.pill-nav__item-link', exact_text: '全て' + assert_selector '.pill-nav__item-link', exact_text: '給付金コース' + + visit_with_auth "/practices/#{practices(:practice1).id}/questions", 'grant-course' + assert_no_selector '.pill-nav__item-link', exact_text: '全て' + assert_no_selector '.pill-nav__item-link', exact_text: '給付金コース' + end + + test 'show all questions from both grant and source practices when all filter is selected' do + visit_with_auth "/practices/#{practices(:practice64).id}/questions", 'grant-course' + assert_selector '.pill-nav__item-link.is-active', exact_text: '全て' + assert_selector '.tab-nav__item-link.is-active', exact_text: '全ての質問' + assert_selector '.card-list-item-title__link', exact_text: '給付金コースのプラクティスの質問' + assert_selector '.card-list-item-title__link', exact_text: '給付金コースのプラクティスの質問(解決済み)' + assert_selector '.card-list-item-title__link', exact_text: '給付金コースのコピー元プラクティスの質問' + assert_selector '.card-list-item-title__link', exact_text: '給付金コースのコピー元プラクティスの質問(解決済み)' + end + + test 'show solved questions from both grant and source practices when solved filter is selected' do + visit_with_auth "/practices/#{practices(:practice64).id}/questions", 'grant-course' + within '.tab-nav' do + click_on '解決済み' + end + assert_selector '.pill-nav__item-link.is-active', exact_text: '全て' + assert_selector '.tab-nav__item-link.is-active', exact_text: '解決済み' + assert_no_selector '.card-list-item-title__link', exact_text: '給付金コースのプラクティスの質問' + assert_selector '.card-list-item-title__link', exact_text: '給付金コースのプラクティスの質問(解決済み)' + assert_no_selector '.card-list-item-title__link', exact_text: '給付金コースのコピー元プラクティスの質問' + assert_selector '.card-list-item-title__link', exact_text: '給付金コースのコピー元プラクティスの質問(解決済み)' + end + + test 'show unsolved questions from both grant and source practices when unsolved filter is selected' do + visit_with_auth "/practices/#{practices(:practice64).id}/questions", 'grant-course' + within '.tab-nav' do + click_on '未解決' + end + assert_selector '.pill-nav__item-link.is-active', exact_text: '全て' + assert_selector '.tab-nav__item-link.is-active', exact_text: '未解決' + assert_selector '.card-list-item-title__link', exact_text: '給付金コースのプラクティスの質問' + assert_no_selector '.card-list-item-title__link', exact_text: '給付金コースのプラクティスの質問(解決済み)' + assert_selector '.card-list-item-title__link', exact_text: '給付金コースのコピー元プラクティスの質問' + assert_no_selector '.card-list-item-title__link', exact_text: '給付金コースのコピー元プラクティスの質問(解決済み)' + end + + test 'show all questions only from the grant practice when grant course scope is selected' do + visit_with_auth "/practices/#{practices(:practice64).id}/questions", 'grant-course' + within '.pill-nav' do + click_on '給付金コース' + end + assert_selector '.pill-nav__item-link.is-active', exact_text: '給付金コース' + assert_selector '.tab-nav__item-link.is-active', exact_text: '全ての質問' + assert_selector '.card-list-item-title__link', exact_text: '給付金コースのプラクティスの質問' + assert_selector '.card-list-item-title__link', exact_text: '給付金コースのプラクティスの質問(解決済み)' + assert_no_selector '.card-list-item-title__link', exact_text: '給付金コースのコピー元プラクティスの質問' + assert_no_selector '.card-list-item-title__link', exact_text: '給付金コースのコピー元プラクティスの質問(解決済み)' + end + + test 'show solved questions only from the grant practice when solved filter and grant course scope are selected' do + visit_with_auth "/practices/#{practices(:practice64).id}/questions", 'grant-course' + within '.pill-nav' do + click_on '給付金コース' + end + within '.tab-nav' do + click_on '解決済み' + end + assert_selector '.pill-nav__item-link.is-active', exact_text: '給付金コース' + assert_selector '.tab-nav__item-link.is-active', exact_text: '解決済み' + assert_no_selector '.card-list-item-title__link', exact_text: '給付金コースのプラクティスの質問' + assert_selector '.card-list-item-title__link', exact_text: '給付金コースのプラクティスの質問(解決済み)' + assert_no_selector '.card-list-item-title__link', exact_text: '給付金コースのコピー元プラクティスの質問' + assert_no_selector '.card-list-item-title__link', exact_text: '給付金コースのコピー元プラクティスの質問(解決済み)' + end + + test 'show unsolved questions only from the grant practice when unsolved filter and grant course scope are selected' do + visit_with_auth "/practices/#{practices(:practice64).id}/questions", 'grant-course' + within '.pill-nav' do + click_on '給付金コース' + end + within '.tab-nav' do + click_on '未解決' + end + assert_selector '.pill-nav__item-link.is-active', exact_text: '給付金コース' + assert_selector '.tab-nav__item-link.is-active', exact_text: '未解決' + assert_selector '.card-list-item-title__link', exact_text: '給付金コースのプラクティスの質問' + assert_no_selector '.card-list-item-title__link', exact_text: '給付金コースのプラクティスの質問(解決済み)' + assert_no_selector '.card-list-item-title__link', exact_text: '給付金コースのコピー元プラクティスの質問' + assert_no_selector '.card-list-item-title__link', exact_text: '給付金コースのコピー元プラクティスの質問(解決済み)' + end end From 9e4aff2f87732fc572daff73ade70c27ddcc149b Mon Sep 17 00:00:00 2001 From: djkazunoko Date: Sat, 16 May 2026 17:33:11 +0900 Subject: [PATCH 06/13] =?UTF-8?q?=E8=B3=AA=E5=95=8F=E3=82=BF=E3=83=96?= =?UTF-8?q?=E3=81=AE=E4=BB=B6=E6=95=B0=E8=A1=A8=E7=A4=BA=E3=82=92=E8=A1=A8?= =?UTF-8?q?=E7=A4=BA=E7=AF=84=E5=9B=B2=E3=81=AB=E5=BF=9C=E3=81=98=E3=81=A6?= =?UTF-8?q?=E5=A4=89=E6=9B=B4=E3=81=99=E3=82=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 「全て」では元コースを含む合算件数を表示 - 「給付金コース」では給付金コースのみの件数を表示 - 質問ページ以外では合算件数を表示 --- app/helpers/page_tabs/practices_helper.rb | 15 ++++++++++++++- test/system/practice/questions_test.rb | 18 ++++++++++++++++++ 2 files changed, 32 insertions(+), 1 deletion(-) diff --git a/app/helpers/page_tabs/practices_helper.rb b/app/helpers/page_tabs/practices_helper.rb index e1917e2f1ac..36e4a13c9ec 100644 --- a/app/helpers/page_tabs/practices_helper.rb +++ b/app/helpers/page_tabs/practices_helper.rb @@ -8,7 +8,7 @@ def practice_page_tabs(practice, active_tab:, include_source: nil) tabs = [] tabs << { name: 'プラクティス', link: practice_path(practice) } tabs << { name: '日報', link: practice_reports_path(practice), count: practice.reports_count(include_source:) } - tabs << { name: '質問', link: practice_questions_path(practice), count: practice.questions.length } + tabs << { name: '質問', link: practice_questions_path(practice), count: practice_questions_count(practice, active_tab:) } tabs << { name: 'Docs', link: practice_pages_path(practice), count: practice.pages.length } tabs << { name: '動画', link: practice_movies_path(practice), count: practice.movies.length } if movie_available? tabs << { name: '提出物', link: practice_products_path(practice) } if practice.submission @@ -16,5 +16,18 @@ def practice_page_tabs(practice, active_tab:, include_source: nil) tabs << { name: 'コーディングテスト', link: practice_coding_tests_path(practice) } if practice.coding_tests.present? render PageTabsComponent.new(tabs:, active_tab:) end + + private + + def practice_questions_count(practice, active_tab:) + practices = + if active_tab == '質問' && params[:scope] == 'grant_course' + [practice] + else + [practice, practice.source_practice].compact + end + + Question.where(practice: practices).count + end end end diff --git a/test/system/practice/questions_test.rb b/test/system/practice/questions_test.rb index b4e914a6f6a..ac191ffd4e3 100644 --- a/test/system/practice/questions_test.rb +++ b/test/system/practice/questions_test.rb @@ -109,4 +109,22 @@ class Practice::QuestionsTest < ApplicationSystemTestCase assert_no_selector '.card-list-item-title__link', exact_text: '給付金コースのコピー元プラクティスの質問' assert_no_selector '.card-list-item-title__link', exact_text: '給付金コースのコピー元プラクティスの質問(解決済み)' end + + test 'show total question count from grant and source practices when all scope is selected' do + visit_with_auth "/practices/#{practices(:practice64).id}/questions", 'grant-course' + assert_selector '.page-tabs__item-link.is-active', exact_text: '質問 (4)' + end + + test 'show question count from grant practice only when grant course scope is selected' do + visit_with_auth "/practices/#{practices(:practice64).id}/questions", 'grant-course' + within '.pill-nav' do + click_on '給付金コース' + end + assert_selector '.page-tabs__item-link.is-active', exact_text: '質問 (2)' + end + + test 'show total question count from grant and source practices on non-question pages' do + visit_with_auth "/practices/#{practices(:practice64).id}", 'grant-course' + assert_selector '.page-tabs__item-link', exact_text: '質問 (4)' + end end From 903ab4c78fcac96a8c22056a659f84635c74a5d4 Mon Sep 17 00:00:00 2001 From: djkazunoko Date: Sun, 17 May 2026 21:38:59 +0900 Subject: [PATCH 07/13] =?UTF-8?q?Practices::QuestionsController=E3=81=AEpa?= =?UTF-8?q?rams=E5=87=A6=E7=90=86=E3=82=92=E3=83=AA=E3=83=95=E3=82=A1?= =?UTF-8?q?=E3=82=AF=E3=82=BF=E3=83=AA=E3=83=B3=E3=82=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/controllers/practices/questions_controller.rb | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/app/controllers/practices/questions_controller.rb b/app/controllers/practices/questions_controller.rb index e65c3619508..01d8ad2b357 100644 --- a/app/controllers/practices/questions_controller.rb +++ b/app/controllers/practices/questions_controller.rb @@ -3,10 +3,6 @@ class Practices::QuestionsController < ApplicationController def index @practice = Practice.find(params[:practice_id]) - allowed_targets = %w[solved not_solved].freeze - target = allowed_targets.include?(params[:target]) ? params[:target] : nil - allowed_scopes = %w[grant_course].freeze - scope = allowed_scopes.include?(params[:scope]) ? params[:scope] : nil practices = if scope == 'grant_course' @practice @@ -33,4 +29,12 @@ def empty_message '質問はありません。' end end + + def target + params[:target] if %w[solved not_solved].include?(params[:target]) + end + + def scope + params[:scope] if %w[grant_course].include?(params[:scope]) + end end From b056b4f990cda6e94816d44ebdb120d5e541247b Mon Sep 17 00:00:00 2001 From: djkazunoko Date: Sun, 17 May 2026 23:04:03 +0900 Subject: [PATCH 08/13] =?UTF-8?q?=E3=83=9A=E3=83=BC=E3=82=B8=E3=82=BF?= =?UTF-8?q?=E3=83=96=E3=81=AE=E4=BB=B6=E6=95=B0=E5=8F=96=E5=BE=97=E3=82=92?= =?UTF-8?q?length=E3=81=8B=E3=82=89count=E3=81=AB=E5=A4=89=E6=9B=B4?= =?UTF-8?q?=E3=81=97=E3=81=A6=E4=B8=8D=E8=A6=81=E3=81=AA=E3=83=AD=E3=83=BC?= =?UTF-8?q?=E3=83=89=E3=82=92=E9=98=B2=E3=81=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit lengthでは SELECT * によりレコード全件をロードしていたが、countを使うことで SELECT COUNT(*) による件数取得のみに変更 --- app/helpers/page_tabs/practices_helper.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/helpers/page_tabs/practices_helper.rb b/app/helpers/page_tabs/practices_helper.rb index 36e4a13c9ec..bfcf4b203b0 100644 --- a/app/helpers/page_tabs/practices_helper.rb +++ b/app/helpers/page_tabs/practices_helper.rb @@ -9,8 +9,8 @@ def practice_page_tabs(practice, active_tab:, include_source: nil) tabs << { name: 'プラクティス', link: practice_path(practice) } tabs << { name: '日報', link: practice_reports_path(practice), count: practice.reports_count(include_source:) } tabs << { name: '質問', link: practice_questions_path(practice), count: practice_questions_count(practice, active_tab:) } - tabs << { name: 'Docs', link: practice_pages_path(practice), count: practice.pages.length } - tabs << { name: '動画', link: practice_movies_path(practice), count: practice.movies.length } if movie_available? + tabs << { name: 'Docs', link: practice_pages_path(practice), count: practice.pages.count } + tabs << { name: '動画', link: practice_movies_path(practice), count: practice.movies.count } if movie_available? tabs << { name: '提出物', link: practice_products_path(practice) } if practice.submission tabs << { name: '模範解答', link: practice_submission_answer_path(practice) } if practice.submission_answer.present? tabs << { name: 'コーディングテスト', link: practice_coding_tests_path(practice) } if practice.coding_tests.present? From 8c0b28303ba1bcaf47987ba117e51e2c2f0d6fe8 Mon Sep 17 00:00:00 2001 From: djkazunoko Date: Tue, 19 May 2026 22:58:52 +0900 Subject: [PATCH 09/13] =?UTF-8?q?category=E3=81=94=E3=81=A8=E3=81=AEpracti?= =?UTF-8?q?ce=E3=81=AEposition=E3=81=8C=E9=87=8D=E8=A4=87=E3=83=BB?= =?UTF-8?q?=E6=AC=A0=E7=95=AA=E3=83=BB=E4=B8=8D=E8=87=AA=E7=84=B6=E3=81=AA?= =?UTF-8?q?=E5=80=A4=E3=81=AB=E3=81=AA=E3=81=A3=E3=81=A6=E3=81=84=E3=81=9F?= =?UTF-8?q?=E3=81=9F=E3=82=81=E4=BF=AE=E6=AD=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- db/fixtures/categories_practices.yml | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/db/fixtures/categories_practices.yml b/db/fixtures/categories_practices.yml index dfcd7d7896a..7d89a2a7d77 100644 --- a/db/fixtures/categories_practices.yml +++ b/db/fixtures/categories_practices.yml @@ -316,6 +316,7 @@ categories_practice63: categories_practice64: practice: practice64 category: category10 + position: 3 categories_practice65: practice: practice111 @@ -340,7 +341,7 @@ categories_practice68: categories_practice69: practice: practice65 category: category6 - position: 14 + position: 16 categories_practice70: practice: practice65 @@ -350,7 +351,7 @@ categories_practice70: categories_practice71: practice: practice66 category: category6 - position: 15 + position: 17 categories_practice72: practice: practice66 @@ -360,7 +361,7 @@ categories_practice72: categories_practice73: practice: practice113 category: category24 - position: 16 + position: 1 categories_practice74: practice: practice114 From ae8b17e4803275e807b42041f2325f1e61198c1f Mon Sep 17 00:00:00 2001 From: djkazunoko Date: Tue, 7 Jul 2026 16:41:04 +0900 Subject: [PATCH 10/13] =?UTF-8?q?params=E3=81=8B=E3=82=89=E5=8F=96?= =?UTF-8?q?=E5=BE=97=E3=81=97=E3=81=9F=E5=80=A4=E3=82=92=E8=BF=94=E3=81=99?= =?UTF-8?q?=E3=81=93=E3=81=A8=E3=81=8C=E5=88=86=E3=81=8B=E3=82=8B=E3=83=A1?= =?UTF-8?q?=E3=82=BD=E3=83=83=E3=83=89=E5=90=8D=E3=81=AB=E5=A4=89=E6=9B=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/controllers/practices/questions_controller.rb | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/app/controllers/practices/questions_controller.rb b/app/controllers/practices/questions_controller.rb index 01d8ad2b357..e95cff634dd 100644 --- a/app/controllers/practices/questions_controller.rb +++ b/app/controllers/practices/questions_controller.rb @@ -4,14 +4,14 @@ class Practices::QuestionsController < ApplicationController def index @practice = Practice.find(params[:practice_id]) practices = - if scope == 'grant_course' + if selected_scope == 'grant_course' @practice else [@practice, @practice.source_practice].compact end @questions = Question.where(practice: practices) .includes(%i[correct_answer answers]) - .by_target(target) + .by_target(selected_target) .order(created_at: :desc) .page(params[:page]) @empty_message = empty_message @@ -30,11 +30,11 @@ def empty_message end end - def target + def selected_target params[:target] if %w[solved not_solved].include?(params[:target]) end - def scope + def selected_scope params[:scope] if %w[grant_course].include?(params[:scope]) end end From 711bcce3b5c3c187cf165ae50a9d883d4b6e5a12 Mon Sep 17 00:00:00 2001 From: djkazunoko Date: Tue, 7 Jul 2026 16:47:24 +0900 Subject: [PATCH 11/13] =?UTF-8?q?=E8=BF=94=E3=82=8A=E5=80=A4=E3=82=92?= =?UTF-8?q?=E9=85=8D=E5=88=97=E3=81=AB=E7=B5=B1=E4=B8=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/controllers/practices/questions_controller.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/controllers/practices/questions_controller.rb b/app/controllers/practices/questions_controller.rb index e95cff634dd..0928dc7dcf6 100644 --- a/app/controllers/practices/questions_controller.rb +++ b/app/controllers/practices/questions_controller.rb @@ -5,7 +5,7 @@ def index @practice = Practice.find(params[:practice_id]) practices = if selected_scope == 'grant_course' - @practice + [@practice] else [@practice, @practice.source_practice].compact end From 461aeb3abf7ce5d095112643bbc27fc461bd73d7 Mon Sep 17 00:00:00 2001 From: djkazunoko Date: Tue, 7 Jul 2026 16:49:10 +0900 Subject: [PATCH 12/13] =?UTF-8?q?question=5Fpractices=E3=83=A1=E3=82=BD?= =?UTF-8?q?=E3=83=83=E3=83=89=E3=81=AB=E5=88=87=E3=82=8A=E5=87=BA=E3=81=97?= =?UTF-8?q?=E3=81=A6=E5=87=A6=E7=90=86=E3=82=92=E6=95=B4=E7=90=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../practices/questions_controller.rb | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/app/controllers/practices/questions_controller.rb b/app/controllers/practices/questions_controller.rb index 0928dc7dcf6..27e9cf42be4 100644 --- a/app/controllers/practices/questions_controller.rb +++ b/app/controllers/practices/questions_controller.rb @@ -3,13 +3,7 @@ class Practices::QuestionsController < ApplicationController def index @practice = Practice.find(params[:practice_id]) - practices = - if selected_scope == 'grant_course' - [@practice] - else - [@practice, @practice.source_practice].compact - end - @questions = Question.where(practice: practices) + @questions = Question.where(practice: question_practices) .includes(%i[correct_answer answers]) .by_target(selected_target) .order(created_at: :desc) @@ -30,6 +24,14 @@ def empty_message end end + def question_practices + if selected_scope == 'grant_course' + [@practice] + else + [@practice, @practice.source_practice].compact + end + end + def selected_target params[:target] if %w[solved not_solved].include?(params[:target]) end From 8937bcda4380504bd18e74bf5b147f0ce53eafc1 Mon Sep 17 00:00:00 2001 From: djkazunoko Date: Mon, 13 Jul 2026 16:43:35 +0900 Subject: [PATCH 13/13] =?UTF-8?q?selected=5Fscope=E3=83=A1=E3=82=BD?= =?UTF-8?q?=E3=83=83=E3=83=89=E3=82=92=E5=89=8A=E9=99=A4=E3=81=97=E3=81=A6?= =?UTF-8?q?=E5=AE=9F=E8=A3=85=E3=82=92=E3=82=B7=E3=83=B3=E3=83=97=E3=83=AB?= =?UTF-8?q?=E3=81=AB=E3=81=97=E3=81=9F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/controllers/practices/questions_controller.rb | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/app/controllers/practices/questions_controller.rb b/app/controllers/practices/questions_controller.rb index 27e9cf42be4..f2b10c81789 100644 --- a/app/controllers/practices/questions_controller.rb +++ b/app/controllers/practices/questions_controller.rb @@ -25,7 +25,7 @@ def empty_message end def question_practices - if selected_scope == 'grant_course' + if params[:scope] == 'grant_course' [@practice] else [@practice, @practice.source_practice].compact @@ -35,8 +35,4 @@ def question_practices def selected_target params[:target] if %w[solved not_solved].include?(params[:target]) end - - def selected_scope - params[:scope] if %w[grant_course].include?(params[:scope]) - end end