element119
element119

Reputation: 7625

Why can't I use Record.all.destroy in Rails?

I'm currently beginning to learn Ruby and the Ruby on Rails framework. I've found that in the table records, I can find a record with an id of 5 and delete it by using the following code:

Record.find(5).destroy

This makes sense- I chain methods to find the record and destroy it. However, if I want to destroy all the records in the table, the logical command would be the following, as the all selector selects all the records in the table:

Record.all.destroy

And this returns a NoMethodError! I am aware that I can use Record.destroy_all or Record.delete_all to accomplish this task, however, I'd like to know why I can't just use the most logical choice instead of having to look up things like delete_all. I am new to this framework, so it's entirely possible that I'm missing something fundamental here.

Thanks for any answers in advance.

Upvotes: 7

Views: 4900

Answers (5)

saneshark
saneshark

Reputation: 1243

Actually you can (in a way). Since .all returns an array, and not an active record relation, what exactly would you be deleting? I wouldn't say Record.all.destroy is logical at all -- are you deleting the array object?

One thing you could do is map the resulting array, and since map accepts a proc(&), you can execute that proc for each object in your array.

Record.all.map(&:destroy)

Note, this is going to trigger callbacks on all of your objects, which might be slower than you intended. If you wanted to avoid triggering callbacks you could map the appropriate destructive method instead of destroy. (hint: :delete)

Alternately, you could just do:

Record.destroy_all or Record.delete_all

as you stated in your question.

Upvotes: 0

Marcel Jackwerth
Marcel Jackwerth

Reputation: 54782

It was a design decision. DataMapper took your approach. Being forced to write destroy_all explicitly can be tedious but will also prevent you from doing something you really don't want (i.e. delete everything in a table, like x = User; ...; x.destroy).

Upvotes: 14

user94154
user94154

Reputation: 16584

The most simple way to avoid Record.destroy_all would be Record.all.each {|r| r.destroy}. This may somewhat satisfy your API design preferences, but should be much slower than the first option.

Upvotes: 1

monocle
monocle

Reputation: 5896

When you have

Record.find(5)

this returns a Record object/instance that represents the data in a row in your table. Then you call the #destroy method on that object which is defined by your Record model.

When you have

Record.all

this returns an Array object. In order for you to then call #destroy on the array, you would have to monkey patch Ruby's core Array class to have a #destroy method.

Upvotes: 1

Jits
Jits

Reputation: 9748

I agree it would be logical to be able to do this. Technically speaking, Record.all returns a collection (or proxy to a collection) which doesn't implement the destroy method.

Upvotes: 3

Related Questions