我的模特
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
目前的用法
在页面上显示拍卖,用户输入金额并点击出价。控制器代码可能如下所示:
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
所需的功能
这到目前为止工作得很好!但是,我需要确保其他一些事情发生。
@ab.auction.bid_count
需要增加1。
@ab.user.bid_count
需要增加1
@ab.auction.current_winner_id
需要设置为 @ab.user_id
那就是 User
和 Auction
与...相关联 AuctionBid
需要更新值以便更新 AuctionBid#save
返回真实。
保存和销毁会自动包含在事务中
都 基料#保存 和 基料#销毁 来包裹着 交易 确保您在验证或回调中所做的任何事情都将在交易的受保护保护下进行。因此,您可以使用验证来检查事务所依赖的值,或者可以在回调中引发异常以进行回滚,包括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
荣誉奖
FrançoisBeausoleil+1。谢谢你 :foreign_key
推荐,但是 current_winner_*
列需要缓存在db中以优化查询。
亚历克斯+1。谢谢你让我开始 Model.transaction { ... }
。虽然这对我来说并不是一个完整的解决方案,但它肯定有助于我指出正确的方向。
您可以覆盖AuctionBid.save,如下所示:
def save
AuctionBid.transaction {
auction.bid_count += 1
user.bid_count += 1
auction.current_winner_id = user_id
auction.save!
user.save!
return super
}
end
您可能还需要捕获事务块中引发的异常并返回false。我想你还需要补充一下 belongs_to :auction
至 AuctionBid
能够参考拍卖对象。
保存和销毁会自动包含在事务中
都 基料#保存 和 基料#销毁 来包裹着 交易 确保您在验证或回调中所做的任何事情都将在交易的受保护保护下进行。因此,您可以使用验证来检查事务所依赖的值,或者可以在回调中引发异常以进行回滚,包括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
荣誉奖
FrançoisBeausoleil+1。谢谢你 :foreign_key
推荐,但是 current_winner_*
列需要缓存在db中以优化查询。
亚历克斯+1。谢谢你让我开始 Model.transaction { ... }
。虽然这对我来说并不是一个完整的解决方案,但它肯定有助于我指出正确的方向。
您可以覆盖AuctionBid.save,如下所示:
def save
AuctionBid.transaction {
auction.bid_count += 1
user.bid_count += 1
auction.current_winner_id = user_id
auction.save!
user.save!
return super
}
end
您可能还需要捕获事务块中引发的异常并返回false。我想你还需要补充一下 belongs_to :auction
至 AuctionBid
能够参考拍卖对象。
你想要启用 反缓存 通过添加:counter_cache到belongs_to关联。
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, :counter_cache => true
belongs_to :user, :counter_cache => true
end
请记住通过迁移添加列。要创建竞价出价并设置用户,我建议使用以下代码:
class MyController
def bid
@ab = current_user.auction_bids.build(params[:auction_bid])
if @ab.save
render :json => {:response => 'YAY!'}
else
render :json => {:response => 'FAIL!'}
end
end
end
保存一个步骤,并确保您永远不会忘记分配用户。
最后的要求是找到当前的赢家。这实际上是拍卖中的has_one关联。你不需要一个列:
class Auction
# has_one is essentially has_many with an enforced :limit => 1 added
has_one :winning_bid, :class_name => "AuctionBid", :order => "bid_amount DESC"
end