Rails中persisted?方法工作原理:同内容实例为何返回不同结果?
为啥俩内容一模一样的实例,
persisted?返回结果差这么多? 哈哈,这个问题戳中了Rails Active Record实例的核心状态逻辑,我给你掰扯明白~
本质上,persisted?这个方法根本不是看实例的属性值是不是和数据库里的记录一样,它的核心作用是判断:当前这个实例,到底是不是对应数据库里已经存在的一条有效记录。Rails主要靠这两个关键点来识别:
主键(ID)的有效性
你用EmailAddress.new创建的实例,本质上是在内存里生成了一个“草稿”——它还没跟数据库打过交道,所以默认是没有主键(比如id字段)的,或者主键值是nil。而find_by捞出来的实例,是直接从数据库读取的,必然带着数据库生成的合法主键值,这是第一个区别。内部的状态标记
Active Record的实例内部藏着两个关键的状态标记:new_record?:用new创建的实例,这个标记会被设为true,相当于给Rails说“这是个还没存到库的新家伙”;destroyed?:用来标记实例是不是已经被删除(不管软删还是硬删)。
而persisted?的判断逻辑其实很简单:!new_record? && !destroyed?——只要是新创建没保存的,或者已经被删掉的,都会返回false,只有真正存在于数据库里的有效记录才会返回true。
哪怕你手动给new出来的实例赋值了和数据库记录完全一样的所有属性(包括id),只要没调用过save或者create把它存进数据库,它的new_record?标记还是true,persisted?依然会返回false。不信你试试这段代码:
# 内存里的“草稿”实例 new_email = EmailAddress.new(email: "test@example.com") new_email.id = 1 # 手动塞个主键值 new_email.persisted? # 结果还是false!因为new_record?还是true # 从数据库捞的实例 found_email = EmailAddress.find_by(email: "test@example.com") found_email.persisted? # 妥妥的true,因为new_record?是false,destroyed?也是false
总结一下:Rails判断实例是否“持久化”,看的是它有没有被成功保存到数据库的经历,靠内部状态标记和主键的有效性来识别,和属性内容是不是跟数据库记录一致,半毛钱关系都没有~
内容的提问来源于stack exchange,提问作者RalphShnelvar
相关产品推荐
相关产品推荐

