2016-03-05 32 views
0

Rails開始使用我的第一個正確的Rails應用程序。本週的7天Rails計數和分組到列中

我有2個表

交易

t.integer "product_id" 
t.text  "url" 
t.text  "saletime" 

產品

t.text  "name" 
t.decimal "price" 

樣本數據

交易

PRODUCT_ID | url | saletime

2  foo.com  2016-02-29T04:32:20+11:00 
    2  foo.com  2016-02-26T04:32:20+11:00 
    5  foo.com  2016-02-27T04:32:20+11:00 
    1  foo.com  2016-02-25T04:32:20+11:00 
    4  foo.com  2016-02-21T03:34:20+11:00 
    3  foo.com  2016-02-29T02:24:20+11:00 
    2  foo.com  2016-02-29T01:13:20+11:00 

產品

ID |名稱|價格

1  Prod1  39.99 
    2  Prod2  99.99 
    3  Prod3  32.99 
    4  Prod4  21.99 
    5  Prod5  19.99 

我想產生Rails的一個觀點如下(爲當前周):

Product Mon Tues Wed Thurs Fri Sat Sun Total 
Prod1  1  0  4  4  3  8  10 
Prod2  0  2  5  1  4  3  0 
Prod3  1  10  12 5  3  18 12 
Prod4  1  0  2  4  3  0  10 
Prod5  2  0  2  1  32  8  10 

我掙扎至於如何去這樣做。我應該嘗試編寫一個複雜的SQL查詢來直接返回這些數據,或者有人指出他們如何在Rails中做到這一點。

謝謝。

+0

您可能可以使用數據庫特定的日期函數按星期幾分組。你使用哪個數據庫(Postgres,MySQL等)? – ajporterfield

+0

@ajporterfield感謝問 - 我正在使用Postgres –

回答

2

我會從最簡單的解決方案開始。取決於您檢查此頁面的頻率以及您有多少產品和交易可能已經足夠好。 那麼最簡單的解決方案是什麼?我將邏輯提取到一個 Dashboard(或任何你想稱之爲)對象。這樣你不代碼雜亂款車型具體到儀表板:

class Dashboard 
    def initialize(range_start, range_end) 
    @range_start = range_start 
    @range_end = range_end 
    end 

    attr_reader :range_start, :range_end 

    def range 
    (range_start..range_end) 
    end 

    def products 
    Product.joins(:transactions).where('date(transactions.recorded_at) >= :start AND date(transactions.recorded_at) <= :end', start: range_start, end: range_end).select("products.*").distinct 
    end 

    def transactions_on(product, date) 
    product.transactions.where('date(recorded_at) = ?', date) 
    end 

    def transactions_in_range(product) 
    product.transactions.where('date(transactions.recorded_at) >= :start AND date(transactions.recorded_at) <= :end', start: range_start, end: range_end) 
    end 
end 

然後你就可以使用這個儀表板類在視圖中建表:

Displaying <%= @dashboard.range_start %> - <%= @dashboard.range_end %> 
<table border="1"> 
    <thead> 
    <tr> 
     <th>Product</th> 
     <% @dashboard.range.each do |date| %> 
     <td><%= date.strftime('%^a') %></td> 
     <% end %> 
     <th>TOTAL</th> 
    </tr> 
    </thead> 
    <tbody> 
    <% @dashboard.products.each do |product| %> 
     <tr> 
     <td><%= product.name %></td> 
     <% @dashboard.range.each do |date| %> 
      <td><%= @dashboard.transactions_on(product, date).count %></td> 
     <% end %> 
     <td><%= @dashboard.transactions_in_range(product).count %></td> 
     </tr> 
    <% end %> 
    </tbody> 
</table> 

這是非常動態的,你可以改變範圍,桌子將適應。您可以添加分頁以顯示上一週/下週或更大的範圍。

在儀表盤控制器:

def show 
    range_start = Time.zone.today.beginning_of_week - 1.week # would probably get it from params 
    range_end = range_start.end_of_week 
    @dashboard = Dashboard.new(range_start, range_end) 
    end 

這將觸發相當長的一段數查詢(1個+ range.size * products.size)。但解決方案很容易理解和維護。如果這樣做有效,那麼我不會花太多時間來實現過於聰明的事情。

聰明的一種方法是使用AR會自動添加屬性的事實。您可以使用select添加計算字段併爲其添加別名。之後,您可以使用普通的紅寶石來訪問這些值。所以,如果你想要檢索的單個SQL語句中的所有值:

def table 
    scope = Product.all.select('products.*') 
    range.each_with_index do |date, index| 
     scope = scope.select("(SELECT count(*) from transactions t WHERE t.product_id = products.id AND date(t.recorded_at) = date('#{date.to_s(:db)}')) as d_#{index}") 
    end 
    scope = scope.select("(SELECT count(*) from transactions t WHERE t.product_id = products.id AND date(t.recorded_at) >= date('#{range_start.to_s(:db)}') AND date(recorded_at) <= date('#{range_end.to_s(:db)}')) as d_total") 
    scope 
    end 

,然後在視圖中使用這樣的:

<table border="1"> 
    <thead> 
    <tr> 
     <th>Product</th> 
     <% @dashboard.range.each do |date| %> 
     <td><%= date.strftime('%^a') %></td> 
     <% end %> 
     <th>TOTAL</th> 
    </tr> 
    </thead> 
    <tbody> 
    <%- @dashboard.table.each do |product| %> 
     <tr> 
     <td><%= product.name %></td> 
     <% @dashboard.range.each_with_index do |date, index| %> 
      <td><%= product.public_send("d_#{index}") %></td> 
     <% end %> 
     <td><%= product.public_send('d_total') %></td> 
     </tr> 
    <% end %> 
    </tbody> 
</table> 

需要一些清理。但它的工作。請注意,第二個解決方案當前顯示所有產品。如果你想限制那些有相應交易的人,那麼你需要根據你的需求來調整它。

+0

哇!吹走男人!這太不可思議了 - 非常感謝你 - 這正是我期待做的事。我仍然在處理它,但這與我頭腦中的數據流相匹配,但我永遠無法以您所做過的優雅方式「Railsify」。再次感謝! –

相關問題