Sea*_*yar 0 ruby conditional ruby-on-rails instance-variables
我正在阅读一篇文章,并遇到了第一个示例代码.在模型中,设置实例变量以避免不必要的查询.我也在其中一个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
Run Code Online (Sandbox Code Playgroud)
第二个例子
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
Run Code Online (Sandbox Code Playgroud)
更新的问题
第一个例子
正如我所看到的那样,'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
Run Code Online (Sandbox Code Playgroud)
或者也可以使用@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
Run Code Online (Sandbox Code Playgroud)
我在这里看到他们通过定义实现了什么total_weight,但为什么在我的示例中使用实例变量更好?
简短的故事是:你的代码在Puma上应该没问题.
关于Puma环境中的线程安全性,您需要担心的是更改可能跨线程共享的内容(这通常意味着类级别的东西,而不是实例级别的东西 - 我不认为Puma会在它的线程之间共享对象的实例 - 而你并没有这样做.
||=您引用的技术称为"memoization".您应该阅读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方法的第一行中定义不够?我认为它只会运行一次查询好的,所以如果shipping_price方法只在每个类的实例中被调用一次,那么你是对的 - 不需要进行memoization.但是,如果每个实例多次调用它,那么每次都必须执行它line_items.to_a.sum(&:weight)来计算总数.
因此,假设您shipping_price在同一个实例上出于某种原因连续三次调用.然后没有记忆,它将不得不执行line_items.to_a.sum(&:weight)3次.但是通过memoization,它只需要执行line_items.to_a.sum(&:weight)一次,而接下来的两次它只需要检索@total_weight实例变量的值
嗯......我不确定如果不写一个很长的答案并解释很多背景等,我可以给出一个很好的答案.但短篇小说是:只要有一种方法适合以下所有方法:
一个很好的类比可能是:如果有人问你时间,你检查你的手表(即耗时的动作).如果他们再次问你时间,1秒钟之后,你不需要再次检查你的手表了 - 你基本上说"我刚刚检查过,现在是早上9点".(这有点像你在记忆时间 - 节省你必须检查你的手表,因为自从你上次询问后结果不会改变).