如何判断ActiveRecord中的关联关系是否发生变更?
好问题!在Rails 5.2版本里,ActiveRecord确实提供了针对关联关系的变更追踪能力,不过和单个属性的#name_changed?这类方法的用法略有区别,下面分不同关联类型给你拆解说明:
针对has_many关联的变更检测
对于has_many这种一对多关联,你可以用以下几个方法来检测变更:
#association_changed?:假设你的模型定义了has_many :comments,那直接调用@post.comments_changed?就能返回布尔值,判断这个关联集合是否有添加、删除或替换过记录。- 更细粒度的检测:如果想分别判断是添加还是移除了记录,可以用
#association_added?和#association_removed?,比如@post.comments_added?会告诉你是否有新的评论被关联到这篇文章,@post.comments_removed?则检测是否有评论被移除。
注意:这些方法只对通过ActiveRecord关联方法操作的变更生效,比如用
@post.comments << new_comment或者@post.comments.destroy(existing_comment)这种方式操作;如果直接手动修改关联表的记录,是不会触发这些变更追踪的。
其他关联类型的检测方法
除了has_many,其他关联类型也有对应的检测方式:
- belongs_to关联:因为这类关联对应着模型上的外键属性,所以你可以直接用外键的
_changed?方法,比如@comment.post_id_changed?;另外也可以用#association_changed?,比如@comment.post_changed?,它会判断关联的对象是否发生了变更(比如从A文章改成了B文章)。 - has_one关联:和
belongs_to类似,既可以用#association_id_changed?(比如@user.profile_id_changed?),也可以用#association_changed?(比如@user.profile_changed?)来检测关联对象的变更。
额外注意点
- 这些变更追踪是基于当前模型实例的内存状态,只有当你修改了关联但还没保存到数据库时,这些方法才会返回
true;一旦调用save或save!,变更追踪的状态就会被重置。 - 如果只是修改了关联对象本身的属性(比如修改了某条评论的内容),
@post.comments_changed?不会返回true——因为这个方法检测的是关联集合的成员变化,而不是集合内对象的属性变化。如果要追踪这类变更,需要单独检测每个关联对象的属性变更。
内容的提问来源于stack exchange,提问作者François Beausoleil
相关产品推荐
相关产品推荐

