2012-01-12 13 views
2

私は本当にシンプルでなければならないものがありますが、それは私を殺しています。私はそう真または偽を認識しないレール

l.discount_percentage.blank? 
=> false 

を持って

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"> 

、私は次の方法があります。

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? )まったく動作しませんでした!

true/falseがView on Railsでしか機能しない場合は、構文WHATEVER_HERE?

+0

ポストフィックス条件( 'do_something if condition')はRubyの有効な構文であり、ビューに限定されません。 – MrTheWalrus

+1

代わりに 'self.discount_percentage'を使うとどうなりますか? –

+0

Dave、それは問題ありませんが、問題は次のとおりです。 価格がself.priceなしでアクセスできるのであれば、なぜ私はdiscount_amountとdiscount_percentageで自己を持っている必要がありますか? –

答えて

6

問題を産む:

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

Rubyはその行に、彼は最初のローカル変数を見ているように、上から下へ、左から右へ、変数、(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:計算を行うときに命令コードを書き込まないでください!実際には、数学(典型的なアプリケーションで行うことの9倍の%、(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を含めて不可欠です。それは人間の言語に近いです。 –

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 

これもプログラミングRubyの本の中でexplainedです:

なぜ私たちは、74ページの例ではself.leftChannelを書きましたか?さて、 書き込み可能な属性を持つ隠された癖があります。通常、あるクラス内のメソッド は、同じクラス内の他のメソッドと、その関数型の スーパークラス(暗黙の受信者 self)を呼び出すことができます。しかし、これは属性ライターでは機能しません。 Rubyは の割り当てを見て、左の名前が属性ライターへのメソッド呼び出しではなくローカルの 変数でなければならないと判断します。ここで

関連する問題