I have something that should be really simple, but it’s killing me.
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">
I have
l.discount_percentage.blank?
=> false
So, I have the following method:
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
But when I do this:
l.total_price
Instead of returning 899, it returns 999 (meaning that the if discount_percentage.blank? didn’t work at all!)
Or the syntax WHATEVER_HERE if true/false only work in the View on Rails??
Here lays the problem:
Ruby “sees” variables from top to bottom and from left to right, so in that line he first sees a local variable (
discount_amount =) so he decides thisdiscount_amountthing indiscount_mount.blank?is that same local variable (and not the instance method. You think the variable is not defined yet, but Ruby has already spotted it). Not having any value yet,discount_amountit set to default valuenil, sonil.blank?succeeds and the assignmentdiscount_percentage = 0is made. Ditto fordiscount_percentage. Here’s a demo snippet:Step 1: don’t use the same names for local variables and instance methods. That’s usually a bad idea anyway because you lose track of which one you are using, but in this case it has really bitten you.
Step 2: Do not write imperative code when you’re doing math calculations! Really, maths (9X % of the things you do in a typical application, (10-X)% being unavoidable side-effects) play well with expressions, not with statements. I’d write: