【问题标题】:Ruby destroy is not working? Or objects still present?红宝石破坏不起作用?还是物体仍然存在?
【发布时间】:2015-06-07 00:32:27
【问题描述】:

一个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_dates 的方法,例如 a.plan_date[0],我希望看到 nilSun, 07 Jun 2015 00:00:00 UTC +00:00 返回。

【问题讨论】:

    标签: ruby-on-rails ruby activerecord destroy


    【解决方案1】:

    首先,让我解释一下数组保留被破坏元素的行为。由于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
    

    【讨论】:

    • 这是一个很好的解释!
    猜你喜欢
    • 1970-01-01
    • 2012-01-12
    • 1970-01-01
    • 2017-04-01
    • 1970-01-01
    • 2017-09-02
    • 1970-01-01
    • 2014-01-05
    • 1970-01-01
    相关资源
    最近更新 更多