Rails 与蜻蜓的交易
Rails transaction with dragonfly
我目前正在做一个 Rails 项目。我有一个嵌套表单,允许用户上传多张图片。我正在使用蜻蜓进行上传 我还对用户可以上传的图像的大小和格式设置了一些限制,并且它们工作正常。我的问题是,当我尝试上传无效图像时,即使它们不会被上传,表单的其余部分仍会被保存。为了缓解这个问题,我最初编写了如下创建方法:
def create
@announcements = Announcement.new(announcement_params)
images = []
respond_to do |format|
params[:photos]['image'].each do |pic|
img = Photo.new(image: pic)
if img.valid?
images << img
else
@photos = @announcement.photos.build
format.html { render: 'new' }
end
if @announcement.save
params[:photos]['image'].each do |pic|
@photos = @announcement.photos.create(image: pic)
end
format.html { redirect_to @announcement }
else
format.html { render: 'new' }
end
end
end
这很好用,但我相信你们中的很多人都会同意其中有很多重复,而且代码很丑陋。在找到更好的解决方案之前,我会写一个代码作为快速解决方法。我尝试使用如下交易:
def create
@announcement = Announcement.new(announcement_params)
respond_to do |format|
ActiveRecord::Base.transaction do
begin
@announcement.save
params[:photos]["image"].each do |pic|
@photos = @announcement.photos.create!(image: pic)
end
format.html { redirect_to @announcement }
rescue
format.html { render action: 'new' }
end
end
end
结束
但它不起作用任何人都可以告诉我我做错了什么,或者建议更好的方法来做到这一点。谢谢
编辑:
这是我的日志的摘录:
Started POST "/announcements" for 127.0.0.1 at 2015-09-20 15:07:31 +0100
AnnouncementsController 处理#create as HTML
参数:{"utf8"=>"✓",
"authenticity_token"=>"fjU1kjnxqSdDwTqieOpTTCH56//p65AynqNyQQX6yiu84zwO0bJeQ3ZKr8tEBvGSZJphclxKkoys2bFp771hWg==", "announcement"=>{"title"=>"Testing wrong image size", "content"=>"Testing wrong image format with transaction code "}, "photos"=>{"image"=>[#<ActionDispatch::Http::UploadedFile:0x007fe9a83f9b18 @tempfile=#<Tempfile:/tmp/RackMultipart20150920-10097-muom0i.jpg>, @original_filename="AhiiZFK2.jpg", @content_type="image/jpeg", @headers="Content-Disposition: form-data; name=\"photos[image][]\"; filename=\"AhiiZFK2.jpg\"\r\nContent-Type: image/jpeg\r\n">]}, "commit"=>"Créer l'announce"}
User Load (0.6ms) SELECT "users".* FROM "users" WHERE "users"."id" = ORDER BY "users"."id" ASC LIMIT 1 [["id", 1]]
(0.3ms) BEGIN
SQL (0.9ms) INSERT INTO "announcements" ("title", "content", "created_at", "updated_at") VALUES (, , , ) RETURNING "id" [["title", "Testing wrong image size"], ["content", "Testing wrong image format with transaction code "], ["created_at", "2015-09-20 14:07:31.247186"], ["updated_at", "2015-09-20 14:07:31.247186"]]
DRAGONFLY: shell command: 'identify' '-ping' '-format' '%m %w %h' '/tmp/RackMultipart20150920-10097-muom0i.jpg'
(41.4ms) COMMIT
Photo Load (0.8ms) SELECT "photos".* FROM "photos" WHERE "photos"."announcement_id" = [["announcement_id", 1]]
Rendered announcements/new.html.erb within layouts/application (24.1ms)
Rendered layouts/_header.html.erb (1.9ms)
Rendered layouts/_sidebar.html.erb (0.5ms)
Completed 200 OK in 3287ms (Views: 3154.3ms | ActiveRecord: 44.1ms)
如果您不希望数据库中的数据在记录无效时出现,您需要中止交易。这是在引发异常时完成的。
但是你嵌套你的代码的方式,一个来自 create!
的异常被拯救了,事务块可以正常完成。
你需要这样嵌套:
begin
ActiveRecord::Base.transaction do
@announcement.save!
params[:photos]["image"].each do |pic|
@announcement.photos.create!(image: pic)
end
end # transaction
format.html { redirect_to @announcement }
rescue
logger.warn "transaction aborted"
format.html { render action: 'new' }
end
为了进一步改进,您将数据库的东西放在一个自己的方法中,这样数据库调用和渲染调用就不会混在一起。
要显式中止(或用数据库术语 "rollback")事务,您可以引发 ActiveRecord::Rollback
异常。这会中止交易并且不会重新抛出交易块之外。 http://api.rubyonrails.org/classes/ActiveRecord/Rollback.html
我目前正在做一个 Rails 项目。我有一个嵌套表单,允许用户上传多张图片。我正在使用蜻蜓进行上传 我还对用户可以上传的图像的大小和格式设置了一些限制,并且它们工作正常。我的问题是,当我尝试上传无效图像时,即使它们不会被上传,表单的其余部分仍会被保存。为了缓解这个问题,我最初编写了如下创建方法:
def create
@announcements = Announcement.new(announcement_params)
images = []
respond_to do |format|
params[:photos]['image'].each do |pic|
img = Photo.new(image: pic)
if img.valid?
images << img
else
@photos = @announcement.photos.build
format.html { render: 'new' }
end
if @announcement.save
params[:photos]['image'].each do |pic|
@photos = @announcement.photos.create(image: pic)
end
format.html { redirect_to @announcement }
else
format.html { render: 'new' }
end
end
end
这很好用,但我相信你们中的很多人都会同意其中有很多重复,而且代码很丑陋。在找到更好的解决方案之前,我会写一个代码作为快速解决方法。我尝试使用如下交易:
def create
@announcement = Announcement.new(announcement_params)
respond_to do |format|
ActiveRecord::Base.transaction do
begin
@announcement.save
params[:photos]["image"].each do |pic|
@photos = @announcement.photos.create!(image: pic)
end
format.html { redirect_to @announcement }
rescue
format.html { render action: 'new' }
end
end
end
结束
但它不起作用任何人都可以告诉我我做错了什么,或者建议更好的方法来做到这一点。谢谢
编辑: 这是我的日志的摘录:
Started POST "/announcements" for 127.0.0.1 at 2015-09-20 15:07:31 +0100
AnnouncementsController 处理#create as HTML 参数:{"utf8"=>"✓",
"authenticity_token"=>"fjU1kjnxqSdDwTqieOpTTCH56//p65AynqNyQQX6yiu84zwO0bJeQ3ZKr8tEBvGSZJphclxKkoys2bFp771hWg==", "announcement"=>{"title"=>"Testing wrong image size", "content"=>"Testing wrong image format with transaction code "}, "photos"=>{"image"=>[#<ActionDispatch::Http::UploadedFile:0x007fe9a83f9b18 @tempfile=#<Tempfile:/tmp/RackMultipart20150920-10097-muom0i.jpg>, @original_filename="AhiiZFK2.jpg", @content_type="image/jpeg", @headers="Content-Disposition: form-data; name=\"photos[image][]\"; filename=\"AhiiZFK2.jpg\"\r\nContent-Type: image/jpeg\r\n">]}, "commit"=>"Créer l'announce"}
User Load (0.6ms) SELECT "users".* FROM "users" WHERE "users"."id" = ORDER BY "users"."id" ASC LIMIT 1 [["id", 1]]
(0.3ms) BEGIN
SQL (0.9ms) INSERT INTO "announcements" ("title", "content", "created_at", "updated_at") VALUES (, , , ) RETURNING "id" [["title", "Testing wrong image size"], ["content", "Testing wrong image format with transaction code "], ["created_at", "2015-09-20 14:07:31.247186"], ["updated_at", "2015-09-20 14:07:31.247186"]]
DRAGONFLY: shell command: 'identify' '-ping' '-format' '%m %w %h' '/tmp/RackMultipart20150920-10097-muom0i.jpg'
(41.4ms) COMMIT
Photo Load (0.8ms) SELECT "photos".* FROM "photos" WHERE "photos"."announcement_id" = [["announcement_id", 1]]
Rendered announcements/new.html.erb within layouts/application (24.1ms)
Rendered layouts/_header.html.erb (1.9ms)
Rendered layouts/_sidebar.html.erb (0.5ms)
Completed 200 OK in 3287ms (Views: 3154.3ms | ActiveRecord: 44.1ms)
如果您不希望数据库中的数据在记录无效时出现,您需要中止交易。这是在引发异常时完成的。
但是你嵌套你的代码的方式,一个来自 create!
的异常被拯救了,事务块可以正常完成。
你需要这样嵌套:
begin
ActiveRecord::Base.transaction do
@announcement.save!
params[:photos]["image"].each do |pic|
@announcement.photos.create!(image: pic)
end
end # transaction
format.html { redirect_to @announcement }
rescue
logger.warn "transaction aborted"
format.html { render action: 'new' }
end
为了进一步改进,您将数据库的东西放在一个自己的方法中,这样数据库调用和渲染调用就不会混在一起。
要显式中止(或用数据库术语 "rollback")事务,您可以引发 ActiveRecord::Rollback
异常。这会中止交易并且不会重新抛出交易块之外。 http://api.rubyonrails.org/classes/ActiveRecord/Rollback.html