2014-02-08 134 views
5

我是Rails的新手,我有一个奇怪的问题。ActiveRecord - “范围”中的“第一个”方法返回多个记录

这里是一个代码示例:

class News < ActiveRecord::Base 
    scope :pinned, -> { where(pinned: true).first } 
end 

如果有与“钉”标志的记录是没有问题的,当我叫News.pinned返回一条记录。

而且我看到这个查询日志中:

SELECT `news`.* 
FROM `news` 
WHERE `news`.`pinned` = 1 
ORDER BY `news`.`id` ASC 
LIMIT 1 

但是,如果没有记录与“固定”的标志,当我打电话News.pinned接下来的两个查询被执行:

SELECT `news`.* 
FROM `news` 
WHERE `news`.`pinned` = 1 
ORDER BY `news`.`id` ASC 
LIMIT 1 

SELECT `news`.* FROM `news` 

谢谢!

+0

请包括代码,其中'News.pinned'被称为。 – Victor

+0

嗨,这里是我所说的范围代码: 类NewsController user3287809

+0

检查'新闻/ index.html.erb',删除所有代码,只包括这个'<%​​= @ pinned.inspect =>',然后尝试重新加载页面并查看第二个SQL是否仍然执行。 – Victor

回答

12

Friendy,这里是ActiveRecord的方法“范围”:

1 # File activerecord/lib/active_record/scoping/named.rb, line 145 
2 def scope(name, body, &block) 
3  extension = Module.new(&block) if block 
4 
5  # Check body.is_a?(Relation) to prevent the relation actually being 
6  # loaded by respond_to? 
7  if body.is_a?(Relation) || !body.respond_to?(:call) 
8  ActiveSupport::Deprecation.warn(
9   "Using #scope without passing a callable object is deprecated. For "    "example `scope :red, where(color: 'red')` should be changed to "    "` scope :red, -> { where(color: 'red') }`. There are numerous gotchas "    "in the former usage and it makes the implementation more complicated "    "and  buggy. (If you prefer, you can just define a class method named "    "`self.red`.)" 
10  ) 
11 end 
12 
13 singleton_class.send(:define_method, name) do |*args| 
14  if body.respond_to?(:call) 
15  scope = all.scoping { body.call(*args) } 
16  scope = scope.extending(extension) if extension 
17  else 
18  scope = body 
19  end 
20 
21  scope || all 
22 end 
23 end 

注意行21如果范围是“无”,那么“所有”被返回。
在你的情况下,当你在第15行中没有记录的情况下调用“News.pinned”时,第一次咨询是运行的并且范围接收“nil”,所以当它到达第21行时,由于范围是“nil”,“all”运行第二次查询并返回所有寄存器。

我测试过它通过移除线21的“全”覆盖法“范围”,我刚一个查询

要绕过这一点:

class News < ActiveRecord::Base 
    def self.pinned 
    where(pinned: true).first 
    end 
end 
相关问题