2011-09-05 125 views
1

打我有兩個型號,projectswords其中project has_many :words(詞實際上只是保持每天寫每個項目詞的數量模型。減少數據庫的Rails

我有我建立一個像一個視圖這一點,這說明從開始的日子結束在這個項目有多少,如果有話寫在那一天:

<% project_range(@project.start, @project.end).each do |day| %> 
    <%= day %> 
    <%= get_word_count_by_date(@project, day) %> 
<% end %> 

而且在我的幫助:

def project_range(start, finish) 
    project_days = (start..finish).collect 
end 

def get_word_count_by_date(project, date) 
    word_count = Word.find_by_project_id_and_wrote_on(project, date) 
    if word_count 
    word_count.quantity 
    else 
    0 
    end 
end 

麻煩的是,在視圖中,很多命中我的數據庫。例如,如果該項目是30天,我得到:

Word Load (0.2ms) SELECT "words".* FROM "words" WHERE "words"."project_id" = 2 AND "words"."wrote_on" = '2011-09-01' LIMIT 1 
    Word Load (0.1ms) SELECT "words".* FROM "words" WHERE "words"."project_id" = 2 AND "words"."wrote_on" = '2011-09-02' LIMIT 1 
    Word Load (0.1ms) SELECT "words".* FROM "words" WHERE "words"."project_id" = 2 AND "words"."wrote_on" = '2011-09-03' LIMIT 1 
    Word Load (0.1ms) SELECT "words".* FROM "words" WHERE "words"."project_id" = 2 AND "words"."wrote_on" = '2011-09-04' LIMIT 1 
    Word Load (0.1ms) SELECT "words".* FROM "words" WHERE "words"."project_id" = 2 AND "words"."wrote_on" = '2011-09-05' LIMIT 1 
    Word Load (0.1ms) SELECT "words".* FROM "words" WHERE "words"."project_id" = 2 AND "words"."wrote_on" = '2011-09-06' LIMIT 1 
    Word Load (0.1ms) SELECT "words".* FROM "words" WHERE "words"."project_id" = 2 AND "words"."wrote_on" = '2011-09-07' LIMIT 1 
    Word Load (0.1ms) SELECT "words".* FROM "words" WHERE "words"."project_id" = 2 AND "words"."wrote_on" = '2011-09-08' LIMIT 1 
    Word Load (0.1ms) SELECT "words".* FROM "words" WHERE "words"."project_id" = 2 AND "words"."wrote_on" = '2011-09-09' LIMIT 1 
    Word Load (0.1ms) SELECT "words".* FROM "words" WHERE "words"."project_id" = 2 AND "words"."wrote_on" = '2011-09-10' LIMIT 1 
    Word Load (0.1ms) SELECT "words".* FROM "words" WHERE "words"."project_id" = 2 AND "words"."wrote_on" = '2011-09-11' LIMIT 1 
    Word Load (0.1ms) SELECT "words".* FROM "words" WHERE "words"."project_id" = 2 AND "words"."wrote_on" = '2011-09-12' LIMIT 1 
    Word Load (0.1ms) SELECT "words".* FROM "words" WHERE "words"."project_id" = 2 AND "words"."wrote_on" = '2011-09-13' LIMIT 1 
    Word Load (0.1ms) SELECT "words".* FROM "words" WHERE "words"."project_id" = 2 AND "words"."wrote_on" = '2011-09-14' LIMIT 1 
    Word Load (0.1ms) SELECT "words".* FROM "words" WHERE "words"."project_id" = 2 AND "words"."wrote_on" = '2011-09-15' LIMIT 1 
    Word Load (0.1ms) SELECT "words".* FROM "words" WHERE "words"."project_id" = 2 AND "words"."wrote_on" = '2011-09-16' LIMIT 1 
    Word Load (0.1ms) SELECT "words".* FROM "words" WHERE "words"."project_id" = 2 AND "words"."wrote_on" = '2011-09-17' LIMIT 1 
    Word Load (0.1ms) SELECT "words".* FROM "words" WHERE "words"."project_id" = 2 AND "words"."wrote_on" = '2011-09-18' LIMIT 1 
    Word Load (0.1ms) SELECT "words".* FROM "words" WHERE "words"."project_id" = 2 AND "words"."wrote_on" = '2011-09-19' LIMIT 1 
    Word Load (0.1ms) SELECT "words".* FROM "words" WHERE "words"."project_id" = 2 AND "words"."wrote_on" = '2011-09-20' LIMIT 1 
    Word Load (0.1ms) SELECT "words".* FROM "words" WHERE "words"."project_id" = 2 AND "words"."wrote_on" = '2011-09-21' LIMIT 1 
    Word Load (0.1ms) SELECT "words".* FROM "words" WHERE "words"."project_id" = 2 AND "words"."wrote_on" = '2011-09-22' LIMIT 1 
    Word Load (0.1ms) SELECT "words".* FROM "words" WHERE "words"."project_id" = 2 AND "words"."wrote_on" = '2011-09-23' LIMIT 1 
    Word Load (0.1ms) SELECT "words".* FROM "words" WHERE "words"."project_id" = 2 AND "words"."wrote_on" = '2011-09-24' LIMIT 1 
    Word Load (0.1ms) SELECT "words".* FROM "words" WHERE "words"."project_id" = 2 AND "words"."wrote_on" = '2011-09-25' LIMIT 1 
    Word Load (0.1ms) SELECT "words".* FROM "words" WHERE "words"."project_id" = 2 AND "words"."wrote_on" = '2011-09-26' LIMIT 1 
    Word Load (0.1ms) SELECT "words".* FROM "words" WHERE "words"."project_id" = 2 AND "words"."wrote_on" = '2011-09-27' LIMIT 1 
    Word Load (0.1ms) SELECT "words".* FROM "words" WHERE "words"."project_id" = 2 AND "words"."wrote_on" = '2011-09-28' LIMIT 1 
    Word Load (0.1ms) SELECT "words".* FROM "words" WHERE "words"."project_id" = 2 AND "words"."wrote_on" = '2011-09-29' LIMIT 1 
    Word Load (0.1ms) SELECT "words".* FROM "words" WHERE "words"."project_id" = 2 AND "words"."wrote_on" = '2011-09-30' LIMIT 1 

有沒有辦法做到這一點沒有每天都在該項目的長度查詢?我試着首先加載一個項目的所有文字,但無法弄清楚如何在那裏得到零的日子。

回答

2

你可以使用塊助手來保持它的清潔,避免找起來:

def project_range(project, start, finish, &blk) 
    words = project.words.where(:wrote_on => start..finish) 
    word_map = words.index_by(&:wrote_on) 
    for day in start..finish 
    word_count = word_map[day] ? word_map[day].quantity : 0 
    blk.call(day, word_count) 
    end 
end 

然後使用它像

<% project_range(project, start, finish) do |day, word_count| %> 
    <%= day %> 
    <%= word_count %> 
<% end %> 

您也可以清理幫手(避免使用SQL),也許可以通過傳遞預取單詞列表或使用scope

編輯:m_x建議wrote_onstart..finish where條款更清潔!

+2

啊,我剛剛發佈了相同的答案......再加上,你可以使用'where(:writes_on => @project.start .. @ project.end)',它將導致一個單獨的SQL語句IN令牌。 –

+0

哦,非常好,我會確保使用下一次我得到的機會!雖然有人認爲,如果你正在尋找一個巨大的日期範圍 - 是不是最好還是做範圍查詢而不是IN查詢 –

+0

有點麻煩這個...它不喜歡.each在開始..結束(說這是未定義的方法)。我用()包圍了範圍,然後它告訴我'不能將日期轉換爲整數' – Slick23

3

這是一個「n + 1」問題...您想要做的是在查詢中加入單詞和項目,以便每個項目的所有單詞都包含在結果集中。

假設你的項目「的has_many:詞」:

@project = Project.find(:id, :include => :words) 

現在每個項目的詞集合將在短短的1查詢預先填充的話。

更多根據「社團的預先加載」 http://api.rubyonrails.org/classes/ActiveRecord/Associations/ClassMethods.html

+0

傑西,我毫不猶豫地用這種方法是:a)他去抓住整個項目歷史的所有單詞(不僅僅是他正在查看的那個單詞)和b)他將不得不以某種方式遍歷它們以找到他正在尋找的那一天。除此之外,一致認爲這絕對是預先加載所有關聯的方式。 –

+0

@Kristian:好點....也許會添加一個自定義條件......比如':conditions => [「words.wrote_on> =?和words.wrote_on <=?」,start,end]' –

+0

不幸的是,修改原始項目查詢而不是加載的關聯(另外我相信你在考慮'.joins')。如果您有一個項目在日期範圍內沒有字詞,那麼該項目不會被退回。他還需要解決'0字數'日問題。 –

0

我會去的東西,如:

@words = @project.words.where("wrote_on >= ? and wrote_on <= ?", start, end) 

,比使用group_by在視圖中顯示它們:

@words.group_by(&:wrote_on).each do |day, word| 
<%= day %> 
<%= word.quantity %> 
end 
+0

唯一的麻煩是它似乎沒有顯示沒有字數的日子......這就是麻煩。我需要那些。 – Slick23

+0

我編輯了這個問題。我忘了字段名稱。它應該工作正常 – lucapette