【问题标题】:How would I destroy_all or delete_all records except one in ruby on rails?除了 ruby​​ on rails 中的一条记录之外,我将如何销毁_all 或 delete_all 记录?
【发布时间】:2012-03-12 08:04:40
【问题描述】:

我在我的网站上为我的用户消息线程功能使用“acts_as_tree”插件。我有一种方法可以删除选定的消息。这些消息实际上并没有被删除。他们的 sender_status 或 recipient_status 列设置为 1,具体取决于哪个用户是邮件的发件人或收件人。

无论如何,如果两个用户都将这些状态设置为一个,那么最后一行确保消息行完全从数据库中移出。现在这很好,只要它不是被删除的父消息。如果父消息被删除,那么未被选中删除的子消息将无法再访问。

方法如下:

        def delete_all_users_selected_messages(message_ids, user_id, parent_id)
          Message.where(:id => message_ids, :sender_id => user_id).update_all(:sender_status => 1)
          Message.where(:id => message_ids, :recipient_id => user_id).update_all(:recipient_status => 1)
          Message.delete_all(:sender_status => 1, :recipient_status => 1, :parent_id => parent_id).where("id != ?", parent_id)
        end

我想要做什么很明显。我需要忽略父母。因此,主键等于 parent_id 意味着该行是父级(通常 parent_id 为 nil,但我需要将其设置为主键值出于其他原因,长篇大论,并不重要)。无论如何,我可以在 tat 方法的最后一行末尾添加一条 SQL 语句吗?确保它只删除行的 id 不等于 parent_id 的消息?

我可以安排永远不允许删除 parent_id 行,除非实际线程(引用消息表对话的 MessageThreads 表)被删除。

我怎样才能做到这一点,以便在运行 delete_all 方法时忽略该父行?

亲切的问候

【问题讨论】:

    标签: ruby-on-rails ruby ruby-on-rails-3 ruby-on-rails-3.1 rubygems


    【解决方案1】:

    现在在 Rails 4 中,您可以这样做:

    Model.where.not(attr: "something").delete_all
    

    Model.where.not(attr: "something").destroy_all
    

    别忘了区别:

    • destroy_all:关联对象通过调用其destroy 方法与该对象一起被销毁。实例化所有记录并一次销毁它们,因此对于大型数据集,这可能会很慢
    • delete_all:所有关联对象立即销毁,无需调用其destroy 方法。不会调用回调。

    【讨论】:

    • 应该注意,回调不会在delete_all 上触发,所以如果你有依赖项,你希望也被删除,它们不会被删除。使用 destroy_all 代替该需求。
    • 这应该是答案。假设更新到 destroy_all。
    【解决方案2】:

    为什么不使用父记录中的关联,像这样?

    Message.where(:id => parent_id).first
      .children.where(:sender_status => 1, :recipient_status => 1)
      .delete_all
    

    【讨论】:

    • 得到未定义的子方法,所以我尝试了 Message.where(:id => parent_id).first.children.delete_all(:sender_status => 1, :recipient_status => 1) .. 然后得到了错误的数字参数 1 为 0
    • 是的,很抱歉我错过了first。您能否将此链分成多行语句,以便我们找到错误发生的位置?比如先获取父记录,然后调用children....
    • 消息负载 (0.3ms) SELECT messages.* FROM messages WHERE messages.id = 343 LIMIT 1 ArgumentError: wrong number of arguments (1 for 0) 这是来自 Rails 控制台的错误
    • 我运行了这个 Message.where(:id => 343).first.children.delete_all(:sender_status => 1, :recipient_status => 1)
    • 如果选中它仍然会删除父消息
    【解决方案3】:

    这最终对我有用。

    Message.where('id != ? AND parent_id = ?', parent_id, parent_id).where(:sender_status => 1, :recipient_status => 1).delete_all
    

    基本上返回该特定会话的所有消息,除了 id == parent_id 的消息。每当 id == parent_id 这意味着它是一个父消息。

    【讨论】:

      【解决方案4】:

      我会考虑一种稍微不同的方法,让具有has_many 关系的模型具有:dependent => destroy,例如
      User has_many :messages, :dependent => :destroy 这样您就不会遇到您描述的“悬空孤儿记录”问题。

      我会尝试以这种方式处理它,而不是考虑“所有记录除外”。
      我不知道是否有我没有解决的问题,但这就是所描述的问题所要找到的。

      【讨论】:

      • 消息模型有_one message_thread和message_thread模型belongs_to消息模型。我不确定如何用我所做的来实现依赖销毁。我已经将它与我的 microposts 和 cmets 功能一起使用。基本上,当主微博被删除时,它的所有 cmets 也都被删除了。使用这个消息系统,它非常复杂,因为 message_thread 属于消息 .. 如果我调用 message_thread.message 父消息出现如果我调用 message.message_thread 引用对话(消息表中的父和子)的 message_thread 出现。
      • 因此,如果我在消息模型中使用依赖销毁,message_thread 将被删除,父消息将被删除,但不会留下所有子消息吗?另外,如果我以相反的方式执行此操作并删除了 message_thread,它不会只是删除父消息并留下子消息吗?我不太确定acts_as_tree 在后台是如何工作的。
      猜你喜欢
      • 2011-04-26
      • 1970-01-01
      • 1970-01-01
      • 2015-06-01
      • 1970-01-01
      • 2019-06-09
      • 1970-01-01
      • 2012-03-26
      • 1970-01-01
      相关资源
      最近更新 更多