2012-01-12 65 views
2

我有些東西應該很簡單,但它會殺死我。導軌不能識別真假

l = LineItem.first 
#<LineItem id: 5, product_id: 1, quantity: 1, price: #<BigDecimal:7f7fdb51a3f8,'0.999E3',9(18)>, cart_id: 5, discount_percentage: 10, discount_amount: nil, discount_active: true, created_at: "2012-01-12 16:17:41", updated_at: "2012-01-12 16:17:41"> 

l.discount_percentage.blank? 
=> false 

所以,我有以下方法:

def total_price 
    discount_amount = 0 if discount_amount.blank? 
    discount_percentage = 0 if discount_percentage.blank? 

    discounted_amount_from_percent = price*(discount_percentage.to_f/100) 

    applicable_discount = [discount_amount,discounted_amount_from_percent].max 

    return (price-applicable_discount) 
    end 

但是,當我這樣做:

l.total_price 

,而不是返回899,它返回999(意思是if discount_per centage.blank?根本沒有工作!)

或者語法WHATEVER_HERE如果真/假只能在View on Rails?

+0

postfix條件('do_something if condition')是有效的Ruby語法,並且不限於視圖。 – MrTheWalrus 2012-01-12 16:48:19

+1

如果使用'self.discount_percentage'代替會發生什麼? – 2012-01-12 16:53:13

+0

戴夫,這工作,但問題是: 如果價格可以訪問沒有self.price,爲什麼我需要有自己的discount_amount和discount_percentage ??? – 2012-01-12 16:56:30

回答

6

這裏奠定了問題:

discount_amount = 0 if discount_amount.blank? 
discount_percentage = 0 if discount_percentage.blank? 

紅寶石「看到」從上到下,自左到右,所以在該行,他第一次看到一個局部變量(discount_amount =),所以他決定這個變量discount_amountdiscount_mount.blank?中的東西就是同一個局部變量(而不是實例方法,你認爲這個變量還沒有定義,但是Ruby已經發現了它)。沒有任何價值,discount_amount它設置爲默認值nil,所以nil.blank?成功,並且分配discount_percentage = 0被製成。同上discount_percentage。這裏有一個演示片段:

class ExampleClass 
    def run 
    x = "it works as expected" if x == "x" 
    x 
    end 

    def run2 
    if x == "x" 
     x = "it works as expected" 
    end 
    x 
    end 

    def run3 
    xy = "it works as expected" if x == "x" 
    xy 
    end 

    def x; "x"; end 
end 

p ExampleClass.new.run #=> nil 
p ExampleClass.new.run2 #=> "it works as expected" 
p ExampleClass.new.run3 #=> "it works as expected" 

步驟1:不使用局部變量和實例方法相同的名稱。無論如何,這通常是一個壞主意,因爲你失去了你正在使用哪一個,但在這種情況下,它真的已經咬你。

第2步:當您正在進行數學計算時,不要編寫命令式代碼!真的,數學(在典型應用中做的事情的9X%,(10-X)%是不可避免的副作用)與expressions一起玩,而不是語句。我會寫:

def total_price 
    final_discount_amount = discount_amount || 0 
    final_discount_percentage = discount_percentage || 0 
    discounted_amount_from_percent = price * (final_discount_percentage.to_f/100) 
    applicable_discount = [final_discount_amount, discounted_amount_from_percent].max 
    price - applicable_discount 
end 
+1

你的解釋非常好。 該方法更清潔。但我是一個初學者,這就是爲什麼我的方法都是必要的,包括calcs。它更接近人類的語言。 – 2012-01-13 20:09:31

1

使用屬性編寫者(例如foo = ...)時,應該明確使用self。這很好地解釋了here

所以,你的代碼應該是這樣的:

def total_price 
    self.discount_amount = 0 if discount_amount.blank? 
    self.discount_percentage = 0 if discount_percentage.blank? 

    # local var, self not necessary 
    discounted_amount_from_percent = price*(discount_percentage.to_f/100) 

    # local var, self not necessary 
    applicable_discount = [discount_amount,discounted_amount_from_percent].max 

    return (price-applicable_discount) 
    end 

這也是explained編程紅寶石書:

爲什麼我們寫在74頁的例子self.leftChannel?那麼, 有一個帶有可寫屬性的隱藏gotcha。通常,類中的方法可以以功能形式(即,具有 self的隱式接收器)調用同一類中的其他方法及其超類。但是,這不適用於屬性編寫器。 Ruby看到 這個分配,並決定左邊的名稱必須是本地的 變量,而不是對屬性編寫器的方法調用。