我正在开发一个带有几个扩展 ActiveRecord::Base 的模型类的 Rails 应用程序。我已经在其中一些模型类上实现了多种方法,这些方法可以用来更新数据库内容,并且这些方法都可以按照我希望的方式工作。例如,我有一个TeamStats
将各种统计值存储到数据库的类,并且我定义了允许我通过应用游戏结果来更新这些属性的方法:
class TeamStats < ActiveRecord::Base
belongs_to :team
def << game_result
# Lots of stuff here to update persisted attributes for
# wins, losses, total points scored, etc
end
end
class Team < ActiveRecord::Base
has_one :stats, :class_name => TeamStats, :dependent => destroy
end
现在我发现自己想要重用该逻辑,但使用一些我不想提交到数据库的临时数据。例如,我想使用游戏的子集而不是所有游戏重新计算团队的统计数据。所以我有这样的代码:
# relevant_game_results is an array containing game results I want considered
teams.each do |team|
new_stats = TeamStats.new(:team => team)
relevent_game_results.each do |results|
new_stats << results
end
end
# Do stuff to choose a team based on these un-persisted stats that have been
# assigned to the team
# After I'm done, through all the team_stats I created and make sure all of the
# related team model objects still reference their original team stats values
我最初的计划是修改我的模型实例,然后reload
在我完成后调用这些实例。例如:
teams.each do |team|
team.reload
end
我认为这会起作用,但我必须为很多对象做这件事,如果可以的话,我宁愿在一次操作中做到这一点。
似乎我真正需要的是一个总是回滚而不是提交的事务。执行此操作的最合适的“rails 方式”是什么?我应该在一个transaction
区块内执行此操作,然后ActiveRecord::Rollback
在我的区块末尾提出一个吗?换句话说,像这样的东西?
Team.transaction do
teams.each do |team|
new_stats = TeamStats.new(:team => team)
relevent_game_results.each do |results|
new_stats << results
end
end
# Do stuff to choose a team based on these un-persisted stats that have been
# assigned to the team
raise ActiveRecord::Rollback
end
这对我来说似乎有点“肮脏”,但这只是我的 Java 背景;)是否有更符合 Rails 方式的更清洁的方法?
更新:事实证明,将其包装在事务中并回滚不仅丑陋,而且似乎很难使其正常工作。因为执行此代码的方法本身可以在另一个事务中,并且由于 ActiveRecord 关系对象的某些更改的某些趋势是自动保存的,所以我不得不跳过许多环节才能使其正常工作。
根据接受的答案中的建议,我已经采用了完全创建新 TeamStats 对象的方法,只是从不保存它。似乎对我来说工作得更好。