【问题标题】:Deleting old records assigned to variable删除分配给变量的旧记录
【发布时间】:2016-03-21 08:45:18
【问题描述】:

我的主要目标是在正确创建新记录后删除旧记录。我尝试将其分配给变量并使用#dup 方法。请看示例代码:

def my_method
  old_items = @user.items.dup

  new_items = @user.items.new(item_params) # one or more

  # confusing part
  old_items.destroy_all if new_items.save
end

我想销毁 old_items,但是当我创建 new_items 时,它们是 old_items == new_items。为什么重复#dup 在这里不起作用?如何拆分和删除旧记录?我还尝试了一个事务(如果 new_items 无效则回滚),这也不起作用。

【问题讨论】:

  • 为什么不尝试使用deep_dup 而不是dup

标签: ruby-on-rails ruby activerecord destroy


【解决方案1】:

.dup 在这里复制了ActiveRecord::Relation,这更像是对记录的延迟加载引用,而不是记录本身。

因此,当您执行new_item = @user.items.new(item_params) 时,您仍在修改集合。

相反,您可以这样做:

def my_method
  new_item = @user.items.new(item_params)
  if new_item.save
     @user.items.where.not(id: new_item.id).destroy_all
  end
end

但如果用户只能拥有一项,为什么要使用has_many 而不是has_one 关系?

您可能还想研究使用nested attributes

class User
  has_many :items
  accepts_nested_attributes_for :items, allow_destroy: true
end

class Item
  belongs_to :user
end

这样你就可以做到:

User.find(1).update(items_attributes: [
  { id: 1, _destroy: "1" },
  { name: 'Bob' }
])

此示例将删除项目 1 并创建一个名为 Bob 的新项目。这使得创建表单输入变得容易,让用户决定保留/销毁哪些记录。

【讨论】:

    【解决方案2】:

    另一种解决方案是为每个名为“is_new”的记录使用布尔字段。

    所有记录都是通过设置is_new = true 创建的,但在保存之前,我们会找到旧记录并使用以下命令销毁它们: @user.items.where(is_new: true).destroy_all 或者如果您不需要销毁它们,请将它们设置为 false。

    【讨论】:

      【解决方案3】:

      根据您想走的路,有很多可能性。一种方法可能是这个:

      def my_method
        old_items = get_old_items_ids
      
        new_item = @user.items.new(item_params)
      
        if new_item.save
          old_items.delete_old_items 
        end
      end
      
      def get_old_items_ids
        @user.items.pluck(:id)
      end
      
      def delete_old_items(old_item_ids)
        Items.where(:id => old_item_ids).destroy_all
      end
      

      另一种方法是比较 created_at 的时间戳,然后删除之前创建的时间戳。

      【讨论】:

        【解决方案4】:
        def my_method
          ##create new and delete all except new one
           new_item = @user.items.new(item_params)
          ##any condition that you want to compare
           @user.items.where.not(:item_name=> new_item.name ).destroy_all
        
        end
        

        【讨论】:

        • Enumerable#delete_if 仅从数组中删除项目 - 而不是从数据库中删除。它的别名是reject_if
        • 还是不行。 new_item 在插入数据库之前没有 ID。在删除其他人之前,您也没有检查new_item 是否有效。如果您不确定,您应该考虑启动一个 Rails 应用程序并实际测试您的答案。如果你发布一些真正有效的东西,我会投票赞成。
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-08-04
        • 2012-10-01
        • 1970-01-01
        相关资源
        最近更新 更多