Ruby 销毁不起作用?或者物体仍然存在?

Ruby destroy is not working? Or objects still present?

一个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。另外,对象实际上是如何从数组中删除的?我调用具有特定 plan_date 的方法,例如 a.plan_date[0],并且我希望看到 nilSun, 07 Jun 2015 00:00:00 UTC +00:00 返回。

首先,让我解释一下数组保留已销毁元素的行为。由于 rails 缓存机制,这种情况是可能的。

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