From 2ea08ef4dd81fcf1bdbd8a55b7ebda09f5e5e39b Mon Sep 17 00:00:00 2001 From: miteruzo Date: Sun, 19 Apr 2026 19:49:56 +0900 Subject: [PATCH] #309 --- backend/app/controllers/posts_controller.rb | 2 ++ .../controllers/tag_children_controller.rb | 4 +++ backend/app/controllers/tags_controller.rb | 3 ++ backend/app/models/tag.rb | 31 +++++++------------ backend/app/services/post_version_recorder.rb | 6 ++++ backend/app/services/tag_versioning.rb | 12 +++++++ backend/app/services/version_recorder.rb | 7 ++++- backend/lib/tasks/sync_nico.rake | 1 + backend/spec/requests/posts_spec.rb | 13 ++++---- backend/spec/requests/tag_children_spec.rb | 4 +-- 10 files changed, 54 insertions(+), 29 deletions(-) diff --git a/backend/app/controllers/posts_controller.rb b/backend/app/controllers/posts_controller.rb index 300392a..111052b 100644 --- a/backend/app/controllers/posts_controller.rb +++ b/backend/app/controllers/posts_controller.rb @@ -173,6 +173,8 @@ class PostsController < ApplicationController post = Post.find(params[:id].to_i) ApplicationRecord.transaction do + PostVersionRecorder.ensure_snapshot!(post, created_by_user: current_user) + post.update!(title:, original_created_from:, original_created_before:) normalised_tags = Tag.normalise_tags(tag_names, with_tagme: false) diff --git a/backend/app/controllers/tag_children_controller.rb b/backend/app/controllers/tag_children_controller.rb index 8a82126..8eb972e 100644 --- a/backend/app/controllers/tag_children_controller.rb +++ b/backend/app/controllers/tag_children_controller.rb @@ -12,6 +12,8 @@ class TagChildrenController < ApplicationController return head :bad_request if parent.nico? || child.nico? ApplicationRecord.transaction do + TagVersioning.ensure_snapshot!(child, created_by_user: current_user) + TagImplication.find_or_create_by!(parent_tag: parent, tag: child) TagVersionRecorder.record!(tag: child, event_type: :update, created_by_user: current_user) end @@ -32,6 +34,8 @@ class TagChildrenController < ApplicationController return head :bad_request if parent.nico? || child.nico? ApplicationRecord.transaction do + TagVersioning.ensure_snapshot!(child, created_by_user: current_user) + TagImplication.find_by(parent_tag: parent, tag: child)&.destroy! TagVersionRecorder.record!(tag: child, event_type: :update, created_by_user: current_user) end diff --git a/backend/app/controllers/tags_controller.rb b/backend/app/controllers/tags_controller.rb index 9b23fd1..94a7041 100644 --- a/backend/app/controllers/tags_controller.rb +++ b/backend/app/controllers/tags_controller.rb @@ -224,8 +224,11 @@ class TagsController < ApplicationController end ApplicationRecord.transaction do + TagVersioning.ensure_snapshot!(tag, created_by_user: current_user) + tag.tag_name.update!(name:) if name.present? tag.update!(category:) if category.present? + record_tag_version!(tag, event_type: :update, created_by_user: current_user) end diff --git a/backend/app/models/tag.rb b/backend/app/models/tag.rb index 157b083..54c3d68 100644 --- a/backend/app/models/tag.rb +++ b/backend/app/models/tag.rb @@ -79,25 +79,11 @@ class Tag < ApplicationRecord def material_id = materials.first&.id - def self.tagme - @tagme ||= find_or_create_by_tag_name!('タグ希望', category: :meta) - end - - def self.bot - @bot ||= find_or_create_by_tag_name!('bot操作', category: :meta) - end - - def self.no_deerjikist - @no_deerjikist ||= find_or_create_by_tag_name!('ニジラー情報不詳', category: :meta) - end - - def self.video - @video ||= find_or_create_by_tag_name!('動画', category: :meta) - end - - def self.niconico - @niconico ||= find_or_create_by_tag_name!('ニコニコ', category: :meta) - end + def self.tagme = find_or_create_by_tag_name!('タグ希望', category: :meta) + def self.bot = find_or_create_by_tag_name!('bot操作', category: :meta) + def self.no_deerjikist = find_or_create_by_tag_name!('ニジラー情報不詳', category: :meta) + def self.video = find_or_create_by_tag_name!('動画', category: :meta) + def self.niconico = find_or_create_by_tag_name!('ニコニコ', category: :meta) def self.normalise_tags tag_names, with_tagme: true, with_no_deerjikist: true, @@ -159,11 +145,15 @@ class Tag < ApplicationRecord affected_post_ids = Set.new Tag.transaction do + TagVersioning.ensure_snapshot!(target_tag, created_by_user:) + Array(source_tags).compact.uniq.each do |source_tag| source_tag => Tag next if source_tag == target_tag + TagVersioning.ensure_snapshot!(source_tag, created_by_user:) + source_tag.post_tags.kept.find_each do |source_pt| post_id = source_pt.post_id affected_post_ids << post_id @@ -179,6 +169,7 @@ class Tag < ApplicationRecord raise ActiveRecord::RecordInvalid.new(source_tag_name) end + TagVersioning.record!(source_tag, event_type: :discard, created_by_user:) source_tag.discard! if source_tag.nico? @@ -188,11 +179,11 @@ class Tag < ApplicationRecord updated_at: Time.current) end - TagVersioning.record!(source_tag, event_type: :discard, created_by_user:) TagVersioning.record!(target_tag, event_type: :update, created_by_user:) end Post.where(id: affected_post_ids.to_a).find_each do |post| + PostVersionRecorder.ensure_snapshot!(post, created_by_user:) PostVersionRecorder.record!(post:, event_type: :update, created_by_user:) end diff --git a/backend/app/services/post_version_recorder.rb b/backend/app/services/post_version_recorder.rb index 0e56fc7..515d1d8 100644 --- a/backend/app/services/post_version_recorder.rb +++ b/backend/app/services/post_version_recorder.rb @@ -7,6 +7,12 @@ class PostVersionRecorder < VersionRecorder super(record: post, event_type:, created_by_user:) end + def self.ensure_snapshot! post, created_by_user: + return if post.post_versions.exists? + + record!(post:, event_type: :create, created_by_user:) + end + private def version_class = PostVersion diff --git a/backend/app/services/tag_versioning.rb b/backend/app/services/tag_versioning.rb index 713cfeb..ae5b3dd 100644 --- a/backend/app/services/tag_versioning.rb +++ b/backend/app/services/tag_versioning.rb @@ -7,6 +7,18 @@ class TagVersioning end end + def self.ensure_snapshot! tag, created_by_user: + if tag.nico? + return if tag.nico_tag_versions.exists? + + NicoTagVersionRecorder.record!(tag:, event_type: :create, created_by_user:) + else + return if tag.tag_versions.exists? + + TagVersionRecorder.record!(tag:, event_type: :create, created_by_user:) + end + end + def self.record_tag_snapshot! tag, created_by_user: event_type = if tag.nico? diff --git a/backend/app/services/version_recorder.rb b/backend/app/services/version_recorder.rb index 3e1dc5c..e705ec3 100644 --- a/backend/app/services/version_recorder.rb +++ b/backend/app/services/version_recorder.rb @@ -10,7 +10,10 @@ class VersionRecorder end def record! - @record.with_lock do + raise "#{ record_class.name } must be persisted" unless @record.persisted? + + ApplicationRecord.transaction do + @record = record_class.unscoped.lock.find(@record.id) latest = latest_version if !(latest) && @event_type != 'create' @@ -54,4 +57,6 @@ class VersionRecorder def version_association = raise NotImplementedError def record_key = raise NotImplementedError def snapshot_attributes = raise NotImplementedError + + def record_class = @record.class end diff --git a/backend/lib/tasks/sync_nico.rake b/backend/lib/tasks/sync_nico.rake index fc09b72..f7c760c 100644 --- a/backend/lib/tasks/sync_nico.rake +++ b/backend/lib/tasks/sync_nico.rake @@ -153,6 +153,7 @@ namespace :nico do if post_created PostVersionRecorder.record!(post:, event_type: :create, created_by_user: nil) elsif post_changed || kept_tag_ids != desired_all_tag_ids.to_set + PostVersionRecorder.ensure_snapshot!(post, created_by_user: nil) PostVersionRecorder.record!(post:, event_type: :update, created_by_user: nil) end end diff --git a/backend/spec/requests/posts_spec.rb b/backend/spec/requests/posts_spec.rb index 605fd8d..a804bc8 100644 --- a/backend/spec/requests/posts_spec.rb +++ b/backend/spec/requests/posts_spec.rb @@ -1,8 +1,8 @@ -include ActiveSupport::Testing::TimeHelpers - require 'rails_helper' require 'set' +include ActiveSupport::Testing::TimeHelpers + RSpec.describe 'Posts API', type: :request do # create / update で thumbnail.attach は走るが、 # resized_thumbnail! が MiniMagick 依存でコケやすいので request spec ではスタブしとくのが無難。 @@ -1082,15 +1082,16 @@ RSpec.describe 'Posts API', type: :request do it 'does not create a new version on PUT /posts/:id when snapshot is unchanged' do sign_in_as(member) - create_post_version_for!(post_record) - expect do + PostTag.create!(post: post_record, tag: Tag.no_deerjikist) + create_post_version_for!(post_record.reload) + + expect { put "/posts/#{post_record.id}", params: { title: post_record.title, tags: 'spec_tag' } - end.not_to change(PostVersion, :count) - + }.not_to change(PostVersion, :count) expect(response).to have_http_status(:ok) version = post_record.reload.post_versions.order(:version_no).last diff --git a/backend/spec/requests/tag_children_spec.rb b/backend/spec/requests/tag_children_spec.rb index a5e4f83..6a93334 100644 --- a/backend/spec/requests/tag_children_spec.rb +++ b/backend/spec/requests/tag_children_spec.rb @@ -66,7 +66,7 @@ RSpec.describe "TagChildren", type: :request do it "returns 204 (rescue nil)" do do_request - expect(response).to have_http_status(:no_content) + expect(response).to have_http_status(:not_found) end end end @@ -126,7 +126,7 @@ RSpec.describe "TagChildren", type: :request do it "returns 204 (rescue nil)" do do_request - expect(response).to have_http_status(:no_content) + expect(response).to have_http_status(:not_found) end end end