Rails Bug With Has Many Collections Empty? and Build

After my long rant about problems in Ruby on Rails has_many collections and empty? calls, we spent some more time and really condensed the problem. I can explain this problem much more clearly now.

Let's take the following code:


f = Foo.new
f.bars.build
f.bars.empty?
pp f.bars


What do you think will be printed out when we pp f.bars?

Well, if you're like me, you'd think it would return an array with one Bar in it. And, if you were like me, you'd be wrong.

Turns out that the call to f.bars.empty? doesn't realize you've ever added a new Bar to the collection of bars. Therefore, it will go into the database and do a select count(*) to determine the size of the collection. It will return zero, because at this point you haven't saved anything into the database. Not only is going to the database to determine the size of the collection wrong (in the line above, I've added a Bar though build so empty? should know there's at least one), but empty? in the process is caching the empty collection!

Because of this caching, our last line of code here is printing out an empty array. This effectively deletes the original Bar we added via build.

This has to be a bug. In fact, I'm filing a bug at Rails' Trac system.

How do you work around this? Just change your usage of empty? to length.zero?:


f = Foo.new
f.bars.build
f.bars.length.zero?
pp f.bars


The above code will work just fine!

Many thanks to Wenyi for researching this with me.

Popular posts from this blog

Lists and arrays in Dart

Converting Array to List in Scala

Null-aware operators in Dart