Ruby on rails Rails关联-更改值和缓存过多的问题!

Ruby on rails Rails关联-更改值和缓存过多的问题!,ruby-on-rails,caching,associations,Ruby On Rails,Caching,Associations,假设我有一个纸牌游戏应用程序,它有一个玩家模型,它有一个动作整数列;和卡型号。玩家可以使用自己的一张牌,这需要花费一个动作;一张特殊的牌在玩的时候会有两个动作 如果我将其编码如下: class Player < ActiveRecord::Base has_many :cards def play_card(card) raise "Not yours!" unless cards.include? card self.actions -= 1 card.

假设我有一个纸牌游戏应用程序,它有一个
玩家
模型,它有一个
动作
整数列;和
型号。玩家可以使用自己的一张牌,这需要花费一个动作;一张特殊的牌在玩的时候会有两个动作

如果我将其编码如下:

class Player < ActiveRecord::Base
  has_many :cards

  def play_card(card)
    raise "Not yours!" unless cards.include? card
    self.actions -= 1
    card.play
    save!
  end
end

class Card < ActiveRecord::Base
  belongs_to :player

  def play
    player.actions += 2
  end
end

但这会将一个数据库写入变为两次写入和一次读取!肯定有更好的办法。我遗漏了什么?

在代码的第一个版本中,您加载的是同一行的table Player,但您希望rails足够智能,能够识别它已经在内存中加载了这一行,但rails并不是这样工作的。因此,当你在玩家身上发出+=2时,它在另一个实例上发出+=2,而不是在你发出-=1的实例上发出+=2

我设置了一个小示例来说明同一行的实例太多:

ruby-1.8.7-p174 > p_instance_1 = Player.first
 => #<Player id: 1, actions: -1, created_at: "2010-10-13 17:07:22", updated_at: "2010-10-13 17:11:00"> 
ruby-1.8.7-p174 > c = Card.first
 => #<Card id: 1, player_id: 1, created_at: "2010-10-13 17:07:28", updated_at: "2010-10-13 17:07:28"> 
ruby-1.8.7-p174 > p_instance_2 = c.player
 => #<Player id: 1, actions: -1, created_at: "2010-10-13 17:07:22", updated_at: "2010-10-13 17:11:00"> 
ruby-1.8.7-p174 > p_instance_1.object_id
 => 2158703080 
ruby-1.8.7-p174 > p_instance_2.object_id
 => 2156926840 
ruby-1.8.7-p174 > p_instance_1.actions += 1
 => 0 
ruby-1.8.7-p174 > p_instance_2.actions += 1
 => 0

总而言之,我想说你的代码设计有问题。如果我理解得很好,您希望表行的每个AR实例都是ObjectSpace中的同一个对象,但我猜如果rails以这种方式构建,它将引入奇怪的行为,您可以处理在验证和其他挂钩中更改的半备份对象。

好的,我理解这两个实例是不同的“对象”到Ruby。是否有一个解决方法来防止执行三个DB操作(除了将播放器实例传递到Card#play中,因为这样做会破坏关联点)?谢谢你的解决方案。这有点难看,但知道我有这个选择很好。我同意代码设计的观点,但我很好奇你是否能建议一个更好的选择?我想(我正在使用STI)我可以将动作减量放入卡的超类中,而派生类中的增量…“错误”可能有点太强了。我只是对更新卡模型中玩家模型的动作字段感到奇怪。接受你的答案是因为这是一个有效的解决方法。为了后代,我意识到这一点,从而解决了这个问题
actions
实际上只是另一个表中的行数;因此我将其作为属性删除,并立即计算。
ruby-1.8.7-p174 > p_instance_1 = Player.first
 => #<Player id: 1, actions: -1, created_at: "2010-10-13 17:07:22", updated_at: "2010-10-13 17:11:00"> 
ruby-1.8.7-p174 > c = Card.first
 => #<Card id: 1, player_id: 1, created_at: "2010-10-13 17:07:28", updated_at: "2010-10-13 17:07:28"> 
ruby-1.8.7-p174 > p_instance_2 = c.player
 => #<Player id: 1, actions: -1, created_at: "2010-10-13 17:07:22", updated_at: "2010-10-13 17:11:00"> 
ruby-1.8.7-p174 > p_instance_1.object_id
 => 2158703080 
ruby-1.8.7-p174 > p_instance_2.object_id
 => 2156926840 
ruby-1.8.7-p174 > p_instance_1.actions += 1
 => 0 
ruby-1.8.7-p174 > p_instance_2.actions += 1
 => 0
class Player < ActiveRecord::Base
  has_many :cards

  def play_card(card)
    raise "Not yours!" unless cards.include? card
    new_self = card.player
    card.play
    new_self.actions -= 1
    new_self.save!
  end
end

class Card < ActiveRecord::Base
  belongs_to :player

  def play
    player.actions += 2
  end
end
ruby-1.8.7-p174 > p = Player.first
 => #<Player id: 1, actions: 0, created_at: "2010-10-14 13:33:51", updated_at: "2010-10-14 13:33:51"> 
ruby-1.8.7-p174 > p.play_card(Card.first)
 => true 
ruby-1.8.7-p174 > p
 => #<Player id: 1, actions: 0, created_at: "2010-10-14 13:33:51", updated_at: "2010-10-14 13:33:51"> 
ruby-1.8.7-p174 > p.reload
 => #<Player id: 1, actions: 1, created_at: "2010-10-14 13:33:51", updated_at: "2010-10-14 13:34:40"> 
  Player Load (0.5ms)   SELECT * FROM "players" LIMIT 1
  Card Load (0.2ms)   SELECT * FROM "cards" LIMIT 1
  Card Load (0.2ms)   SELECT "cards".id FROM "cards" WHERE ("cards"."id" = 1) AND ("cards".player_id = 1) LIMIT 1
  Player Load (0.1ms)   SELECT * FROM "players" WHERE ("players"."id" = 1) 
  Player Update (0.6ms)   UPDATE "players" SET "updated_at" = '2010-10-14 13:34:40', "actions" = 1 WHERE "id" = 1