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.

Posted in Releases | 73 comments

Comments

  1. Frank Lakatos on 16 Nov 16:38:

    Woot! Next up, removing ActiveRecord all together

  2. Roland on 16 Nov 16:39:

    I prefer the “less last minute bugs” feature ;-)

  3. Reuben on 16 Nov 16:40:

    Wow! Great, thank guys!

  4. Zach Bailey on 16 Nov 16:41:

    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?

  5. Roland on 16 Nov 16:44:

    @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

  6. straydog on 16 Nov 16:55:

    Thanks everyone! Could we please get some free weed in the next release?

  7. Troy on 16 Nov 17:05:

    That’s really great news. Thanks for all the hard work.

    Now our ruby projects can run faster!!

    http://tech.rawsignal.com

  8. Louis Galipeau on 16 Nov 17:08:

    This is totally awesome!

  9. Adagio Ingenuitea on 16 Nov 17:31:

    Good work everyone updating ad we speak, can’t wait to get stuck into a fresh 3.0.3 app tonight!

  10. Adagio Ingenuitea on 16 Nov 17:31:

    Good work everyone updating ad we speak, can’t wait to get stuck into a fresh 3.0.3 app tonight!

  11. Adagio Ingenuitea on 16 Nov 17:31:

    Good work everyone updating ad we speak, can’t wait to get stuck into a fresh 3.0.3 app tonight!

  12. Adagio Ingenuitea on 16 Nov 17:31:

    Good work everyone updating ad we speak, can’t wait to get stuck into a fresh 3.0.3 app tonight!

  13. Jan M. on 16 Nov 18:04:

    Oh great, the <%== %> construct made it in: no more html_safe and raw() littering my code.

    Thanks!

  14. Tobi Knaup on 16 Nov 18:22:

    Great work! Exciting!

  15. Judson on 16 Nov 18:24:

    Really? “warning: boys kissing”?

  16. Jon on 16 Nov 18:30:

    Just upgraded our app from to 3.0.1 to 3.0.3. Great job, Rails Core!

  17. Jon Atack on 16 Nov 18:31:

    Just upgraded our app from 3.0.1 to 3.0.3. Great job, Rails Core!

  18. Jonathan on 16 Nov 18:39:

    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?

  19. maxy on 16 Nov 20:02:

    Great work! Exciting! http://www.checkandlearn.com

  20. Matt on 16 Nov 20:10:

    I’m learning Rails for 2 weeks and I just love it, thanks a lot !

  21. Jones Lee on 16 Nov 21:35:

    W00t! what happened to 3.0.2?

  22. spovich on 16 Nov 21:47:

    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)

  23. marcel on 16 Nov 23:33:

    huiiiiiiiiiiiiiiiii

  24. Misha on 17 Nov 00:05:

    Whoa! Thanks for free speed! :-)

  25. Luke on 17 Nov 00:06:

    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.

  26. hipertracker on 17 Nov 00:12:

    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))

  27. Hobson on 17 Nov 00:56:

    Less homophobia! More great software!

  28. Chad Fowler on 17 Nov 01:43:

    @Hobson I read that as sarcasm, not an ACTUAL warning

  29. DHH on 17 Nov 03:52:

    Chad, stop being so sensible. This is the internet, dammit!

  30. Morgan Currie on 17 Nov 04:04:

    This is great! Thanks!

  31. Caleb Perkins on 17 Nov 05:52:

    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.

  32. Caleb Perkins on 17 Nov 06:03:

    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)

  33. tw on 17 Nov 08:20:

    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)

  34. Niall on 17 Nov 09:33:

    @tw see https://github.com/thoughtbot/paperclip/issuesearch?state=open&q=fingerprint#issue/346 for more on the ‘fingerprint’ issue

  35. Szymon Kurcab on 17 Nov 10:27:

    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/...]

  36. Jones Lee on 17 Nov 11:34:

    i am going back to 3.0.1. Too much CPU used /w AR.

  37. Donald Piret on 17 Nov 14:23:

    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

  38. Donald Piret on 17 Nov 14:24:

    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

  39. Rolf Timmermans on 17 Nov 15:12:

    @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

  40. hipertracker on 17 Nov 16:01:

    “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?

  41. Rails3 fan on 17 Nov 16:33:

    Rails 3 is great, but you should consider Sequel as ORM, much better imo.

  42. sigerello on 17 Nov 20:57:

    @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… :)

  43. hipertracker on 17 Nov 22:15:

    @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!

  44. Jon on 17 Nov 23:47:

    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.

  45. mikhailov on 18 Nov 04:18:

    Aaron, thanks for the great job!

  46. tw on 18 Nov 08:14:

    @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.

  47. Peter Marklund on 18 Nov 09:57:

    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

  48. The_Lord on 18 Nov 13:33:

    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.

  49. hipertracker on 18 Nov 15:13:

    @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!

  50. foljs on 18 Nov 17:17:

    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…

  51. solnic on 18 Nov 17:23:

    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.

  52. eric on 18 Nov 17:36:

    @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.

  53. hipertracker on 18 Nov 22:48:

    @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.

  54. stephen murdoch on 19 Nov 01:53:

    thanks for this, faster is always good

  55. vkh on 19 Nov 04:16:

    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.

  56. Craig Knox on 20 Nov 00:46:

    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.

  57. DGM on 20 Nov 18:43:

    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.

  58. SMS on 21 Nov 06:21:

    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 ..

  59. Kristian on 21 Nov 20:12:

    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.

  60. Chaussure Jordan on 23 Nov 03:26:

    Every cloud has a silver lining.*

  61. MichaelG on 23 Nov 21:32:

    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.

  62. Mage on 23 Nov 23:12:

    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.

  63. Michael Nissim on 24 Nov 07:25:

    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.

  64. solnic on 24 Nov 20:13:

    @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

  65. Saran on 25 Nov 16:56:

    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 !!!.

  66. Eric on 25 Nov 17:27:

    Very exciting. It just gets better and better!

    www.discoposse.com

  67. Jason on 27 Nov 04:49:

    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?

  68. Kewin on 27 Nov 07:14:

    Thanks, hava a good job

  69. Cosmo on 01 Dec 22:01:

    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!

  70. Gudata on 06 Dec 11:21:

    @solnic I think like you.

    Someone to change this post to include some warning for the others.

  71. Krishna on 08 Dec 02:58:

    Please read this article: Database Applications for Ruby On Rails

  72. wout on 08 Dec 16:53:

    Excellent job! Nearly 45% overall performance improvement. I’m very happy!

  73. Mage on 08 Dec 23:11:

    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.