2012-02-03 34 views
3

我正在使用Rails實施在線應用程序商店。其數據模型如下圖所示:優化Rails中的購買查詢

class User < ActiveRecord::Base 
    has_many purchase_records 
    has_many items, :through => purchase_records 
end 

class Item < ActiveRecord::Base 
    has_many purchase_records 
    has_many users, :through => purchase_records 
end 

class PurchaseRecord < ActiveRecord::Base 
    belongs_to :user 
    belongs_to :item 
end 

它具有顯示可用的項目頁面,有價格,如果用戶已經購買的商品,價格將是一個下載鏈接,就像應用程序商店一樣。一個視圖助手可幫助產生這樣的聯繫:

def download_link(item) 
    # generate a download link 
end 

def item_link(item) 
    if current_user and current_user.items.where(:id => item.id).first != nil 
    # User already purchased it 
    download_link(item, 'book-price') 
    else 
    # Not purchased yet, show price and link to its details 
    link_to item.price, item 
    end 
end 

current_user由色器件定義。它可以很好地工作,除了需要20個額外的數據庫查詢才能處理20個項目的頁面,因爲它需要檢查用戶是否已經爲每個項目購買了項目。我想知道它是否可以優化,例如,預先加載購買的當前用戶的項目,但我不知道如何在視圖助手中編寫它。

回答

0

那麼,你不寫在視圖助手。您可以在名爲的purchase_items的用戶模型上創建一個範圍,您可以在其中檢查用戶購買的所有項目。

由於您沒有提供User,Item和他們的關係是什麼的源代碼,我只能給你一般提示。

+0

感謝您的意見。我在問題中添加了數據模型。 – capistrano 2012-02-04 03:44:11

1

我剛剛爲客戶端實現了可下載的內容。

我所做的是對用戶類檢索用戶的購買的物品,例如:

class User < ActiveRecord::Base 
    ... 
    def downloads 
    self.orders.collect { |o| o.products }.flatten 
    end 
end 

你可以使用包括寫一個實例方法?方法來檢查,如果用戶購買的商品,例如:

def item_link(item) 
    if current_user && current_user.downloads.include?(item) 
    download_link(item, 'book-price') 
    else 
    link_to item.price, item 
    end 
end  

不幸的是,雖然這是一個有點更加明確,它仍然會通過用戶的訂單環每次ITEM_LINK被擊中。我會建議使用Rails低級緩存優化,您可以在每次用戶登錄或完成購買時清除緩存。

一個Rails低層緩存可能看起來像這樣:

def downoads 
    Rails.cache.fetch("user-downloads-#{self.id}") do 
    self.orders.collect { |o| o.products }.flatten 
    end 
end 

,並調用以下清除緩存:

Rails.cache.delete("user-downloads-#{self.id}") 
1

您可以設置用戶的購買物品中的實例變量控制器。然後你只打一次數據庫:

# app/controllers/items_controller.rb 
def index 
    @purchased_items = current_user.items 
end 

# app/helpers/items_helper.rb 
def item_link(item) 
    if @purchased_items.include?(item) 
    download_link(...) 
    else 
    link_to ... 
    end 
end