2012-01-25 65 views
14

基於Rails 3 API,範圍和類方法之間的差異幾乎不存在。Rails 3中的範圍與類方法3

class Shipment < ActiveRecord::Base 
    def self.unshipped 
    where(:shipped => false) 
    end 
end 

相同

scope :unshipped, where(:shipped => false) 

然而,我發現,我有時讓他們使用不同的結果。

雖然它們都生成相同的,正確的SQL查詢,但調用時範圍並不總是返回正確的值。它看起來像這個問題只發生在它在方法中以相同的方式調用兩次,儘管在不同的貨物上。第二次調用它時,使用範圍它返回與第一次相同的事情。而如果我使用類方法,它可以正常工作。

使用範圍時是否存在某種查詢緩存?

編輯:

order.line_items.unshipped 

上面的線是範圍是如何被調用。訂單有很多line_items。

generate_multiple_shipments方法被調用兩次,因爲測試會創建一個訂單並生成貨件以查看有多少貨件。然後它會更改訂單並重新生成貨件。但是,group_by_ship_date返回與第一次訂單迭代相同的結果。

def generate_multiple_shipments(order) 
    line_items_by_date = group_by_ship_date(order.line_items.unshipped) 

    line_items_by_date.keys.sort.map do |date| 
    shipment = clone_from_order(order) 
    shipment.ship_date = date 
    line_items_by_date[date].each { |line_item| shipment.line_items << line_item } 
    shipment 
    end 
end 

def group_by_ship_date(line_items)  
    hash = {} 
    line_items.each do |line_item| 
    hash[line_item.ship_date] ||= [] 
    hash[line_item.ship_date] << line_item 
    end 
    hash 
end 
+2

能否請你提供,你相信所謂的兩次當查詢被緩存的例子(代碼段)。 –

+0

我已將更多信息添加到原始帖子。 – blim8183

+0

檢查Rails日誌會告訴你結果是否被緩存。 – Sasha

回答

1

我認爲你的調用是不正確的。您應該添加所謂的查詢方法來執行範圍,如allfirstlast,即:

order.line_items.unshipped.all 

我觀察到了一些不一致的地方,尤其是在RSpec中,通過添加查詢方法避免。

您沒有發佈您的測試代碼,所以很難準確地說出來,但我的經歷是,在修改相關記錄後,您必須強制重新加載,因爲查詢緩存並不總是足夠智能檢測到一個變化。通過傳遞true的關聯,您可以強制協會重新加載和查詢重新運行:

order.line_items(true).unshipped.all 
+0

強制關聯重新加載似乎已經成功了。我仍然不完全清楚查詢緩存如何確定是否有變化,但至少現在正在工作。謝謝! – blim8183

+0

@ blim8183我也不知道這個答案,但我懷疑這可能是一個設計權衡。很高興重新爲你工作。 –

1

假設你引用的Rails 3.1,一個範圍可以通過可以在模型中定義,而一個類的方法不會默認範圍的影響。