Rails事务:将数据保存在多个模型中

mač*_*ček 12 activerecord ruby-on-rails

我的模特

class Auction
  belongs_to :item
  belongs_to :user, :foreign_key => :current_winner_id
  has_many :auction_bids

end

class User
  has_many :auction_bids

end

class AuctionBid
  belongs_to :auction
  belongs_to :user

end
Run Code Online (Sandbox Code Playgroud)

目前的用法

在页面上显示拍卖,用户输入金额并点击出价.控制器代码可能如下所示:

class MyController
  def bid
    @ab = AuctionBid.new(params[:auction_bid])
    @ab.user = current_user
    if @ab.save
      render :json => {:response => 'YAY!'}
    else
      render :json => {:response => 'FAIL!'}
    end
  end 
end
Run Code Online (Sandbox Code Playgroud)

所需的功能

这到目前为止工作得很好!但是,我需要确保其他一些事情发生.

  1. @ab.auction.bid_count 需要增加1.
  2. @ab.user.bid_count 需要增加1
  3. @ab.auction.current_winner_id 需要设置为 @ab.user_id

也就是说,UserAuction与关联AuctionBid为了更新以及需要值的AuctionBid#save返回true.

mač*_*ček 11

保存和销毁会自动包含在事务中

ActiveRecord的::交易:: ClassMethods

这两个基地#保存基地#销毁进来包裹在一个交易,确保,无论你在做验证或回调将交易的保护盖下发生.因此,您可以使用验证来检查事务所依赖的值,或者可以在回调中引发异常以进行回滚,包括after_*回调.

真正的惯例!

class AuctionBid < ActiveRecord::Base

  belongs_to :auction, :counter_cache => true
  belongs_to :user

  validate              :auction_bidable?
  validate              :user_can_bid?
  validates_presence_of :auction_id
  validates_presence_of :user_id

  # the real magic!
  after_save  :update_auction, :update_user

  def auction_bidable?
    errors.add_to_base("You cannot bid on this auction!") unless auction.bidable?
  end

  def user_can_bid?
    errors.add_to_base("You cannot bid on this auction!") unless user.can_bid?
  end

  protected

  def update_auction
    auction.place_bid(user)
    auction.save!
  end

  def update_user
    user.place_bid
    user.save!
  end

end
Run Code Online (Sandbox Code Playgroud)

荣誉奖

FrançoisBeausoleil+1.感谢您的:foreign_key建议,但是current_winner_*需要在数据库中缓存列以优化查询.

亚历克斯+1.谢谢你让我开始Model.transaction { ... }.虽然这对我来说并不是一个完整的解决方案,但它肯定有助于我指出正确的方向.