Fix #4913: Invalid replacements created if an error is raised during replacement

Perform the replacement in a before_create callback so that it runs in a
transaction and if it fails, the transaction will rollback and the
replacement record won't be created.

Doing the replacement in a transaction isn't great because, for one
thing, it could hold the transaction open a long time, which isn't good
for the database. And two, if the transaction rolls back, the database
changes will be undone, but if the replacement file has already been saved
to disk, then it won't be undone, which could result in a dangling file.
This commit is contained in:
evazion
2022-02-01 00:25:31 -06:00
parent 770a6c339a
commit 60a13fd2d5
7 changed files with 37 additions and 16 deletions

View File

@@ -154,6 +154,23 @@ class PostReplacementsControllerTest < ActionDispatch::IntegrationTest
end
end
context "a replacement that fails" do
should "not create a post replacement record" do
@post = create(:post)
assert_no_difference("PostReplacement.count") do
post_auth post_replacements_path, create(:moderator_user), params: {
post_id: @post.id,
post_replacement: {
replacement_file: Rack::Test::UploadedFile.new("test/files/ugoira.json"),
}
}
assert_redirected_to @post
end
end
end
should "not allow non-mods to replace posts" do
assert_difference("PostReplacement.count", 0) do
@post = create(:post)
@@ -187,8 +204,8 @@ class PostReplacementsControllerTest < ActionDispatch::IntegrationTest
@admin = create(:admin_user)
@mod = create(:moderator_user, name: "yukari")
@post_replacement = create(:post_replacement, creator: @mod, post: create(:post, tag_string: "touhou"))
@admin_replacement = create(:post_replacement, creator: create(:admin_user), replacement_url: "https://danbooru.donmai.us")
@post_replacement = create(:post_replacement, creator: @mod, post: create(:post, tag_string: "touhou"), replacement_file: Rack::Test::UploadedFile.new("test/files/test.png"))
@admin_replacement = create(:post_replacement, creator: @admin, replacement_file: Rack::Test::UploadedFile.new("test/files/test.jpg"))
end
should "render" do
@@ -197,7 +214,6 @@ class PostReplacementsControllerTest < ActionDispatch::IntegrationTest
end
should respond_to_search({}).with { [@admin_replacement, @post_replacement] }
should respond_to_search(replacement_url_like: "*danbooru*").with { @admin_replacement }
context "using includes" do
should respond_to_search(post_tags_match: "touhou").with { @post_replacement }