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 answer开发者_C百科s in advance.
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
).
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.
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.
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.
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.
精彩评论