我正在阅读一篇文章并遇到了第一个示例代码。在模型中,设置实例变量以避免不必要的查询。我也在其中一个railscast中看到了这个(第二个例子)。另一方面,我在更多的文章中读到如果我使用这种模式,那么我的应用程序可能不会是线程安全的,所以我无法利用我的puma网络服务器。
可以告诉我何时/何地应该使用这种模式?
第一个例子:
def first_order_date
if first_order
first_order.created_at.to_date
else
NullDate.new 'orders'
end
end
private
def first_order
@first_order ||= orders.ascend_by_created_at.first
end
第二个例子
def shipping_price
if total_weight == 0
0.00
elsif total_weight <= 3
8.00
elsif total_weight <= 5
10.00
else
12.00
end
end
def total_weight
@total_weight ||= line_items.to_a.sum(&:weight)
end
更新的问题
第一个例子
正如我所看到的那样,'first_order_date'总是在一个对象(https://robots.thoughtbot.com/rails-refactoring-example-introduce-null-object)上调用,所以我并不完全看到如何避免额外的查询。我确定我错了,但据我所知,它可能只是
def first_order_date
if orders.ascend_by_created_at.first
first_order.created_at.to_date
else
NullDate.new 'orders'
end
end
或者也可以在其他地方使用@first_order
?
第二个例子
原始问题中的代码与此不相同?
def shipping_price
total_weight = line_items.to_a.sum(&:weight)
if total_weight == 0
0.00
elsif total_weight <= 3
8.00
elsif total_weight <= 5
10.00
else
12.00
end
end
我在这里看到他们通过定义total_weight
所取得的成就,但为什么在我的示例中使用实例变量会更好?
答案 0 :(得分:6)
短篇小说是:你的代码在Puma上应该没问题。
关于Puma环境中的线程安全性,您需要担心的是更改可能跨线程共享的内容(这通常意味着类级别的内容,而不是实例级别的内容 - 我不会&#39 ;我认为Puma将在它的线程中共享对象的实例 - 而你并没有这样做。
您引用的||=
技术称为“memoization&#39;”。您应该阅读https://bearmetal.eu/theden/how-do-i-know-whether-my-rails-app-is-thread-safe-or-not/上的完整文章,特别是有关记忆的部分。
回答你评论中的问题:
total_weight = line_items.to_a.sum(&:weight)
?我认为它只会运行一次查询好的,所以如果shipping_price
方法只针对该类的每个实例调用一次,那么你就是对了 - 不需要进行记忆。但是,如果多次调用每个实例,那么每次都必须执行line_items.to_a.sum(&:weight)
来计算总数。
所以,让我们说你在同一个实例上连续3次调用shipping_price
。然后没有记忆,它将必须执行line_items.to_a.sum(&:weight)
3次。但是通过记忆,它只需要执行line_items.to_a.sum(&:weight)
一次,而接下来的两次只需要检索@total_weight
实例变量的值
嗯......我不确定如果不写一个很长的答案并解释很多背景等,我就能给出一个好的答案。但短篇小说是:每当有一个方法,适合以下所有:
一个很好的类比可能是:如果有人问你时间,你检查你的手表(即耗时的动作)。如果他们再次问你时间,1秒钟之后,你就不需要再次检查你的手表了 - 你基本上说'#34;我刚刚检查过,它已经是9:00 am&#34;。 (这有点像你,并且记住时间 - 节省你必须检查你的手表,因为结果自你上次询问以来没有改变。)
答案 1 :(得分:2)
在这种情况下,它用于避免在答案相同时重复执行代码。
想象一下这个版本:
def shipping_price
if line_items.to_a.sum(&:weight) == 0
0.00
elsif line_items.to_a.sum(&:weight) <= 3
8.00
elsif line_items.to_a.sum(&:weight) <= 5
10.00
else
12.00
end
end
对于一件简单的事情来说,这是一件很重的事情,不是吗? ||=
模式用于缓存结果。