From 83cd47632594e16a8892b4e2651ccc2489e66e77 Mon Sep 17 00:00:00 2001 From: miteruzo Date: Tue, 30 Jun 2026 12:47:02 +0900 Subject: [PATCH] #386 --- .../app/controllers/materials_controller.rb | 18 ++-- backend/spec/requests/materials_spec.rb | 89 +++++++++++++++++++ 2 files changed, 99 insertions(+), 8 deletions(-) diff --git a/backend/app/controllers/materials_controller.rb b/backend/app/controllers/materials_controller.rb index d438a73..17cd4d0 100644 --- a/backend/app/controllers/materials_controller.rb +++ b/backend/app/controllers/materials_controller.rb @@ -89,15 +89,13 @@ class MaterialsController < ApplicationController begin Material.transaction do - tag_name = TagName.find_undiscard_or_create_by!(name: tag_name_raw) - tag = tag_name.tag - tag = Tag.create!(tag_name:, category: :material) unless tag - + tag = resolve_material_tag!(tag_name_raw) material = Material.new(tag:, url:, created_by_user: current_user, updated_by_user: current_user) material.file.attach(uploaded_blob) if uploaded_blob material.save! + TagVersioning.record_tag_snapshot!(tag, created_by_user: current_user) upsert_export_paths!(material) MaterialVersionRecorder.record!(material:, event_type: :create, created_by_user: current_user) @@ -139,10 +137,7 @@ class MaterialsController < ApplicationController begin Material.transaction do MaterialVersionRecorder.ensure_snapshot!(material, created_by_user: current_user) - tag_name = TagName.find_undiscard_or_create_by!(name: tag_name_raw) - tag = tag_name.tag - tag = Tag.create!(tag_name:, category: :material) unless tag - + tag = resolve_material_tag!(tag_name_raw) material.assign_attributes(tag:, url:, updated_by_user: current_user) if uploaded_blob material.file.attach(uploaded_blob) @@ -150,6 +145,7 @@ class MaterialsController < ApplicationController material.file.detach end material.save! + TagVersioning.record_tag_snapshot!(tag, created_by_user: current_user) upsert_export_paths!(material) MaterialVersionRecorder.record!(material:, event_type: :update, created_by_user: current_user) @@ -240,6 +236,12 @@ class MaterialsController < ApplicationController nil end + def resolve_material_tag! tag_name_raw + tag_name = TagName.find_undiscard_or_create_by!(name: tag_name_raw) + tag = tag_name.tag + tag || Tag.create!(tag_name:, category: :material) + end + def material_index_needs_tag_name? filters filters[:q].present? || filters[:sort] == 'tag_name' end diff --git a/backend/spec/requests/materials_spec.rb b/backend/spec/requests/materials_spec.rb index fcabde4..c1ffdf4 100644 --- a/backend/spec/requests/materials_spec.rb +++ b/backend/spec/requests/materials_spec.rb @@ -287,6 +287,25 @@ RSpec.describe 'Materials API', type: :request do expect(json.dig('export_paths', 'legacy_drive')).to eq('伊地知ニジカ/created.png') end + it 'creates a create tag_version for a newly created material tag' do + expect do + post '/materials', params: { + tag: 'material_create_versioned_tag', + file: dummy_upload(filename: 'created.png') + } + end.to change(TagVersion, :count).by(1) + + expect(response).to have_http_status(:created) + + tag = Tag.joins(:tag_name).find_by!(tag_names: { name: 'material_create_versioned_tag' }) + version = tag.tag_versions.order(:version_no).last + + expect(version.event_type).to eq('create') + expect(version.name).to eq('material_create_versioned_tag') + expect(version.category).to eq('material') + expect(version.created_by_user).to eq(member_user) + end + it 'snapshots attached file metadata and sha256' do post '/materials', params: { tag: 'material_create_file_version', @@ -466,6 +485,73 @@ RSpec.describe 'Materials API', type: :request do expect(json.dig('tag', 'name')).to eq('material_update_new') end + it 'creates a create tag_version when update creates a new tag' do + expect do + put "/materials/#{ material.id }", params: { + tag: 'material_update_versioned_tag', + file: dummy_upload(filename: 'updated.png') + } + end.to change(Tag, :count).by(1) + .and change(TagName, :count).by(1) + .and change(TagVersion, :count).by(1) + + expect(response).to have_http_status(:ok) + + tag = Tag.joins(:tag_name).find_by!(tag_names: { name: 'material_update_versioned_tag' }) + version = tag.tag_versions.order(:version_no).last + + expect(version.event_type).to eq('create') + expect(version.name).to eq('material_update_versioned_tag') + expect(version.category).to eq('material') + expect(version.created_by_user).to eq(member_user) + end + + it 'backfills a create tag_version for an existing material tag without history' do + existing_tag = + Tag.create!(tag_name: TagName.create!(name: 'material_update_existing_no_history'), + category: :material) + + expect(existing_tag.tag_versions).to be_empty + + expect do + put "/materials/#{ material.id }", params: { + tag: 'material_update_existing_no_history', + file: dummy_upload(filename: 'updated.png') + } + end.to change(TagVersion, :count).by(1) + + expect(response).to have_http_status(:ok) + + version = existing_tag.reload.tag_versions.order(:version_no).last + expect(version.event_type).to eq('create') + expect(version.name).to eq('material_update_existing_no_history') + expect(version.category).to eq('material') + expect(version.created_by_user).to eq(member_user) + end + + it 'backfills a create tag_version for an existing character tag without history' do + existing_tag = + Tag.create!(tag_name: TagName.create!(name: 'material_update_character_no_history'), + category: :character) + + expect(existing_tag.tag_versions).to be_empty + + expect do + put "/materials/#{ material.id }", params: { + tag: 'material_update_character_no_history', + file: dummy_upload(filename: 'updated.png') + } + end.to change(TagVersion, :count).by(1) + + expect(response).to have_http_status(:ok) + + version = existing_tag.reload.tag_versions.order(:version_no).last + expect(version.event_type).to eq('create') + expect(version.name).to eq('material_update_character_no_history') + expect(version.category).to eq('character') + expect(version.created_by_user).to eq(member_user) + end + it 'detaches the existing file without purging blob when url replaces file' do old_blob_id = material.file.blob.id @@ -494,6 +580,7 @@ RSpec.describe 'Materials API', type: :request do it 'does not increase version for the same snapshot update' do MaterialVersionRecorder.record!(material:, event_type: :create, created_by_user: member_user) + TagVersioning.ensure_snapshot!(tag, created_by_user: member_user) expect do put "/materials/#{ material.id }", params: { @@ -501,6 +588,8 @@ RSpec.describe 'Materials API', type: :request do } end.not_to change(MaterialVersion, :count) + expect(tag.reload.tag_versions.count).to eq(1) + expect(response).to have_http_status(:ok) expect(material.reload.version_no).to eq(1) end -- 2.34.1