| @@ -173,6 +173,8 @@ class PostsController < ApplicationController | |||||
| post = Post.find(params[:id].to_i) | post = Post.find(params[:id].to_i) | ||||
| ApplicationRecord.transaction do | ApplicationRecord.transaction do | ||||
| PostVersionRecorder.ensure_snapshot!(post, created_by_user: current_user) | |||||
| post.update!(title:, original_created_from:, original_created_before:) | post.update!(title:, original_created_from:, original_created_before:) | ||||
| normalised_tags = Tag.normalise_tags(tag_names, with_tagme: false) | normalised_tags = Tag.normalise_tags(tag_names, with_tagme: false) | ||||
| @@ -12,6 +12,8 @@ class TagChildrenController < ApplicationController | |||||
| return head :bad_request if parent.nico? || child.nico? | return head :bad_request if parent.nico? || child.nico? | ||||
| ApplicationRecord.transaction do | ApplicationRecord.transaction do | ||||
| TagVersioning.ensure_snapshot!(child, created_by_user: current_user) | |||||
| TagImplication.find_or_create_by!(parent_tag: parent, tag: child) | TagImplication.find_or_create_by!(parent_tag: parent, tag: child) | ||||
| TagVersionRecorder.record!(tag: child, event_type: :update, created_by_user: current_user) | TagVersionRecorder.record!(tag: child, event_type: :update, created_by_user: current_user) | ||||
| end | end | ||||
| @@ -32,6 +34,8 @@ class TagChildrenController < ApplicationController | |||||
| return head :bad_request if parent.nico? || child.nico? | return head :bad_request if parent.nico? || child.nico? | ||||
| ApplicationRecord.transaction do | ApplicationRecord.transaction do | ||||
| TagVersioning.ensure_snapshot!(child, created_by_user: current_user) | |||||
| TagImplication.find_by(parent_tag: parent, tag: child)&.destroy! | TagImplication.find_by(parent_tag: parent, tag: child)&.destroy! | ||||
| TagVersionRecorder.record!(tag: child, event_type: :update, created_by_user: current_user) | TagVersionRecorder.record!(tag: child, event_type: :update, created_by_user: current_user) | ||||
| end | end | ||||
| @@ -224,8 +224,11 @@ class TagsController < ApplicationController | |||||
| end | end | ||||
| ApplicationRecord.transaction do | ApplicationRecord.transaction do | ||||
| TagVersioning.ensure_snapshot!(tag, created_by_user: current_user) | |||||
| tag.tag_name.update!(name:) if name.present? | tag.tag_name.update!(name:) if name.present? | ||||
| tag.update!(category:) if category.present? | tag.update!(category:) if category.present? | ||||
| record_tag_version!(tag, event_type: :update, created_by_user: current_user) | record_tag_version!(tag, event_type: :update, created_by_user: current_user) | ||||
| end | end | ||||
| @@ -79,25 +79,11 @@ class Tag < ApplicationRecord | |||||
| def material_id = materials.first&.id | 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, | def self.normalise_tags tag_names, with_tagme: true, | ||||
| with_no_deerjikist: true, | with_no_deerjikist: true, | ||||
| @@ -159,11 +145,15 @@ class Tag < ApplicationRecord | |||||
| affected_post_ids = Set.new | affected_post_ids = Set.new | ||||
| Tag.transaction do | Tag.transaction do | ||||
| TagVersioning.ensure_snapshot!(target_tag, created_by_user:) | |||||
| Array(source_tags).compact.uniq.each do |source_tag| | Array(source_tags).compact.uniq.each do |source_tag| | ||||
| source_tag => Tag | source_tag => Tag | ||||
| next if source_tag == target_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| | source_tag.post_tags.kept.find_each do |source_pt| | ||||
| post_id = source_pt.post_id | post_id = source_pt.post_id | ||||
| affected_post_ids << post_id | affected_post_ids << post_id | ||||
| @@ -179,6 +169,7 @@ class Tag < ApplicationRecord | |||||
| raise ActiveRecord::RecordInvalid.new(source_tag_name) | raise ActiveRecord::RecordInvalid.new(source_tag_name) | ||||
| end | end | ||||
| TagVersioning.record!(source_tag, event_type: :discard, created_by_user:) | |||||
| source_tag.discard! | source_tag.discard! | ||||
| if source_tag.nico? | if source_tag.nico? | ||||
| @@ -188,11 +179,11 @@ class Tag < ApplicationRecord | |||||
| updated_at: Time.current) | updated_at: Time.current) | ||||
| end | end | ||||
| TagVersioning.record!(source_tag, event_type: :discard, created_by_user:) | |||||
| TagVersioning.record!(target_tag, event_type: :update, created_by_user:) | TagVersioning.record!(target_tag, event_type: :update, created_by_user:) | ||||
| end | end | ||||
| Post.where(id: affected_post_ids.to_a).find_each do |post| | 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:) | PostVersionRecorder.record!(post:, event_type: :update, created_by_user:) | ||||
| end | end | ||||
| @@ -7,6 +7,12 @@ class PostVersionRecorder < VersionRecorder | |||||
| super(record: post, event_type:, created_by_user:) | super(record: post, event_type:, created_by_user:) | ||||
| end | 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 | private | ||||
| def version_class = PostVersion | def version_class = PostVersion | ||||
| @@ -7,6 +7,18 @@ class TagVersioning | |||||
| end | end | ||||
| 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: | def self.record_tag_snapshot! tag, created_by_user: | ||||
| event_type = | event_type = | ||||
| if tag.nico? | if tag.nico? | ||||
| @@ -10,7 +10,10 @@ class VersionRecorder | |||||
| end | end | ||||
| def record! | 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 | latest = latest_version | ||||
| if !(latest) && @event_type != 'create' | if !(latest) && @event_type != 'create' | ||||
| @@ -54,4 +57,6 @@ class VersionRecorder | |||||
| def version_association = raise NotImplementedError | def version_association = raise NotImplementedError | ||||
| def record_key = raise NotImplementedError | def record_key = raise NotImplementedError | ||||
| def snapshot_attributes = raise NotImplementedError | def snapshot_attributes = raise NotImplementedError | ||||
| def record_class = @record.class | |||||
| end | end | ||||
| @@ -153,6 +153,7 @@ namespace :nico do | |||||
| if post_created | if post_created | ||||
| PostVersionRecorder.record!(post:, event_type: :create, created_by_user: nil) | PostVersionRecorder.record!(post:, event_type: :create, created_by_user: nil) | ||||
| elsif post_changed || kept_tag_ids != desired_all_tag_ids.to_set | 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) | PostVersionRecorder.record!(post:, event_type: :update, created_by_user: nil) | ||||
| end | end | ||||
| end | end | ||||
| @@ -1,8 +1,8 @@ | |||||
| include ActiveSupport::Testing::TimeHelpers | |||||
| require 'rails_helper' | require 'rails_helper' | ||||
| require 'set' | require 'set' | ||||
| include ActiveSupport::Testing::TimeHelpers | |||||
| RSpec.describe 'Posts API', type: :request do | RSpec.describe 'Posts API', type: :request do | ||||
| # create / update で thumbnail.attach は走るが、 | # create / update で thumbnail.attach は走るが、 | ||||
| # resized_thumbnail! が MiniMagick 依存でコケやすいので request spec ではスタブしとくのが無難。 | # 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 | it 'does not create a new version on PUT /posts/:id when snapshot is unchanged' do | ||||
| sign_in_as(member) | 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: { | put "/posts/#{post_record.id}", params: { | ||||
| title: post_record.title, | title: post_record.title, | ||||
| tags: 'spec_tag' | tags: 'spec_tag' | ||||
| } | } | ||||
| end.not_to change(PostVersion, :count) | |||||
| }.not_to change(PostVersion, :count) | |||||
| expect(response).to have_http_status(:ok) | expect(response).to have_http_status(:ok) | ||||
| version = post_record.reload.post_versions.order(:version_no).last | version = post_record.reload.post_versions.order(:version_no).last | ||||
| @@ -66,7 +66,7 @@ RSpec.describe "TagChildren", type: :request do | |||||
| it "returns 204 (rescue nil)" do | it "returns 204 (rescue nil)" do | ||||
| do_request | do_request | ||||
| expect(response).to have_http_status(:no_content) | |||||
| expect(response).to have_http_status(:not_found) | |||||
| end | end | ||||
| end | end | ||||
| end | end | ||||
| @@ -126,7 +126,7 @@ RSpec.describe "TagChildren", type: :request do | |||||
| it "returns 204 (rescue nil)" do | it "returns 204 (rescue nil)" do | ||||
| do_request | do_request | ||||
| expect(response).to have_http_status(:no_content) | |||||
| expect(response).to have_http_status(:not_found) | |||||
| end | end | ||||
| end | end | ||||
| end | end | ||||