Rails 关联 - 更改值的问题以及过多的缓存!
假设我有一个纸牌游戏应用程序,它具有一个 Player
模型,该模型有一个 actions
整数列;和一个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
...那么 Player#play_card
的最终效果是将 actions
减 1。我发现进行这两项更改的唯一方法应用于同一个对象,从而导致净增量为 1 的操作,就是定义这样的函数:
class Player < ActiveRecord::Base
has_many :cards
def play_card(card)
raise "Not yours!" unless cards.include? card
self.actions -= 1
// Stick that change in the Database
save!
card.play
end
end
class Card < ActiveRecord::Base
belongs_to :player
def play
// Force reload of the player object
player(true).actions += 2
// And save again
player.save!
end
end
但这会将单个数据库写入变成两次写入和一次读取!当然一定有更好的方法。我缺少什么?
Suppose I've got a card-game app, which features a Player
model, which has an actions
integer column; and a Card
model. A player can play a card they own, which costs an action; one particular card grants two actions when it's played.
If I code this as follows:
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
... then the net effect of Player#play_card
is to decrement actions
by 1. The only way I've found to make both changes apply to the same object, thereby resulting in a net increment of 1 action, is to define the functions like this:
class Player < ActiveRecord::Base
has_many :cards
def play_card(card)
raise "Not yours!" unless cards.include? card
self.actions -= 1
// Stick that change in the Database
save!
card.play
end
end
class Card < ActiveRecord::Base
belongs_to :player
def play
// Force reload of the player object
player(true).actions += 2
// And save again
player.save!
end
end
But that turns a single database write into two writes and a read! Surely there must be a better way. What am I missing?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
在代码的第一个版本中,您正在加载桌面播放器的同一行,但是当您期望 Rails 足够智能以识别它已经将这一行加载到内存中时,Rails 不会以这种方式工作。因此,当您对玩家发出 +=2 时,他会在另一个实例上执行 +=2,而不是在您执行 -=1 的实例上。
我设置了一个小例子来表明同一行有太多实例:
所以最后,由于您没有保存应用 +=2 的实例,所以只有 -1 的实例被保存
更新
您可以尝试欺骗 Rails 始终使用同一玩家实例。这有点难看,但它确实有效。
因此,当您输入这些命令时:
您在播放器中具有正确数量的操作,并且在日志卡中仅加载一次:
总而言之,我想说您的代码设计有问题。如果我理解得很好,你想要的是表行的每个 AR 实例都是 ObjectSpace 中的同一个对象,但我想如果 Rails 是以这种方式构建的,它会引入奇怪的行为,你可以在半支持的对象上工作改变在验证和其他挂钩中。
In the first version of your code you are loading the same row of the table players but while you are expecting rails to be smart enough to recognize that it has already load this row in memory, rails doesn't work that way. So when you are issuing a +=2 on player it does he +=2 on another instance than the one on which you have done -=1.
i've setup a little example to show that there are too instance of the same row:
So finally as you haven't save the instance with the +=2 applied, there's only the one with the -1 that is saved
UPDATE
You can try to trick rails to use the same instance of player all the way. This is a little bit ugly but it works.
so when you input those commands:
You have the right number of actions in player, and in the logs card is only loaded once:
To sum up the whole thing, I would say that there's something wrong in your code design. If i understand well,what you would like is that every AR instance of a table row is the same object in the ObjectSpace, but I guess that if rails was build that way it would introduce strange behaviors where you could work on half backed object changed in validations and other hooks.