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中scope和类方法的区别

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

Rails 中 scope

Rails 中自由地使用命名 scope# 可以链式调用 class User < ActiveRecord::Base scope :old, -> { where('age > 60') } ...
  • XIAO_XIAO_C
  • XIAO_XIAO_C
  • 2017年06月30日 10:48
  • 251

Ruby on rails 实战圣经:ActiveRecord

All problems in computerscience can be solved by another level of indirection(abstraction) - DavidWh...
  • felomeng
  • felomeng
  • 2013年11月29日 17:28
  • 13854

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

default_scope(scope = nil) Link Use this macro in your model to set a default scope for all opera...
  • dazhi_100
  • dazhi_100
  • 2013年08月02日 14:42
  • 2169

Rails ActiveRecord的default_scope的坑

Rails ActiveRecord的default_scope的坑其实,我是特别反对使用default_scope的。它很强大,同时也非常的难于驾驭。它的优点在于我们只需要在Model层增加一行代码...
  • hexudong08
  • hexudong08
  • 2016年05月11日 15:55
  • 1616

rails优化三:default_scope是魔鬼

解读default_scope方法。
  • u010642107
  • u010642107
  • 2015年01月23日 17:39
  • 779

如何修改RubyOnRails中ActiveRecord默认的表格名和外键字段映射关系?

        最近在看ROR的东西,并试着实践了一下。        在看完了ROR那个诱人的demo短片和Eiffel Qiu的rubyonrails.pdf后,我在佩服ror的快捷之余,有两个疑...
  • earoc
  • earoc
  • 2006年05月02日 23:24
  • 1684

Ruby Variable Scope 简单讲解

Name Begins With Variable Scope $ A global variable @ An instance variable [a-z] or _ A local ...
  • cs08211317dn
  • cs08211317dn
  • 2015年06月21日 02:45
  • 768

Rails宝典之第五式: 使用with_scope

这次来介绍with_scope方法的使用。  继续前面的例子,我们希望只取得complete为false的前20条数据,我们可以给find_incomplete方法添加一个Hash参数,然后使用...
  • blacksource
  • blacksource
  • 2011年12月25日 22:17
  • 1100

ruby rails 重写activerecord::Base 的字段属性

在ruby rails中如果你想要保存一个属性(或读取一个属性),同时希望在保存属性(或读取一个属性)时做一些其他的操作 可以使用重写该属性的设置器或读取器的方法。 比如一个Models的表中有一...
  • u010640235
  • u010640235
  • 2015年04月03日 11:10
  • 857
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:Rails ActiveRecord的default_scope的坑
举报原因:
原因补充:

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