0

短的:

在 Ruby on Rails 中保存 ActiveRecord 对象时如何防止出现竞争条件?或者如果检测到比赛,至少有办法得到错误?

长:

假设我们有这个模型

class Game < ActiveRecord::Base
  belongs_to :current_user, :class_name => "User", 
                  :foreign_key => "current_user_id"
  belongs_to :other_user, :class_name => "User", 
                  :foreign_key => "other_user_id
end

在控制器中创建游戏时,我想找到:other_user_id 为 nil 的第一个游戏,将其设置为尝试创建游戏的用户,然后保存更新的游戏。如果没有找到这样的游戏,请使用询问用户创建一个新游戏作为 current_user。

我在 ActiveRecord 的文档中找不到任何内容,显示如何防止在保存更新的游戏时出现竞争,即用户 b 可以在用户 a 找到游戏之后但在他们之前找到空游戏并保存到数据库中'已保存到数据库。如果有的话,我读过的关于唯一性验证的内容似乎我需要在数据库级别解决这个问题。

提前致谢!

4

2 回答 2

0

当然,我没有完全阅读 Rails 指南。这个http://guides.rubyonrails.org/active_record_querying.html#locking-records-for-update有一个部分

于 2012-08-29T05:22:26.093 回答
0

您本质上想要乐观锁定。这可以通过在游戏中使用 lock_version 列来启用。因此,在迁移中添加以下内容:

 class AddLockedVersionToGames < ActiveRecord::Migration
   def changes
     add_column :games, :lock_version, :integer, :default => 0
   end
 end

在游戏模型中:

  def self.add_user_to_game(current_user)
    game = Game.find_by_other_user(nil)
    if game
      game.other_user = current_user
    else
      game = Game.new(current_user: current_user)
    end
    game.save
  rescue ActiveRecord::StaleObjectError
    game = Game.new(current_user: current_user)
    game.save
  end
于 2012-08-29T07:14:07.567 回答