我试图用唯一性约束来管理HABTM关系。
我希望我的User
has_and_belongs_to_many :tokens
但我不希望同一个令牌与给定用户多次关联。
我在连接表上放置了一个唯一索引
add_index users_tokens [:user_id, :token_id], unique: true
如果代码尝试多次向给定用户添加相同的令牌,则会正确地引发ActiveRecord::RecordNotUnique异常。
在我的代码中,我希望只是默默地捕捉/吞下这个异常,类似于:
begin
user << token
rescue ActiveRecord::RecordNotUnique
# nothing to do here since the user already has the token
end
然而,我遇到了一个问题,当我的用户对象被修改为其他对象时,RecordNotUnique异常在我的代码中很晚才被抛出。
所以一些代码调用类似于
...
# The following line throws ActiveRecord::RecordNotUnique
# for user_tokens, even though
# we are not doing anything with tokens here:
user.update_counters
这就好像关联记得它是“脏的”或未保存的,然后试图保存以前没有保存的记录,最后抛出异常。
有什么想法吗?在哪里可以查看关联是否真的认为它是脏的,和/或如何在捕获异常时重置它的“脏”状态?
1条答案
按热度按时间bkhjykvo1#
ActiveRecord在应用程序层维护数据库中记录的对象表示,包括与其他对象的关系,并尽力使应用程序层数据表示与数据库保持同步。当您将
token
分配给user
时,如下所示:ActiveRecord首先查找任何会阻止分配的应用程序级验证,如果没有找到,它将在应用程序层中将
token
链接到user
,然后它继续发出必要的DB请求,以便在DB层中也建立此连接。DB具有阻止此连接的约束,因此引发错误。您从错误中挽救并继续,但这两个对象的应用程序级连接仍然存在。下次您通过ActiveRecord对同一个user
对象进行任何编辑时,它将再次尝试使数据库与该对象在应用程序中的表示方式同步,并且由于到token
的连接仍然存在,因此它将再次尝试将此连接插入DB中,但这一次不会对出现的错误进行补救。因此,当您从数据库错误中进行救援时,还必须撤消应用程序级别的更改,如下所示: