2014-02-08 92 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 
相關問題