Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How would I destroy_all or delete_all records except one in ruby on rails?

I'm using "acts_as_tree" plugin for my user messaging thread feature on my website. I have a method that makes deleting selected messages possible. The messages don't actually get deleted. Their sender_status or recipient_status columns get set to 1 depending on what user is the sender or recipient of the message.

Anyway if both users have those status's set to one then that last line makes sure the message row is completely moved from the database. Now this is fine as long as it's not the parent message being deleted. If the parent message deleted then the children that haven't been selected for deletion won't be accessible anymore.

Here is the method:

        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

It's quite obvious what I'm trying to do. I need to have the parent ignored. So where the primary key is equal to the parent_id means that row is a parent (normally the parent_id is nil but I needed it set to the primary keys value for some other reason, long story and not important). Anyway is there an SQL statement I can add on to the end of the last line in tat method? To make sure it only deletes messages where the id of the row is not equal to the parent_id?

I can arrange for the parent_id row to never be permitted for deletion unless the actual thread (MessageThreads table that references the messages tables conversations) is deleted.

Any way how can I make it so this parent row is ignored when that delete_all method is run?

Kind regards

like image 578
LondonGuy Avatar asked Feb 22 '12 00:02

LondonGuy


People also ask

What is the difference between delete and destroy in Rails?

Basically destroy runs any callbacks on the model while delete doesn't. Deletes the record in the database and freezes this instance to reflect that no changes should be made (since they can't be persisted). Returns the frozen instance.

What does Destroy_all return?

Method: ActiveRecord::Relation#destroy_all Returns the collection of objects that were destroyed; each will be frozen, to reflect that no changes should be made (since they can't be persisted).


2 Answers

Nowadays in Rails 4, you can do:

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

and

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

And don't forget about difference:

  • destroy_all: The associated objects are destroyed alongside this object by calling their destroy method. Instantiates all the records and destroys them one at a time, so with a large dataset, this could be slow
  • delete_all: All associated objects are destroyed immediately without calling their destroy method. Callbacks are not called.
like image 73
igmarin Avatar answered Sep 21 '22 17:09

igmarin


Why not use association from the parent record, something like this?

Message.where(:id => parent_id).first
  .children.where(:sender_status => 1, :recipient_status => 1)
  .delete_all
like image 33
James Chen Avatar answered Sep 21 '22 17:09

James Chen