Rails ActiveRecord的default_scope的坑

Rails ActiveRecord的default_scope的坑

其实,我是特别反对使用default_scope的。它很强大,同时也非常的难于驾驭。它的优点在于我们只需要在Model层增加一行代码,就能解决整个项目中的如何一个地方数据的获取。

举个例子,我们有一个项目的Model,前期比较简单,我们在代码的如何地方都可以方便的使用Project.find 或者 Project.where...。然后,我们来了一个新的需求,需要给Project增加一个开关,只有通过审核的项目才能在项目中显示。这个时候,我们首先想到的方案就是使用 default_scope。 So easy! 我们只需要在Model中增加一行代码 default_scope { where("checked is not null") }。 表面上,或者没有经过全面的测试,这行代码没有问题。而且非常方便的解决了我们的问题。但其中隐藏很多问题。

问题

会在系统的其他引用Project的地方报 nil 异常

比如我们有一个User 模型, 它跟 Project的关系是 belongs_to的关系。所以,下面的代码

@users.each do |user|
    user.project.name
end

是比较常见的case。 但由于projectdefault_scope的原因,导致 projectnil, 这个时候,就会报错~

解决办法:每一个引用project的地方,都做nil判断。 这个解决方案不好,特别麻烦。一种比较好的方案是引入 gem 'unscoped_associations'.

组合而成的SQL会有问题~

这个问题比较隐晦,很难发现。我先用一个例子说明,接着上面说的。
1. 有一个新的模型 Investor,它跟Project一样,有同样的default_scope的条件,也就是说在 investors 表 和 projects 表,都有一个checked字段。
2. 约会的模型 Interview会关联上 ProjectInvestor
现在有一个需求,客户需要获取所有的Interview。我们一般会写如下的代码

Investor.includes(:project, :investor).all

上面这行代码会报错!原因是框架在组合SQL的时候,会有两个checked字段的条件,如果我们使用default_scope { where("checked is not null") } 这种方式,框架是不能设置 projects.checked 这样的条件(如果使用Hash方式,是可以智能的组合的,所以,尽量要使用hash).

解决办法:通过arel 底层组合SQL

default_scope { where(arel_table[:checked].not_eq(nil)) }

总结

default_scope给我们解决的问题的同时,会引入更多的问题。甚至需要修改底层代码才能解决。所以,在使用default_scope的时候,一定要清楚自己做什么。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值