Ruby破坏不起作用?还是仍然存在物体?

时间:2015-06-07 00:32:27

标签: ruby-on-rails ruby activerecord destroy

plan有很多plan_dates。这是我控制台的一个简单示例

a = Plan.create
a.plan_dates.create( ddate: Date.today)
a.plan_dates.create( ddate: Date.today + 1.days )
a.plan_dates.create( ddate: Date.today + 2.days )
a.plan_dates.count
# => 3
a.plan_dates.each { |pd| puts pd.ddate }
# => 2015-06-06 00:00:00 UTC
# => 2015-06-07 00:00:00 UTC
# => 2015-06-08 00:00:00 UTC

当我销毁plan_date时,count会跟踪它,但each不会:

a.plan_dates.find_by_ddate(Date.today.to_datetime).destroy
a.plan_dates.count
# => 2
a.plan_dates.each { |pd| puts pd.ddate }
# => 2015-06-06 00:00:00 UTC
# => 2015-06-07 00:00:00 UTC
# => 2015-06-08 00:00:00 UTC
a.plan_dates[0].ddate
# => Sat, 06 Jun 2015 00:00:00 UTC +00:00 
a.plan_dates[1].ddate
# => Sun, 07 Jun 2015 00:00:00 UTC +00:00 
a.plan_dates[2].ddate
# => Mon, 08 Jun 2015 00:00:00 UTC +00:00 

我认为Ruby从数据库中删除了记录但冻结了对象,所以它们仍然存在,尽管偶然:

a.plan_dates.each { |pd| puts pd.frozen? }
# => false
# => false
# => false

对于我销毁的第一个pd,我原以为true。就像这样:

a.destroy
a.frozen?
# => true

用于迭代现有记录的方法是什么?像each_non_frozen这样的东西。另外,对象实际上是如何从数组中删除的?我使用a.plan_date[0]之类的特定plan_dates调用方法,并且我想要看到nilSun, 07 Jun 2015 00:00:00 UTC +00:00返回。

1 个答案:

答案 0 :(得分:2)

首先,让我解释一下保存被破坏元素的数组的行为。由于磁道缓存机制,这种情况是可能的。

a.plan_dates.find_by_ddate(Date.today.to_datetime).destroy
# DELETE FROM "plan_dates" WHERE ...
a.plan_dates.count
# SELECT COUNT(*) FROM "plan_dates"  WHERE ...
a.plan_dates.each { |pd| puts pd.ddate }

如您所见,前两行启动SQL查询。但最后一个没有!它使用上一个请求中的缓存数组plan_dates.each。有关详细信息,请参阅控制缓存(3.1)参考部分:ActiveRecord Associations

以下是强制数组再次从数据库中获取数据的方法:

a.plan_dates(true).each { |pd| puts pd.ddate }
# => 2015-06-07 00:00:00 UTC
# => 2015-06-08 00:00:00 UTC

# another way, with the same effect:
a.plan_dates.reload.each { |pd| puts pd.ddate }

在冻结对象时,Rails会冻结手动接收destroy方法调用的数组元素,但不知道在完全不同的对象上调用它时会发生什么:

a.plan_dates.find_by_ddate(Date.today.to_datetime).destroy
# you have initiated SQL SELECT here!
# the result is not contained in initial array

这可以按预期使用EnumerableArray而不是ActiveRecord的查询器进行调用:

a.plan_dates.find{|i| i.ddate == Date.today}.destroy
a.plan_dates.find{|i| i.ddate == Date.today}.frozen? # => true