Rails 3.0.3: Faster Active Record plus fixes
Posted by David November 15, 2010 @ 07:34 PM
How about some free speed? Well, here you go. Rails 3.0.3 includes a much faster version of Active Record that reclaims the performance lost when we went from Rails 2.3.x to 3.x and then some. Aaron Patterson has done a phenomenal job benchmarking, tweaking, and tuning the ARel engine that underpins Active Record 3 and the result is Teh Snappy.
You can read more about Aaron’s work in his ARel 2.0 write-up. If you dare, you can also have a look at his RubyConf slides that went over the rewrite and speed-up in even greater detail (warning: there are slides of boys kissing!).
In addition to the free speed, we’ve also included a truckload of minor fixes. So everything just works better and faster. What more can you ask for? Oh, that it’s a drop-in replacement for Rails 3.0—there are no API changes. You got it.
See all the changes on Github. Install the latest version using gem install rails. Or bind yourself to the v3.0.3 tag.
Enjoy!
Note: Active Record 3.0.3 is mistakenly reporting its tiny version as 1 instead of 3. This has no impact on anything you do unless you were specifically checking that tiny version. But if it bothers you lots, it’s fixed on the 3-0-stable branch.

Woot! Next up, removing ActiveRecord all together
I prefer the “less last minute bugs” feature ;-)
Wow! Great, thank guys!
Very nice work + great job to all the rails committers and especially @tenderlove for the great work on ARel 2.
One question: what happened to rails 3.0.2? Was that released and then pulled?
@Zach
seems there were some last minute bugs in 3.0.2 that had to be fixed:
https://github.com/rails/rails/compare/v3.0.2…3-0-stable
Thanks everyone! Could we please get some free weed in the next release?
That’s really great news. Thanks for all the hard work.
Now our ruby projects can run faster!!
http://tech.rawsignal.com
This is totally awesome!
Good work everyone updating ad we speak, can’t wait to get stuck into a fresh 3.0.3 app tonight!
Good work everyone updating ad we speak, can’t wait to get stuck into a fresh 3.0.3 app tonight!
Good work everyone updating ad we speak, can’t wait to get stuck into a fresh 3.0.3 app tonight!
Good work everyone updating ad we speak, can’t wait to get stuck into a fresh 3.0.3 app tonight!
Oh great, the <%== %> construct made it in: no more html_safe and raw() littering my code.
Thanks!
Great work! Exciting!
Really? “warning: boys kissing”?
Just upgraded our app from to 3.0.1 to 3.0.3. Great job, Rails Core!
Just upgraded our app from 3.0.1 to 3.0.3. Great job, Rails Core!
After installing Rails 3.0.3 into a completely new RVM gemset, the “Welcome Aboard” page reports ActiveRecord as still being version 3.0.1 (everything else is 3.0.3). Is this right?
Great work! Exciting! http://www.checkandlearn.com
I’m learning Rails for 2 weeks and I just love it, thanks a lot !
W00t! what happened to 3.0.2?
One gotcha to note with the new ARel: using ‘select’ scope has changed from accepting args* to now only 1 arg, so you need to make your list of columns an array.
Contact.select(:id, :first_name, :last_name).limit(5)
becomes…
Contact.select([:id, :first_name, :last_name]).limit(5)
huiiiiiiiiiiiiiiiii
Whoa! Thanks for free speed! :-)
Jonathan: I’m also getting the “Welcome Aboard” page. In my case I had an existing rails folder I wanted to update, and being a newbie this has left me trying to “fix” it for a long time now.
All the other gems were 3.0.1 and changed to 3.0.3 when I updated the gms and did bundle update/install… and even though the Gemfile.lock says I’m using active record 3.0.3, bundler says im using ar 3.0.3, and I did gem clean to remove 3.0.1, the “about your environment” still insists it is using active record 3.0.1
I’ve given up with it now.
Arel’s select syntax is still primitive if you needd to choose different columsn from different tables. I would like to have something like that:
Book.joins(:langs,:authors).select(:book,:langs=>:name, :authors=>:name.as(:author))
Less homophobia! More great software!
@Hobson I read that as sarcasm, not an ACTUAL warning
Chad, stop being so sensible. This is the internet, dammit!
This is great! Thanks!
This release completely dies when I do any query of the following form:
Account.where(:created_at => 2.months.ago..1.month.ago)
CPU spikes to 99 percent. I tried different models; it seems to happen every time you use the range syntax in a “where” clause. Back to 3.0.1 for now.
To clarify my last comment, it only happened with time fields, and the workaround was easy: just make sure the date furthest in the future comes first.
So, even though this worked in 3.03:
Account.where(:created_at => 2.months.ago..1.month.ago)
you will have to do:
Account.where(:created_at => 1.month.ago..2.months.ago)
Drop-in replacement?
Works in 3.0.1: Model.select(:field_1, :field_2)
but does not work in 3.0.3, I have to: Model.select([:field_1,:field_2])
And lots of issues with Cucumber and Capybara, for example: undefined method `fingerprint’ for #<actiondispatch::http::uploadedfile:0x1e8a430> (NoMethodError)
@tw see https://github.com/thoughtbot/paperclip/issuesearch?state=open&q=fingerprint#issue/346 for more on the ‘fingerprint’ issue
I have problem with running tests on Rails 3.0.3 (JRuby 1.5.5, rvm, Bundler 1.0.6). It works fine for Rails v.3.0.1
rake test:units (in /[..]/jruby-ui) java.util.ConcurrentModificationException at java.util.WeakHashMap$HashIterator.nextEntry(WeakHashMap.java:762) at java.util.WeakHashMap$KeyIterator.next(WeakHashMap.java:795) at org.jruby.Ruby.eachModule(Ruby.java:780) at org.jruby.RubyObjectSpace.each_object(RubyObjectSpace.java:129) at org.jruby.RubyObjectSpace.each_object19(RubyObjectSpace.java:160) at org.jruby.RubyObjectSpace$s_method_0_1$RUBYFRAMEDINVOKER$each_object19.call(org/jruby/RubyObjectSpace$s_method_0_1$RUBYFRAMEDINVOKER$each_object19.gen:65535) at org.jruby.internal.runtime.methods.DynamicMethod.call(DynamicMethod.java:190) at org.jruby.runtime.callsite.CachingCallSite.cacheAndCall(CachingCallSite.java:319) at org.jruby.runtime.callsite.CachingCallSite.callBlock(CachingCallSite.java:157) at org.jruby.runtime.callsite.CachingCallSite.call(CachingCallSite.java:162) at org.jruby.ast.CallOneArgBlockNode.interpret(CallOneArgBlockNode.java:60) at org.jruby.ast.NewlineNode.interpret(NewlineNode.java:104) at org.jruby.ast.BlockNode.interpret(BlockNode.java:71) at org.jruby.internal.runtime.methods.InterpretedMethod.call(InterpretedMethod.java:180) at org.jruby.internal.runtime.methods.DefaultMethod.call(DefaultMethod.java:174) at org.jruby.runtime.callsite.CachingCallSite.cacheAndCall(CachingCallSite.java:309) at org.jruby.runtime.callsite.CachingCallSite.call(CachingCallSite.java:148) at org.jruby.ast.CallOneArgNode.interpret(CallOneArgNode.java:57) at org.jruby.ast.NewlineNode.interpret(NewlineNode.java:104) at org.jruby.ast.BlockNode.interpret(BlockNode.java:71) at org.jruby.runtime.InterpretedBlock.evalBlockBody(InterpretedBlock.java:373) at org.jruby.runtime.InterpretedBlock.yield(InterpretedBlock.java:327) at org.jruby.runtime.BlockBody.call(BlockBody.java:78) at org.jruby.runtime.Block.call(Block.java:89) at org.jruby.RubyProc.call(RubyProc.java:224) at org.jruby.RubyProc.call(RubyProc.java:203) at org.jruby.RubyProc$i_method_0_0$RUBYFRAMEDINVOKER$call.call(org/jruby/RubyProc$i_method_0_0$RUBYFRAMEDINVOKER$call.gen:65535) at org.jruby.internal.runtime.methods.DynamicMethod.call(DynamicMethod.java:190) at org.jruby.internal.runtime.methods.DynamicMethod.call(DynamicMethod.java:186) at org.jruby.runtime.callsite.CachingCallSite.cacheAndCall(CachingCallSite.java:309) at org.jruby.runtime.callsite.CachingCallSite.call(CachingCallSite.java:148) at org.jruby.ast.CallOneArgNode.interpret(CallOneArgNode.java:57) at org.jruby.ast.InstAsgnNode.interpret(InstAsgnNode.java:95) at org.jruby.ast.NewlineNode.interpret(NewlineNode.java:104) at org.jruby.ast.BlockNode.interpret(BlockNode.java:71) at org.jruby.internal.runtime.methods.InterpretedMethod.call(InterpretedMethod.java:139) at org.jruby.internal.runtime.methods.DefaultMethod.call(DefaultMethod.java:158) at org.jruby.runtime.callsite.CachingCallSite.cacheAndCall(CachingCallSite.java:289) at org.jruby.runtime.callsite.CachingCallSite.call(CachingCallSite.java:108) at org.jruby.ast.CallNoArgNode.interpret(CallNoArgNode.java:61) at org.jruby.ast.NewlineNode.interpret(NewlineNode.java:104) at org.jruby.ast.BlockNode.interpret(BlockNode.java:71) at org.jruby.internal.runtime.methods.InterpretedMethod.call(InterpretedMethod.java:139) at org.jruby.internal.runtime.methods.DefaultMethod.call(DefaultMethod.java:158) at org.jruby.runtime.callsite.CachingCallSite.cacheAndCall(CachingCallSite.java:289) at org.jruby.runtime.callsite.CachingCallSite.call(CachingCallSite.java:108) at org.jruby.ast.CallNoArgNode.interpret(CallNoArgNode.java:61) at org.jruby.ast.CallOneArgNode.interpret(CallOneArgNode.java:57) at org.jruby.ast.NewlineNode.interpret(NewlineNode.java:104) at org.jruby.ast.IfNode.interpret(IfNode.java:119) at org.jruby.ast.NewlineNode.interpret(NewlineNode.java:104) at org.jruby.runtime.InterpretedBlock.evalBlockBody(InterpretedBlock.java:373) at org.jruby.runtime.InterpretedBlock.yield(InterpretedBlock.java:327) at org.jruby.runtime.BlockBody.call(BlockBody.java:78) at org.jruby.runtime.Block.call(Block.java:89) at org.jruby.RubyProc.call(RubyProc.java:224) at org.jruby.RubyProc.call(RubyProc.java:207) at org.jruby.Ruby.tearDown(Ruby.java:2808) at org.jruby.Ruby.tearDown(Ruby.java:2795) at org.jruby.Main.run(Main.java:288) at org.jruby.Main.run(Main.java:128) at org.jruby.util.ShellLauncher$ScriptThreadProcess.run(ShellLauncher.java:136) at java.lang.Thread.run(Thread.java:619) rake aborted! Command failed with status (-1): [/home/skurcab/.rvm/rubies/jruby-1.5.5/bin/...]
i am going back to 3.0.1. Too much CPU used /w AR.
I’m getting unknown column in ‘having clause’ errors for columns that exist in 3.0.3, no problem on 3.0.1, seems like the promise of “everything just works better and faster” was too good to be true after all
I’m getting unknown column in ‘having clause’ errors for columns that exist in the db on 3.0.3, no problem on 3.0.1, seems like the promise of “everything just works better and faster” was too good to be true after all
@Caleb, I was running into the same problem.
It wasn’t hard to fix; see the lighthouse ticket I created for it. Maybe the solution will help you until it is fixed in ARel: https://rails.lighthouseapp.com/projects/8994/tickets/5992-extreme-performance-problem-with-activerecord-queries-with-date-ranges-in-ruby-18#ticket-5992-2
“Oh, that it’s a drop-in replacement for Rails 3.0—there are no API changes”
This is bullshit! Rails 3.0.3 cannot use MyModel.select(:a,:b) anymore, it has to be MyModel.select([:a,:b]) now! If it is not the change of API what is that?
Rails 3 is great, but you should consider Sequel as ORM, much better imo.
@hipertracker about bullshit… It’s not so hard to make some little changes in your application to fix this issue. You should be thankful for all these people who work on Rails to make it better – they do a great work. Don’t comlain! If you don’t like something – don’t use it and go back to php… :)
@sigirello: OMG, what a moron… is it difficult to read with understanding? That statement “there are no API changes” is just not true. This is API change and that change is harmfull because it is not backward compatible!
Model.select(‘a, b, c’) is working fine for me. Model.select(‘a’, ‘b’, ‘c’) is not. No big deal… I’ve been coding select args the first way anyway.
Aaron, thanks for the great job!
@sigerello: I am VERY thanful for all these people, but I agree with @hipertracker and @Jon – simply do not write: “drop-in replacement”. Be sorry, be transparent.
File upload changes between Rails 3.0.1 and Rails 3.0.3 are not backwards compatible. The UploadedFile class was refactored to not inherit from Tempfile and doesn’t expose the path and open methods anymore, see: http://marklunds.com/articles/one/433
Omg it’s so fast it looks fake :D For me it runs like 8-10 times faster. I’m going out to get drunk.
@Peter Marklund you have right. That is another broken backwards compatibility change! That 3.0.3 update is a disaster. I have just had to fix two sites because of that “drop-in place replacement”.
What idiots change public API without any warnings and and lying that nothing has been changed? This should not be acceptable!
I have just had to fix two sites because of that “drop-in place replacement”.
What idiots change public API without any warnings and and lying that nothing has been changed?
Probably the same kind of idiots that use a new release straight off from upstream on two production sites without testing it first…
I, mean, OK, there was an API change or two and the announcement was misleading.
On the other hand, would it hurt you to TEST it first, or wait a few days until such problems are spotted and corrected?
Even if it has NO API CHANGE WHATSOEVER, the wise thing to do is check. People makes mistakes you know…
Well, this release is a failure. It breaks the public API of UploadedFile. My app stopped working because I use dm-paperclip and I had to patch it to make it work again, also, my spec suite was broken because it relies on the uploaded file public API. So, it’s not how it was supposed to be, the rails team promised to never break public APIs with a minor upgrade (which was a common “practice” in rails 1.x and 2.x times) and I was really hoping it won’t happen again with rails 3.x series. Please be more responsible with your changes…thank you.
@jonathon, @luke:
The issue with the About Your Environment showing Active Record 3.0.1 is because the activerecord version.rb file was not updated for the 3.0.2 or 3.0.3 release.
It is just an annoying visual glitch – your Gemfile.lock file should indicate you are using 3.0.3.
@foljs: There is no need for users to write additional tests for Rails public API, this should be tested by core team first, don’t you think? Anyway, just to not do it again, please.
thanks for this, faster is always good
Regarding API change: maybe it is worth reporting as a bug?
It seems to me that the Rails way is to relax the restrictions on the methods arguments.
Also it is pretty inconsistent with other query methods that have preserved (*args) signature.
I for one am very happy with this release. As usual, the people who contribute the least to the community probably whine the most. I just wanted to thank the Rails team for their tireless efforts, regardless of how much people moan and cry when they have to do a bit more work for a release than was advertised. I’m sure DHH and crew didn’t intentionally mislead anyone, sometimes bugs and small changes just slip through. It’s the nature of the game.
yeah the no API change claim was a little bit off. but foljs is right, you folks do test this stuff before deploying, right? create a new git branch, make changes until all is good, and the merge back and deploy. yeesh.
Also changed: some html_safe things changed on me, I had to do escape several strings I didn’t have to before.
Also, I encountered an error “You cannot call create unless the parent is saved” that didn’t not exist before. not too hard to fix, but hardly drop-in replacement.
I have never seen a more disjoint development effort by any bunch of people.
EVERY THING is Broken
-the default behavior of everything is changed.First you messed with getting mysql out and puting sqllite3 in .. now you have made it even more difficult with upgrades.
It appears to me that there are a bunch of mad guys who just want to push releases out without any care for people who are trying to USE this stuff.
it’s not enough that base language is changing all the time .. now the application frame work .. package manager—supported packages are all in flux … I am sure some of you will rot in hell some day ..
Wondering if Rails 4 will still be using the same stack as Rails 1 or finally shift away from Test Unit, Active Record etc. Time to start moving on IMO.
Every cloud has a silver lining.*
Thank you Rails team! I AM GRATEFUL! Upgrading MANY sites, tests all pass! Deploying now.
To the Whiners: It hasn’t taken me much effort to keep up a dozen big Rails projects for several companies thru many upgrades. You’re getting really great stuff for free. If you’re having big problems, maybe a closer look at your coding style might be useful. As far as Rails is concerned, if you want it to be done better, join the team and make it better.
Since I use fragment caching the performance gain was not so huge, however I had a very bad time because the FileUpoad incompatibility.
I did tests before upgrade however I am not sure I have to test he core system at every minor release.
Please don’t do such thing anymore.
I appreciate your warning about pictures in the slides. Kissing in general is an intimate thing, not a public thing, let alone that kind of kissing. People have lost a sense of dignity and decency. But anyway it’s good to know there are performance improvements to ActiveRecord without it requiring code rewrite.
@MichaelG People are not whining. People simply point out that Rails3 was suppose to follow certain conventions which didn’t happen with the latest release. Stop writing stupid arguments like “fix it yourself, it’s for free, you should be happy”. I don’t care if an upgrade takes 3 minutes or half a day however my clients do care. If I want to make an upgrade to a newest bug-fix release b/c of the, well, fixed bugs then I do not want to waste my clients money by fixing file upload that was not supposed to broken.
If you are working on a project that is used by others then you should be responsible for the changes you make. That’s really it.
Now go here http://yehudakatz.com/2008/12/23/rails-and-merb-merge/ and scroll to the section about “public API” :P
Its time to stop shouting at each other and start finding ways to avoid it in future. I’ll start with my suggestion. May be our community must spend a little more time and resource in regression tests covering backward compatibility.May be some nice regression scripts should be automated to be run periodically. May be a nightly run of regression scripts on the main branch should do. Backward compatibility should be followed strictly !!!.
Very exciting. It just gets better and better!
www.discoposse.com
Tests or no tests, it’s been more than a week, and this post is linked from the front page of rubyonrails.org – would a simple update to the post correcting the “drop-in replacement” part be too much to ask, or am I just inviting a bunch of “would it kill you to read all the comments on the post” responses?
Thanks, hava a good job
I second what @Jason said – there should be an edit in the original description saying that it’s mostly a drop-in replacement, with warnings, caveat emptor.
Obviously, the team thought it was drop-in. Probably did their best to make sure it was drop-in. But oopsies happen. The responsible thing is to make sure that users know about them.
Edit the original post!
@solnic I think like you.
Someone to change this post to include some warning for the others.
Please read this article: Database Applications for Ruby On Rails
Excellent job! Nearly 45% overall performance improvement. I’m very happy!
Making a mistake is not a big deal. We all are humans. Mistakes happen.
Not being able to edit the main blog post for such a popular software, even when the post is very misleading and may cause problems, even weeks after it turned out is the real issue here.