ActiveRecord 事务未完全回滚

3

我有一个门票模型,用户可以从给定的序列号开始连续购买门票。用户选择他们想要购买的门票数量,控制器将生成相应数量的门票并存储在数据库中。然而,如果一张门票保存失败,事务应该回滚,但在这种情况下没有回滚。

tickets_controller.rb

...
def create
  number = params[:ticket_qty].to_i
  @tickets = Array.new
  number.times do |n|
    t = Ticket.new(ticket_params)
    t.serial_number = t.serial_number.to_i + n 
    @tickets.push(t)
  end

  respond_to do |format|
    ActiveRecord::Base.transaction do 
      @tickets.each do |t| 
        if t.save
          format.html { redirect_to tickets_path, notice: "#{number} #{"ticket".pluralize(number)} successfully created." }
          format.json { render :show, status: :created, location: tickets_path }
        else
          format.html { render :new, notice: "Some tickets have errors, check the serial number range" }
          format.json { render json: @ticket.errors, status: :unprocessable_entity }
        end
      end
    end
  end
end
...

此外,重定向是正确的,但没有任何通知显示出来。
2个回答

4

如果希望在出现错误时回滚您的事务,请将t.save替换为t.save!

这将导致:

respond_to do |format|
  begin 
    ActiveRecord::Base.transaction do 
      @tickets.each &:save!
      format.html { redirect_to tickets_path, notice: "#{number} #{"ticket".pluralize(number)} successfully created." }
      format.json { render :show, status: :created, location: tickets_path }
    end
  rescue ActiveRecord::ActiveRecordError => e
    format.html { render :new, notice: "Some tickets have errors, check the serial number range" }
    format.json { render json: e.message, status: :unprocessable_entity }
  end
end

太棒了,这个交易可以正常进行,但是遗憾的是错误提示没有出现,有什么想法吗?不过成功时会显示提示。 - Syafiq Kamarul Azman
render json: @ticket.errors 给你返回了一个数组,但在我的编辑中不再是这种情况,这可能是原因。 - apneadiving
必须在HTML格式中使用flash[:notice]才能弹出错误消息。 - Syafiq Kamarul Azman

2
另一种选择是保存所有记录,并根据结果手动触发回滚:
Ticket.transaction do 
  @save_results = @tickets.map(&:save)
  raise ActiveRecord::Rollback unless @save_results.all?
end

respond_to do |format|
  if @save_results.all?
    format.html # ...
    format.json # ...
  else
    format.html # ...
    format.json # ...
  end
end

您可以使用@save_results来显示失败记录的数量:
"#{@save_results.count(false)} tickets have errors, ..."

不错,这让我也可以列出出现错误的票据序列号! - Syafiq Kamarul Azman
不知道 all?,在这种情况下,“只有当集合成员都不为false或nil时才返回true。”非常棒。 - daniel

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接