Rails没有认识到真或假

时间:2012-01-12 16:38:49

标签: ruby-on-rails ruby methods

我有一些应该非常简单的东西,但这会让我感到害怕。

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_percentage.blank?根本不起作用!)

或者语法WHATEVER_HERE如果true / false仅适用于View on Rails ??

2 个答案:

答案 0 :(得分:6)

这就解决了问题:

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

Ruby从顶部到底部以及从左到右“看到”变量,因此在该行中他首先看到一个局部变量(discount_amount =),因此他在discount_amount中确定了这个discount_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 :(得分: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

这也是 Programming Ruby 书中的explained

  

为什么我们在第74页的示例中编写self.leftChannel?好,   有一个隐藏的陷阱与可写属性。通常,方法   在一个类中可以调用同一个类中的其他方法及其   函数形式的超类(即隐式接收器)   self)。但是,这不适用于属性编写器。 Ruby看到了   分配并确定左侧的名称必须是本地名称   变量,而不是对属性writer的方法调用。