Rails ActiveRecord的default_scope的坑

原创 2016年05月11日 15:55:47

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的时候,一定要清楚自己做什么。

版权声明:本文为博主原创文章,未经博主允许不得转载。

相关文章推荐

rails default_scope:为一个模型设置一个操作区域

default_scope(scope = nil) Link Use this macro in your model to set a default scope for all opera...

Ruby on rails 实战圣经:ActiveRecord

All problems in computerscience can be solved by another level of indirection(abstraction) - DavidWh...

Rails中scope和类方法的区别

原文:Active Record scopes vs class methods我们在项目中应该使用scopes还是类方法来保持统一性?网上关于这个问题的讨论有很多。经典的言论往往归结于“两者没有不同...
  • lissdy
  • lissdy
  • 2016-04-09 22:06
  • 1855

Ruby on Rails,使用new和create创建ActiveRecord对象及他们之间的区别

欢迎来我的博客http://blog.csdn.net/abbuggy/article/details/7944401 在前文《Ruby on Rails,使用Rails Console进行...

Ruby on rails开发从头来(五十九)- ActiveRecord基础(预加载子记录)

预加载子记录讨论的问题和“延迟加载”是相同的。通常ActiveRecord会推迟从数据库中加载子记录,直到你需要他们,例如,通过Rdoc中的例子,我们假定博客程序有一个Model,像下面这样: cl...

Ruby on rails开发从头来(五十三)- ActiveRecord基础(表关联)

很多程序使用的数据库都包含有多个表,而且通常一些表之间还有关联关系,订单常含有多个条目,而一个条目又关联到一种商品,一个商品可能又属于多个商品分类,一个商品分类里又包含有多个不同的商品。 在数据库中...

rails ActiveRecord 操作数据库

RAILS3  ActiveRecord 操作数据库 rails ActiveRecord 操作数据库(CRUD) C 添加记录 (1) new 和 save user = U...

Ruby on rails开发从头来(四十二)- ActiveRecord基础(主键和ID)

也许你已经注意到了,在我们前面的代码中,数据库定义里都使用了一个integer型的字段id作为主键,这是Active Record的一个约定。     或许你要问,为什么不用订单编号或者某个有意义的...

使用Rails Console进行ActiveRecord调试

打开Rails的命令行,到应用的根目录,执行rails console启动。注意,要到Rails应用的根目录,我的是E:\greensoft\RailsInstaller\Sites\simple_c...
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:深度学习:神经网络中的前向传播和反向传播算法推导
举报原因:
原因补充:

(最多只允许输入30个字)