Skip to content
8 changes: 6 additions & 2 deletions app/controllers/mentor/practices_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,12 @@ def index

def new
@practice = Practice.new(pjord_review: true, pjord_auto_check: false)
@practice.build_template
end

def edit; end
def edit
@practice.build_template unless @practice.template
end

def create
@practice = Practice.new(practice_params)
Expand Down Expand Up @@ -63,7 +66,8 @@ def practice_params
:summary,
:ogp_image,
category_ids: [],
practices_books_attributes: %i[id book_id must_read _destroy]
practices_books_attributes: %i[id book_id must_read _destroy],
template_attributes: %i[id description _destroy]
)
end

Expand Down
7 changes: 7 additions & 0 deletions app/models/practice.rb
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,13 @@ class Practice < ApplicationRecord # rubocop:todo Metrics/ClassLength
source: :user
has_many :skipped_practices, dependent: :destroy
has_many :products, dependent: :destroy

has_one :template, as: :templatable, dependent: :destroy
accepts_nested_attributes_for :template, update_only: true, allow_destroy: true,
reject_if: proc { |attributes|
attributes['_destroy'] != '1' && attributes['description'].blank?
}

has_many :questions, dependent: :nullify
has_many :pages,
-> { order(updated_at: :desc, id: :desc) },
Expand Down
7 changes: 7 additions & 0 deletions app/models/template.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# frozen_string_literal: true

class Template < ApplicationRecord
belongs_to :templatable, polymorphic: true

validates :description, presence: true
end
20 changes: 20 additions & 0 deletions app/views/mentor/practices/_form.html.slim
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,26 @@
= f.check_box :include_progress, class: 'a-toggle-checkbox'
= f.label :include_progress
| 進捗の計算に含むようにする場合はチェック

.form-item
label.a-form-label
| 提出物のテンプレート
= f.fields_for :template do |template_form|
- if template_form.object.persisted?
.checkboxes
ul.checkboxes__items
li.checkboxes__item
= template_form.check_box :_destroy, class: 'a-toggle-checkbox'
= template_form.label :_destroy do
| 提出物のテンプレートを削除する
.row.js-markdown-parent
.col-md-6.col-xs-12
= template_form.text_area :description,
class: 'a-text-input js-warning-form markdown-form__text-area js-markdown',
data: { 'preview': '.js-product-template-preview' }
.col-md-6.col-xs-12
.js-product-template-preview.a-long-text.is-md.markdown-form__preview

.form-item
.row.js-markdown-parent
.col-md-6.col-xs-12
Expand Down
4 changes: 3 additions & 1 deletion app/views/products/_form.html.slim
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,10 @@
| 提出物
.form-textarea
.form-textarea__body
- template = @product.practice.template&.description
= f.text_area :body, class: 'a-text-input js-warning-form js-markdown markdown-form__text-area',
data: { 'preview': '.js-preview', 'input': '.file-input' }
data: { 'preview': '.js-preview', 'input': '.file-input' },
value: @product.body.presence || template
.form-textarea__footer
.form-textarea__insert
label.a-file-insert.a-button.is-xs.is-text-reversal.is-block
Expand Down
10 changes: 10 additions & 0 deletions db/migrate/20260520061059_create_templates.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
class CreateTemplates < ActiveRecord::Migration[8.1]
def change
create_table :templates do |t|
t.references :templatable, polymorphic: true, null: false, index: { unique: true }
t.text :description, null: false

t.timestamps
end
end
end
9 changes: 9 additions & 0 deletions db/schema.rb
Original file line number Diff line number Diff line change
Expand Up @@ -1025,6 +1025,15 @@
t.index ["user_id"], name: "index_talks_on_user_id"
end

create_table "templates", force: :cascade do |t|
t.datetime "created_at", null: false
t.text "description", null: false
t.bigint "templatable_id", null: false
t.string "templatable_type", null: false
t.datetime "updated_at", null: false
t.index ["templatable_type", "templatable_id"], name: "index_templates_on_templatable", unique: true
end

create_table "users", id: :serial, force: :cascade do |t|
t.datetime "accessed_at", precision: nil
t.boolean "admin", default: false, null: false
Expand Down
3 changes: 3 additions & 0 deletions test/fixtures/templates.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
one:
templatable: practice1 (Practice)
description: 提出物のテンプレート
32 changes: 32 additions & 0 deletions test/models/practice_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -148,4 +148,36 @@ class PracticeTest < ActiveSupport::TestCase
assert_equal initial_count + 1, practice.reports_count(include_source: false)
assert_equal initial_count_including_source + 1, practice.reports_count(include_source: true)
end

