【问题标题】:ActiveRecord transaction is not rolling back whole transactionActiveRecord 事务没有回滚整个事务
【发布时间】:2014-09-17 17:28:51
【问题描述】:

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

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
...

重定向也是正确的,但没有出现任何通知。

【问题讨论】:

    标签: ruby-on-rails ruby activerecord transactions


    【解决方案1】:

    要在出现错误时回滚您的事务,请将 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
    

    【讨论】:

    • 太棒了,这适用于交易,但遗憾的是错误通知没有出现,有什么想法吗?通知显示成功
    • render json: @ticket.errors 给了你一个数组,我的编辑不再是这种情况,可能是原因
    • 必须在 html 格式上使用 flash[:notice] 才能弹出错误消息
    【解决方案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, ..."
    

    【讨论】:

    • 很好,这让我也可以列出有错误的票务序列!
    • 不知道all?,在这种情况下“只有当集合成员都不为假或零时才会返回真”。很整洁。
    猜你喜欢
    • 1970-01-01
    • 2020-04-11
    • 2020-04-28
    • 2016-04-19
    • 1970-01-01
    • 2018-06-17
    • 2020-09-10
    • 1970-01-01
    • 2022-08-18
    相关资源
    最近更新 更多