2011-06-07 49 views
5

我有多個ActiveRecord子類Item的實例數組,它們需要根據最早的事件循環打印。在這種情況下,我需要打印的打印出來的付款和維護日期如下:5天in 3天需要
B項支付7天
需要
項目的支付需要循環遍歷Ruby中的多個陣列

項目A保養。中8天

需要B項維修

我現在有尋找maintenance兩個查詢和payment項目(非排他性查詢)和類似以下輸出它們:

<%- item_p = nil -%> 
<%- item_m = nil -%> 

<%- loop do -%> 
    <% item_p ||= @items_p.shift %> 
    <% item_m ||= @items_m.shift %> 

    <%- if item_p.nil? and item_m.nil? then break -%> 
    <%- elsif item_p and (item_m.nil? or item_p.paymt < item_m.maint) then -%> 
    <%= item_p.name %> payment required in ... 
    <%- elsif item_m and (item_p.nil? or item_m.maint < item_p.paymt) then -%> 
    <%= item_m.name %> maintenance required in ... 
    <%- end -%> 
<%- end -%> 

任何方式來清理上面(醜)代碼的可讀性?

回答

2

這是快速和骯髒的(即不優化):

# In your controller: 
@items = @items_p.map{ |item| {:item => item, :days => item.paymt, :description => "payment"} } 
@items += @items_m.map{ |item| {:item => item, :days => item.maint, :description => "maintenance"} } 
@items = @items.sort_by{ |item| item[:day] } 

# In your view: 
<% @items.each do |item| %> 
    <%= item[:item].name %> <%= item[:description] %> required in <%= item[:days] %> days 
<% end %> 
+0

+1這也是我的想法,很自然地我喜歡這個想法:-) – DigitalRoss 2011-06-07 20:51:48

5

擁抱鴨打字,並確保你的對象是多態性。您希望您的付款項目爲可比較維護項目,以便對它們進行分類。

因此,假設你有一個PaymentMaintenance類:

module Due 
    include Comparable 

    # Compare this object with another. Used for sorting. 
    def <=>(other) 
    self.due <=> other.due 
    end 
end 

class Payment < ActiveRecord::Base 
    include Due 

    alias_method :due, :payment 

    def action 
    "#{name} requires payment" 
    end 
end 

class Maintenance < ActiveRecord::Base 
    include Due 

    alias_method :due, :maintenance 

    def action 
    "#{name} requires maintenance" 
    end 
end 

看看我們如何創造類的actiondue<=>方法?我們也注意包含Ruby內置模塊Comparable。這使我們可以做到以下幾點:

# Assuming 'payment' and 'maintenance' are date fields... 
a = Payment.new :payment => 3.days.from_now 
b = Maintenance.new :maintenance => 2.days.from_now 
[a, b].sort 
#=> [b, a] 

的看法則變得簡單:

<% (@payment_items + @maintenance_items).sort.each do |item| %> 
    <%= item.action %> in <%= distance_of_time_in_words_to_now(item.due) %><br/> 
<% end %> 

我敢肯定,我沒有得到你的執行權的細節,但我希望這讓你瞭解如何處理你的問題。

+0

感謝您的迴應,但是我現在的模型是一個'Item',它具有'required'和'payment'兩個屬性(作爲日期) 。這會繼續嗎?如我的示例所示,項目A顯示爲維護和付款。在這種情況下,所述物品具有需要付款的「週年紀念」和需要對所述物品進行維護的「週年紀念」。 – Stussa 2011-06-07 21:20:18

1

在你看來你太過分了。真的,你應該在控制器中找出所有這些,並通過一個可以迭代顯示的清理結構。

舉個例子:

length = [ @items_p.length, @items_m.length ].sort.last 

@messages = [ ] 

length.times do |i| 
    item_p = @items_p[i] 
    item_m = @items_m[i] 

    if (item_p and (item_m and item_p.paymt < item_m.maint) or !item_m) 
    @messages << "#{item_p.name} payment required in ..." 
    elsif (item_m and (item_p and item_m.maint < item_p.paymt) or !item_p) 
    @messages << "#{item_m.name} maintenance required in ..." 
    end 
end 

可以根據實際需要將隨後遍歷@messages

這裏真正的問題是,你沒有從戰略上講這些東西的結構這些對象。如果您在截止日期有單一方法,而不必根據類型區分paymtmaint,那將會很好。同樣,如果兩者都配對成一個數組而不是單獨提供,會更好。

如果您在[ p, m ]對有他們,你可以遍歷更加簡單:

items.each do |pair| 
    first_due = pair.compact.sort_by(&:due).first 
    @messages << "#{first_due.name} #{first_due.action} required in ..." 
end 

action方法會根據需要返回paymentmaintenance

+0

在我看來,你不想在你的控制器中做到這一點。 – molf 2011-06-07 21:13:44

+0

@molf這看起來像'胖控制器'(我聽說要避免)。在這種情況下,我應該在模型中做到這一點,謝謝! – Stussa 2011-06-07 21:22:11

+0

從視圖到控制器,以及後來,如果從控制器到模型都可以找到一個好的模式,那麼就會有重構的程度。不過,我不知道這些模型是什麼。關於在哪裏放置重型設備,無論是型號還是控制器,都有不同的思路,這可能取決於您的面向對象背景。鐵軌傾向於較重的車型。 – tadman 2011-06-08 00:57:06