test 'does not create product template when description is blank' do
practice = practices(:practice1)
practice.template&.destroy!

assert_no_difference 'Template.count' do
practice.update!(
template_attributes: {
description: ''
}
)
end

assert_nil practice.reload.template
end

test 'destroys product template with nested attributes' do
practice = practices(:practice1)
practice.template&.destroy!
template = practice.create_template!(description: '提出物のテンプレート')

assert_difference 'Template.count', -1 do
practice.update!(
template_attributes: {
id: template.id,
_destroy: '1'
}
)
end

assert_nil practice.reload.template
end
end
6 changes: 6 additions & 0 deletions test/system/practice/products_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,10 @@ class Practice::ProductsTest < ApplicationSystemTestCase
visit_with_auth "/practices/#{practices(:practice1).id}/products", 'komagata'
assert_equal 'OS X Mountain Lionをクリーンインストールするの提出物 | FBC', title
end

test 'shows product template when product template exists' do
practice = practices(:practice1)
visit_with_auth "/mentor/practices/#{practice.id}/edit", 'komagata'
assert_field 'practice_template_attributes_description', with: '提出物のテンプレート'
end
end
49 changes: 49 additions & 0 deletions test/system/practices/mentor_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -21,13 +21,32 @@ class MentorTest < ApplicationSystemTestCase
end
fill_in 'practice[goal]', with: 'テストのゴールの内容です'
fill_in 'practice[memo]', with: 'テストのメンター向けメモの内容です'
fill_in 'practice_template_attributes_description', with: 'テストテンプレート'
uncheck 'practice[pjord_review]', allow_label_click: true
click_button '登録する'
end
assert_text 'プラクティスを作成しました'
assert_not_predicate Practice.order(:created_at).last, :pjord_review?
end

test 'can create practice without product template' do
visit_with_auth '/mentor/practices/new', 'komagata'

within 'form[name=practice]' do
fill_in 'practice[title]', with: 'テンプレなし'
check categories(:category1).name, allow_label_click: true
fill_in 'practice[description]', with: 'テストの内容です'
fill_in 'practice[goal]', with: 'テストのゴールの内容です'
click_button '登録する'
end

assert_text 'プラクティスを作成しました'

practice = Practice.find_by!(title: 'テンプレなし')
visit_with_auth "/mentor/practices/#{practice.id}/edit", 'komagata'
assert_empty find_field('practice_template_attributes_description').value
end

test 'create practice as a mentor' do
visit_with_auth '/mentor/practices/new', 'mentormentaro'
within 'form[name=practice]' do
Expand All @@ -39,6 +58,7 @@ class MentorTest < ApplicationSystemTestCase
end
fill_in 'practice[goal]', with: 'テストのゴールの内容です'
fill_in 'practice[memo]', with: 'テストのメンター向けメモの内容です'
fill_in 'practice_template_attributes_description', with: 'テストテンプレート'
click_button '登録する'
end
assert_text 'プラクティスを作成しました'
Expand All @@ -51,6 +71,7 @@ class MentorTest < ApplicationSystemTestCase
within 'form[name=practice]' do
fill_in 'practice[title]', with: 'テストプラクティス'
fill_in 'practice[memo]', with: 'メンター向けのメモの内容です'
fill_in 'practice_template_attributes_description', with: 'テストテンプレート'
within '#reference_books' do
click_link '書籍を選択'
end
Expand All @@ -60,6 +81,34 @@ class MentorTest < ApplicationSystemTestCase
visit "/products/#{product.id}"
check 'toggle-mentor-memo-body', allow_label_click: true, visible: false
assert_text 'メンター向けのメモの内容です'

visit new_product_path(practice_id: practice.id)
assert_field 'product[body]', with: 'テストテンプレート'
end

test 'update product template' do
practice = practices(:practice1)
visit_with_auth "/mentor/practices/#{practice.id}/edit", 'komagata'
assert_field 'practice_template_attributes_description', with: '提出物のテンプレート'
fill_in 'practice_template_attributes_description', with: '更新後テンプレート'
click_button '更新する'
assert_text 'プラクティスを更新しました'

visit new_product_path(practice_id: practice.id)
assert_field 'product[body]', with: '更新後テンプレート'
end

test 'deletes product template from practice edit form' do
practice = practices(:practice1)
visit_with_auth "/mentor/practices/#{practice.id}/edit", 'komagata'
check '提出物のテンプレートを削除する', allow_label_click: true

assert_difference 'Template.count', -1 do
click_button '更新する'
end

assert_text 'プラクティスを更新しました'
assert_nil practice.reload.template
end

test 'add a book' do
Expand Down
Loading