Kar*_*arl 0 validation activerecord ruby-on-rails-3
我有一个种族表,在不同的州有很多种族.但是我需要确保只有一个种族被标记为current = true.这是我在Race模型验证中使用的内容.
# current: boolean
validate :only_one_current
private
def only_one_current
if self.current && (Race.current_race.id != self.id)
errors.add(:base, "Races can have only one current race")
end
end
Run Code Online (Sandbox Code Playgroud)
这似乎在大多数时间都有效,但偶尔也没有,我不知道为什么.当它不起作用时,它不允许在删除当前不同的记录之后用current = t保存新记录.我认为这与AR的持久性有关.
必须有更好的方法来做到这一点?
您的问题实际上超出了ActiveRecord.无论你如何实现你的before_save方法,总是有可能发生竞争条件(没有双关语),并且两条记录在数据库中具有current = true.有关更多信息,请参阅validates_uniqueness_of的Concurrancy and Integrity部分.
核心问题是检查记录是否具有current = true并且操作将记录设置为current = true的逻辑不是原子的.这个问题经常出现在并发系统中.
要解决此问题,您需要在数据库中使用唯一的密钥索引.我建议您将当前标志更改为优先级字段.优先级是一个具有唯一键索引的整数.数据库将保证不会同时存在具有相同优先级值的两条记录."当前"竞赛将永远是具有最高优先级值的竞赛.
竞争条件实际上仍然存在 - 你现在只有一种方法来检测它.当您将争用设置为当前(通过查询表中的最大优先级值)时,如果另一个记录当前保持与您尝试保存的记录具有相同的优先级值,则会生成异常.只需捕获重复的密钥异常,然后重试.
| 归档时间: |
|
| 查看次数: |
1669 次 |
| 最近记录: |