コミットを比較
103
コミット
| 作成者 | SHA1 | 日付 | |
|---|---|---|---|
|
|
46e6d94edb | ||
|
|
817cd6ae73 | ||
|
|
dc7353304f | ||
|
|
5ff3fc9441 | ||
|
|
a847d93d2f | ||
|
|
2f87669699 | ||
|
|
1c906d7432 | ||
|
|
f662dc9dc0 | ||
|
|
206c6bc0a0 | ||
|
|
8f66ee8059 | ||
|
|
83e3db3314 | ||
|
|
eae6c30064 | ||
|
|
240e078f0b | ||
|
|
74b1ada0dd | ||
|
|
23d8adf65d | ||
|
|
e0debed94e | ||
|
|
583ce22a7e | ||
|
|
7c808a6f76 | ||
|
|
a5ae7c6f2d | ||
|
|
03dc4d0661 | ||
|
|
06b9c1cb50 | ||
|
|
688b4af575 | ||
|
|
040cc3f25d | ||
|
|
b3e67d8cca | ||
|
|
b00a62a0ac | ||
|
|
e6c3c635b8 | ||
|
|
9552081133 | ||
|
|
2d2a9b4bd6 | ||
|
|
09ac2576bb | ||
|
|
9eca670934 | ||
|
|
c31d84115d | ||
|
|
ff970f8171 | ||
|
|
0ae41b6266 | ||
|
|
eb4bf5e35c | ||
|
|
e6b7e33b83 | ||
|
|
3820d3d4d5 | ||
|
|
dd2d199d04 | ||
|
|
0a8ffc38b8 | ||
|
|
3f75994bd4 | ||
|
|
f91b78bd47 | ||
|
|
7f8cce39bc | ||
|
|
5c5a9fa1b0 | ||
|
|
66c738cbff | ||
|
|
cde0a2deae | ||
|
|
43a3772976 | ||
|
|
90d8d3ff08 | ||
|
|
d1de631eed | ||
|
|
6f3ccb0ffa | ||
|
|
95c3f08a44 | ||
|
|
ef95b20a7e | ||
|
|
f76fbe6711 | ||
|
|
0224c4d2f4 | ||
|
|
ead825e3ee | ||
|
|
3d88fdecb1 | ||
|
|
2e1b4449ba | ||
|
|
4eb483c049 | ||
|
|
e197f27e9a | ||
|
|
34f81325d2 | ||
|
|
9af4670c6c | ||
|
|
5183b0b354 | ||
|
|
d0914fce3b | ||
|
|
0ac7332458 | ||
|
|
07ce19e32d | ||
|
|
5f1d619139 | ||
|
|
3cd22855b3 | ||
|
|
55c69866a7 | ||
|
|
04d2f0f5a9 | ||
|
|
025f49cbcb | ||
|
|
d2f1b1ed48 | ||
|
|
6e5aa1e30f | ||
|
|
21d6c1408a | ||
|
|
eebbd5d069 | ||
|
|
58828597d7 | ||
|
|
b0c24f319a | ||
|
|
f9463f383f | ||
|
|
6d037192c4 | ||
|
|
d035da99ad | ||
|
|
bc660676ef | ||
|
|
97b132e5ab | ||
|
|
be68841bd3 | ||
|
|
ac82adc6b3 | ||
|
|
aa96ec95d1 | ||
|
|
df17f20907 | ||
|
|
769966648b | ||
|
|
7bcb76516c | ||
|
|
8970edc59f | ||
|
|
9b1ea56e36 | ||
|
|
155edfe018 | ||
|
|
23f1ffb04b | ||
|
|
ccfe65a6a4 | ||
|
|
06d6e512e4 | ||
|
|
5bd097bcfe | ||
|
|
f636d2a177 | ||
|
|
10dc776313 | ||
|
|
a9e16735f8 | ||
|
|
440a6c9961 | ||
|
|
4535a9d260 | ||
|
|
440d3d38be | ||
|
|
cb33d9ca25 | ||
|
|
19bf24432a | ||
|
|
ac41385962 | ||
|
|
08bf92ff79 | ||
|
|
c51d7b98ba |
@@ -200,45 +200,14 @@ class TagsController < ApplicationController
|
||||
.find_by(id: params[:id])
|
||||
return head :not_found unless tag
|
||||
|
||||
rows = normalise_deerjikist_rows(tag)
|
||||
return if performed?
|
||||
|
||||
ApplicationRecord.transaction do
|
||||
tag.lock!
|
||||
|
||||
requested_keys = rows.map { |row| [row[:platform], row[:code]] }.uniq
|
||||
row_indexes_by_key = rows_by_key(rows)
|
||||
locked_deerjikists = lock_deerjikists_for_tag_update(tag.id, requested_keys)
|
||||
current_deerjikists = locked_deerjikists.filter { |deerjikist|
|
||||
deerjikist.tag_id == tag.id
|
||||
}
|
||||
requested_deerjikists = locked_deerjikists.filter { |deerjikist|
|
||||
row_indexes_by_key.key?([deerjikist.platform, deerjikist.code])
|
||||
}
|
||||
|
||||
render_deerjikist_conflicts(requested_deerjikists, row_indexes_by_key, tag)
|
||||
raise ActiveRecord::Rollback if performed?
|
||||
|
||||
requested_keys_set = requested_keys.to_set
|
||||
current_deerjikists.each do |deerjikist|
|
||||
key = [deerjikist.platform, deerjikist.code]
|
||||
deerjikist.destroy! unless requested_keys_set.include?(key)
|
||||
end
|
||||
|
||||
existing_keys = requested_deerjikists.to_h { |deerjikist|
|
||||
[[deerjikist.platform, deerjikist.code], true]
|
||||
}
|
||||
requested_keys.each do |platform, code|
|
||||
next if existing_keys[[platform, code]]
|
||||
|
||||
deerjikist = Deerjikist.new(platform:, code:, tag:)
|
||||
row_index = row_indexes_by_key[[platform, code]].first
|
||||
begin
|
||||
render_deerjikist_form_record_invalid(deerjikist, row_index) unless deerjikist.save
|
||||
rescue ActiveRecord::RecordNotUnique
|
||||
conflicts = lock_deerjikists_for_tag_update(tag.id, [[platform, code]])
|
||||
render_deerjikist_conflicts(conflicts, row_indexes_by_key, tag)
|
||||
end
|
||||
tag.deerjikists = []
|
||||
params[:_json].each.with_index do |item, i|
|
||||
platform = item[:platform]
|
||||
code = normalise_deerjikist_code(platform, item[:code])
|
||||
deerjikist = Deerjikist.find_or_initialize_by(platform:, code:)
|
||||
deerjikist.tag = tag
|
||||
render_deerjikist_form_record_invalid(deerjikist, i) unless deerjikist.save
|
||||
raise ActiveRecord::Rollback if performed?
|
||||
end
|
||||
end
|
||||
@@ -684,7 +653,6 @@ class TagsController < ApplicationController
|
||||
end
|
||||
|
||||
def normalise_deerjikist_code platform, code
|
||||
code = code.to_s
|
||||
return code if platform != 'youtube' || code[0] != '@'
|
||||
|
||||
url = "https://www.youtube.com/#{ code }"
|
||||
@@ -701,82 +669,6 @@ class TagsController < ApplicationController
|
||||
nil
|
||||
end
|
||||
|
||||
def normalise_deerjikist_rows tag
|
||||
rows = []
|
||||
|
||||
params[:_json].each.with_index do |item, index|
|
||||
platform = item[:platform]
|
||||
unless Deerjikist.platforms.key?(platform)
|
||||
render_deerjikist_platform_invalid(index)
|
||||
return rows
|
||||
end
|
||||
|
||||
code = normalise_deerjikist_code(platform, item[:code])
|
||||
deerjikist = Deerjikist.new(platform:, code:, tag:)
|
||||
unless deerjikist.valid?
|
||||
render_deerjikist_form_record_invalid(deerjikist, index)
|
||||
return rows
|
||||
end
|
||||
|
||||
rows << { index:, platform:, code: }
|
||||
end
|
||||
|
||||
rows
|
||||
end
|
||||
|
||||
def lock_deerjikists_for_tag_update tag_id, keys
|
||||
clauses = ['tag_id = ?']
|
||||
values = [tag_id]
|
||||
|
||||
keys.each do |platform, code|
|
||||
clauses << '(platform = ? AND code = ?)'
|
||||
values << platform << code
|
||||
end
|
||||
|
||||
Deerjikist
|
||||
.where(clauses.join(' OR '), *values)
|
||||
.order(:platform, :code)
|
||||
.lock
|
||||
.to_a
|
||||
end
|
||||
|
||||
def render_deerjikist_conflicts deerjikists, row_indexes_by_key, tag
|
||||
conflicts = deerjikists.filter { |deerjikist| deerjikist.tag_id != tag.id }
|
||||
return if conflicts.empty?
|
||||
|
||||
tag_names_by_id = Tag
|
||||
.joins(:tag_name)
|
||||
.where(id: conflicts.map(&:tag_id).uniq)
|
||||
.pluck('tags.id', 'tag_names.name')
|
||||
.to_h
|
||||
fields = { }
|
||||
|
||||
conflicts.each do |deerjikist|
|
||||
message = "この情報は既に「#{ tag_names_by_id[deerjikist.tag_id] }」に紐づいてゐます."
|
||||
row_indexes_by_key[[deerjikist.platform, deerjikist.code]].each do |index|
|
||||
field = :"deerjikists.#{ index }.code"
|
||||
fields[field] ||= []
|
||||
fields[field] << message
|
||||
end
|
||||
end
|
||||
|
||||
render_validation_error fields:
|
||||
end
|
||||
|
||||
def render_deerjikist_platform_invalid index
|
||||
render_validation_error fields: {
|
||||
:"deerjikists.#{ index }.platform" => ['値が不正です.'],
|
||||
}
|
||||
end
|
||||
|
||||
def rows_by_key rows
|
||||
rows.each_with_object({ }) do |row, result|
|
||||
key = [row[:platform], row[:code]]
|
||||
result[key] ||= []
|
||||
result[key] << row[:index]
|
||||
end
|
||||
end
|
||||
|
||||
def render_deerjikist_form_record_invalid deerjikist, index
|
||||
fields = { }
|
||||
|
||||
|
||||
@@ -226,14 +226,6 @@ RSpec.describe 'Tags deerjikists API', type: :request do
|
||||
[platform2, code2],
|
||||
)
|
||||
end
|
||||
|
||||
it 'locks the tag before replacing the complete list' do
|
||||
expect_any_instance_of(Tag).to receive(:lock!).and_call_original
|
||||
|
||||
do_request
|
||||
|
||||
expect(response).to have_http_status(:ok)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when tag already has deerjikists' do
|
||||
@@ -307,81 +299,6 @@ RSpec.describe 'Tags deerjikists API', type: :request do
|
||||
end
|
||||
end
|
||||
|
||||
context 'when platform is outside the enum' do
|
||||
let(:payload) do
|
||||
[
|
||||
{ platform: 'invalid', code: code1 },
|
||||
]
|
||||
end
|
||||
|
||||
it 'returns 422 with an indexed platform error without changing the list' do
|
||||
Deerjikist.create!(platform: platform1, code: code1, tag: tag)
|
||||
|
||||
expect {
|
||||
do_request
|
||||
}.not_to change { Deerjikist.where(tag: tag).map { |d| [d.platform, d.code] } }
|
||||
|
||||
expect(response).to have_http_status(:unprocessable_entity)
|
||||
expect(json.fetch('errors')).to include(
|
||||
'deerjikists.0.platform' => [be_present],
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when a requested deerjikist belongs to another tag' do
|
||||
let!(:other_tag) { create(:tag, category: :deerjikist) }
|
||||
let!(:owned_deerjikist) do
|
||||
Deerjikist.create!(platform: platform1, code: code1, tag: tag)
|
||||
end
|
||||
let!(:conflicting_deerjikist) do
|
||||
Deerjikist.create!(platform: platform2, code: code2, tag: other_tag)
|
||||
end
|
||||
let(:payload) do
|
||||
[
|
||||
{ platform: 'nico', code: 'new-code' },
|
||||
{ platform: platform2, code: code2 },
|
||||
]
|
||||
end
|
||||
|
||||
before do
|
||||
other_tag.tag_name.update!(name: 'existing-deerjikist')
|
||||
end
|
||||
|
||||
it 'returns an indexed 422 error and rolls back the complete replacement' do
|
||||
expect {
|
||||
do_request
|
||||
}.not_to change { Deerjikist.order(:platform, :code).pluck(:platform, :code, :tag_id) }
|
||||
|
||||
expect(response).to have_http_status(:unprocessable_entity)
|
||||
expect(json.fetch('errors')).to include(
|
||||
'deerjikists.1.code' => [include('existing-deerjikist')],
|
||||
)
|
||||
expect(owned_deerjikist.reload.tag_id).to eq(tag.id)
|
||||
expect(conflicting_deerjikist.reload.tag_id).to eq(other_tag.id)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when a requested deerjikist already belongs to the same tag' do
|
||||
let!(:existing_deerjikist) do
|
||||
Deerjikist.create!(platform: platform1, code: code1, tag: tag)
|
||||
end
|
||||
let(:payload) do
|
||||
[
|
||||
{ platform: platform1, code: code1 },
|
||||
]
|
||||
end
|
||||
|
||||
it 'keeps the existing row' do
|
||||
expect {
|
||||
do_request
|
||||
}.not_to change { existing_deerjikist.reload.created_at }
|
||||
|
||||
expect(response).to have_http_status(:ok)
|
||||
expect(Deerjikist.where(tag: tag).pluck(:platform, :code))
|
||||
.to eq([[platform1, code1]])
|
||||
end
|
||||
end
|
||||
|
||||
context 'when youtube code is handle' do
|
||||
let(:channel_id) { 'UCabcdefghijklmnopqrstuv' }
|
||||
let(:payload) do
|
||||
|
||||
新しいイシューから参照
ユーザーをブロックする