Testing Against Multiple Rails Versions

Upgrading major versions of Rails sucks. I was there from 0.9 to 1.0, all the way to the famed 2 to 3 release, and they were all painful. I have good news though: Rails 4 is right around the corner, and it’s a much cleaner upgrade. While you are getting your app ready for Rails 4 are you bringing the gems you’ve written up to speed? If the answer is “I don’t know”, keep reading - we will cover how to test the gems you’ve written against multiple versions of Rails including Rails 4 release candidate.

Multiple Versions Matter

Believe it or not, there are still a large number of people who are using Rails 2 in production today. While the path to upgrading to Rails 3 is well documented (there’s a whole book on it) often the biggest blocker isn’t the app, or even the Rails frameworks. The largest hurdle to upgrading is often an un-maintained third party library that can’t be replaced or re-written and doesn’t work in the latest versions. There are many reasons to quit maintaining a library, but “I didn’t know how to upgrade it to support the latest rails release” shouldn’t be one of them.

Testing your App

Step zero is writing tests for your gem if you don’t already have them, once you’re done with that: make sure you’ve got a CI server running, I prefer Travis CI which is free for open source repos. Once you’ve got your CI build green, you’ll need to re-work your Gemfile so you can install multiple versions of Rails and then set up Travis to run your tests multiple times, each with a different version of Rails.

Make Ready your Gemfile

If you you haven’t already, delete your Gemfile.lock and remove it from git:

$ git rm Gemfile.lock

Then ignore the file by adding it to your .gitignore. On a stable app - Gemfile.lock stores the exact version of libraries that are used such as Rails 3.2.13. This is good for normal use, but we need our gem to be able to be bundle install-ed against any version of Rails. Removing the Gemfile.lock allows us to do that.

The next thing we will need to do is to enable your app to load multiple Rails versions from the environment open up your libraries’ Gemfile remove where you’re specifying Rails or railties version:

gem 'rails' '>= 3.1.0'

If it’s in the gemspec, you don’t need to do anything, now add this code

rails_version = ENV["RAILS_VERSION"] || "default"

rails = case rails_version
when "master"
  {github: "rails/rails"}
when "default"
  ">= 3.1.0"
else
  "~> #{rails_version}"
end

gem "rails", rails

Make sure to replace the numeric value in the "default" case with whatever you had specified previously.

Now you can bundle different versions of Rails like so

$ RAILS_VERSION=3.1.0 bundle update
$ RAILS_VERSION=3.1.0 bundle exec rake test

or if you want a one liner:

$ export RAILS_VERSION=3.1.0; bundle update; bundle exec rake test

This will install Rails version ~> 3.1.0 and run tests against it. To run tests against Rails master you can use RAILS_VERSION=master and to run against the betas or release candidates you can run RAILS_VERSION=4.0.0.pre

Now you can run tests on your app using different versions of Rails. You can see an example of this style of Gemfile in my projects oPRO and Wicked. The next step is to configure Travis to automatically do this for you.

Running Multiple Rails Versions on Travis

In your project create a .travis.yml file if you haven’t already. You can add environment variables to your travis run matrix by adding them to this file:

env:
  - "RAILS_VERSION=3.1.0"
  - "RAILS_VERSION=3.2.0"
  - "RAILS_VERSION=4.0.0.pre"
  - "RAILS_VERSION=master"

This will make travis run your project 4x more times each with a different environment specified. While we’re testing against different versions of Rails, let’s make sure we’re testing against different versions of Rubies too. This will test MRI 1.9.3, 2.0.0, and master as well as JRuby in 1.9 mode:

rvm:
  - 1.9.3
  - 2.0.0
  - ruby-head
  - jruby-19mode

Any time you’re testing the head or master of a project such as ruby-head you may see failres because the branch is unstable and not due to your project. For these cases you may want to allow failures until official versions are released.

matrix:
  allow_failures:
    - env: "RAILS_VERSION=master"
    - rvm: ruby-head

This will still run tests against the most recent version of Ruby and against Rails master, but if they fail Travis will not flag the build as failed. If you want to fine tune your allowed failures you can add them together like this:

matrix:
  allow_failures:
    - env: "RAILS_VERSION=3.0.0"
      rvm: 2.0.0

This will allow failures against Rails version 3.0.0 only when using Ruby 2.0.0. You can see the .travis.yml files for oPRO and wicked for full examples.

Test with Pull Requests

Once you’ve got your .travis.yml and Gemfile set up. Commit your results to a branch and push to github:

$ git checkout -b test-rails-4
$ git add .
$ git commit -m "testing rails 4"
$ git push origin test-rails-4

Now go to your repo on Github and open up a pull request like this PR on wicked. If you have PR testing turned on with Travis, this will kick off a build. If you’re lucky all of your required tests will pass and it will look like this:

You can see the Travis build for Wicked here.

If your tests don’t all pass, not to worry: look at the output, reproduce locally, fix, push, and repeat. Sometimes you might not be able to get one version of your library to support all the versions of Rails/Ruby that you need, when that happens you’ve got diverging stable versions.

Diverging Stable Versions

Rails no longer supports version 2.0, but maintains version 3.2+ and 4.0.0.RC1+. Most of your users won’t immediately upgrade to the latest version, and while you’re waiting for them to do so, you may find security or other bugs in a version of your library. For this reason I encourage you to consider supporting at least two versions of Rails. There are a few different strategies you can take in order to accomplish this goal:

Do nothing: If you’re lucky your gem will work unmodified in all versions of Rails, and you’re good to go. Make sure you’re tested, and don’t introduce backwards incompatable changes later down the road.

Branch: Rails uses versions and branches to manage it’s codebase and you can too. If your gem needs a major overhaul to be compliant with the latest release you may want to branch out your codebase. One branch for Rails 3 and you can likely leave Rails 4 on master.

$ git checkout -b rails3

You’ll want to have clearly defined versions for your which version of rails your gem supports. You may want to break semver for a single gem push and shadow Rails versioning. So the Rails3 compatible code can be found in version 3.X and the Rails4 compatible code can be found in 4.X of your gem. Once you do this, release as normal using semver, just avoid rev-ing the major version if you don’t have to.

Separate Gems: If keeping different copies of code in different branches seems too hard, break out your gems into multiple libraries. If your library is named foo consider forking it and making a foo_rails4 gem. While easier on you, it makes it harder for your users to upgrade since they’ll have to know you released a separate gem.

Testing Other Software Versions

You may find that your library depends on other libraries for development or production that have their own dependencies on Rails. One popular library is Devise. You can see how we conditionally change the version of Devise based on our Rails version in oPRO’s Gemfile, I got this little trick from Steve’s work on Draper’s Gemfile.

JRuby Note

While upgrading to Rails 4 I found that a JRuby Gem doesn’t play nice. If you’re testing JRuby and using the JRuby Sqlite3 adapter for ActiveRecord you may need to specify this in your gemfile:

  gem "activerecord-jdbcsqlite3-adapter", '>= 1.3.0.beta', :platform => :jruby

If you’re not testing JRuby in your Travis matrix, why aren’t you? You can always set it as an allowed failure and then at least people who want to know if your lib works with JRuby can check the Travis builds.

The Importance of Release Candidates

Now that you know how to write tests for your libraries to run on multiple versions of Rails, you have no excuse for not having them fully tested and compatible when Rails4 is fully released. It’s important to test against the Release Candidates (RC’s) because these are what will eventually become the fully released version of Rails. If you wait till Rails4 is released and find a bug in the framework, it may be too late to fix. When I was testing Wicked, I found and fixed a regression from 3.2.13 to 4.0.0.RC1. Even better, you’ll know if your library works with Rails4 or not, and so will your users.

If are a connoisseur of Hacker News, you may remember a set of inflammatory comments towards the Rails release team over a number of regressions introduced in a minor version bump of the library. The thing is: there was a release candidate for that minor version and for all of the people who wailed and gnashed their teeth at the regressions, few if any bothered to test against the release candidate. Next time your app gets caught by a regression, ask why you didn’t catch it before that version was released. You could be part of the solution.

Test Today

With bundler and Travis CI testing against multiple versions of Rails couldn’t be easier. Don’t be the maintainer of that one Gem that isn’t compatible with the Rails4 release. Test your gems against all the Rails versions today.

update: @shime_rb pointed out there is a gem called Appraisal to help if you don’t want to manage your Gemfile manually. You can see an example travis.yml with appraisal. Travis also supports specifying multiple gemfiles which is how devise tests against multiple versions of rails .


Richard Schneeman works for Heroku and is married to Ruby, literally. He wrote the easiest way to get started helping in open source: Code Triage. Follow him on twitter @schneems.

cubecul asked: Hi Richard. I love your videos; thanks so much (times a million!). I have a bit of a bigger question to ask. I'm just about to be a junior in college. I'm not studying anything technical. I've fallen in love with programming over the last month and a half. Previously, I just wanted to go into consulting: prestigious and great opportunities ahead. I enjoy that subject matter quite a bit. How can I decide if a career in software is for me? What is the career path/stability/future job titles/etc.?

Happy you’re enjoying them :)

As you may know i’m not a programmer by degree, I have a mechanical engineering BS from georgia tech. You don’t need a degree to get a job, but it is harder to get your first job without one. Not because people care about credentials, just that companies really stink at hiring programmers and may ask you a bunch of horribly lame CS questions in the interview that don’t have anything to do with modern web development.

I spent ~3 years programming Ruby/Rails in college and through my first job before I got my first Rails gig. While everyone is hiring now, it is difficult to find a position looking for junior or new devs. Then if they don’t have the right mentoring programs and experience in place, you may hate working there. For my first job in rails: Gowalla, i got around any interview questions by demoing a fully functioning site (now offline) that did some cool stuf. Then I showed them the repo, and we talked about some of the code. I also gave them ~8+ hours of me giving Rails tutorials…so that helped :)

For consulting: i’ve never done it but I have friends that have. Get involved at a local meetup group. See if you can find other consultants and ask how they got into it. Many that I know share work with one another. I.e. they never turn down a job (lest a door shut) but they might farm off the work to another developer. Look around for a consultant who might be willing to give you a hours of their work a week for a low hourly rate in exchange for pairing/mentoring sessions. 1-on-1 instruction is the fastest way to level up your skills. Go talk to a consultancy agency, they may have a program like this in place already.

If you’re into programming for the money, i say don’t. It’s a lot of time and effort and energy and if you’re not in love with it you will get burned out after a few years making the $$$ even out in the end. Go for it if only you enjoy building, creating, and maintaining meaningful projects. I never meant to learn to program, it just happened that I needed programming to build the things I wanted. The best way to see if this applies to you is to program more and then do the shower test. When you’re taking a shower before your day and getting excited about what you’re going to do, does thinking about programming get you more or less excited.

For career: consultants make tons of money (think 2x what a salary dev makes) but their work is not stable. Typically when a company hires a consultancy it is to do something that no-one at their company wants to do, so you might not be doing the most rewarding work in the world. Salary developers have more ownership and control of what they work on, but there can be little to no variation in the type of projects depending on the size/focus/scope of the company.

For promotions: consultants just raise their rates as they get better. The range I know of right now is anywhere from $80-200 per hour depending on skills and knowledge. Keep in mind they might work 5-80 hours a week depending on how busy they are. Salary workers: you will typically need to ask for a raise like any other job. Titles are typically meaningless. You can be a “senior” engineer at most companies fairly quickly. Other companies have a “flat” architecture and the only difference between engineers is salary. After being a programmer you can go into project management for programmers. While the pay is good here keep in mind a good PM does everything a programmer doesn’t want to: think email…lots of email. If salary isn’t your thing, you can always ask for more vacation, or for extra company time spent working on open source work, or whatever. Most long term programmers make good money, but care more about building and shipping good products than titles and cash.

Ok, so this got a little long. Hope that helps. Try to make community contacts to help with some of these questions, even if you don’t go into consulting…being well networked can only be a good thing. When in doubt go to a Rails meetup. Good question by the way.

iamakimmer asked: You have the best lesson on Rails hands down. Coming from enterprise Java development..I felt that there was so much magic in Rails that other videos tend to skip over. Your through explanations and the Reddit on Rails project really helped to explain many of the details I was really confused about. Thank you!

Glad you enjoyed the lessons :)

mikeholley asked: Hello Richard, I was curious after you worked at Gowalla and used PostgreSQL and now work at Heroku which has MongoDB as an option for users. If you were going to do an app that has data like places as well as user data like posts, checkins which would you use today? Thanks for your response.

Heroku just announced support for postGIS https://devcenter.heroku.com/articles/postgis which helps give you geo location features in your DB. I’ve never used Mongo, so I can’t compare the two. I love postgres though :)

kylegracey asked: Hey man, I just wanted to say thank you for putting the UT rails course online. Seriously. I've tried a couple of different courses, and this is the first one that explains everything clearly and teaches in a way I *understand* and actually *learn* from. So yea, anyways, thank you x1000. If for some reason I ever run into you in the real world, I owe you a beer or three.

Happy to help :)

janezli asked: Dear Richard, I stumbled upon your videos after searching for a way to learn RoR online. Unfortunatey, I have no programming experience at all, and I was completely lost in the second video of week 2 (ActiveRecord). I didn't even know where to start to follow along. Is this intended for beginners with no database/programming knowledge? Finally, I noticed you also have a set of videos in beginner-to-builder-2011. Am I supposed to watch those videos before doing the UT Rails 10 wk course? Thanks!

The course is intended for an audience that has some programming background such as understanding variable assignment and flow control (if/else). If you’re just getting started in any kind of programming i recommend codecademy, either start with Javascript (http://www.codecademy.com/tracks/javascript) or Ruby (http://www.codecademy.com/courses/ruby-beginner-en-MxXx5/0/2).

If you get lost in my course i recommend skipping ahead to the exercises, a good amount of the lecture for the first 1-2 weeks is theory that isn’t used until later.

Git Minutes Podcast Interviews Schneems 

Had a delightful time talking to GitMinutes about workflow, Rails issues, and more. Have a listen and tell me what you think.

Heroku Engineer Engaged to Ruby

It was a long day when @schneems typed $ git push heroku master, opened his website, and exclaimed “I love Ruby!”. Then as if inside of Pee-wee’s Playhouse he heard a voice say: “If you love Ruby so much why don’t you marry her?”. So on December 25th, he got down on one knee with his Grandmother’s engagement ring and proposed to Ruby Ku. She said yes!

You might think that to be the end of the story, dear readers, but it’s just the beginning. Fast forward to March, our young protagonist sits weary on a plane bound for Austin, Tx. He’s been away nearly a month, and has the jet lag to prove it. As he descended the airport escalator, destined to touch foot in the city he calls home, he heard a strange sound. As he lowered, the sound grew, and one-by-one: faces of his friends appeared at the base of the moving steps. As he stepped out he looked for his bride to be, but couldn’t find her. Then his friends part like sea from sky and suddenly…

Did you watch the video?

How are you still reading? Aren’t your eyes filled with tears, and you cheeks cramping from smiling? (I know mine were).

Ruby steps forward holding cue-card style signs. Then, in-time to the boom-box soundtrack, she drops the cards explaining one-by-one why she is in love. As the last card falls she drops to one knee, and with a bottle of 12 year old scotch - proposes to Richard (that’s me). He said yes!

The Couple

Richard met Ruby at a meeting of Austin on Rails when she was learning enough programming to make Hourschool.com. After many awkward moments, false starts, and months of waiting: he stole a kiss after a midnight social (bike) ride. She launched her company, while his got devoured by Facebook. They moved in together, he got a job at Heroku, her company won a design award from core77, and they found the light of their life: Cinco Dog. She sometimes teaches at Austin Center for Design and He sometimes teaches at the University of Texas. They are both massively addicted to coffee, sunny days, and dachshund kisses.

After their mutual proposals, Ruby and Richard will be married on an urban farm in Austin, Tx on April 27th, 2013. Cinco dog remains single and ready to mingle.

The Journey Begins

Tomorrow brings another sunrise, another sunset, and another day of Richard loving Ruby.

Open Source in your Inbox: Code Triage

“I don’t have time to contribute to open source”. But who does? We’re too busy shipping products and open source is so daunting and time consuming. Sure tools and technologies are our livelihood, but there’s just so much there. Even if you’ve got the time - where do you start?

What if giving back wasn’t so overwhelming, so time consuming, so vast and soul crushing? What if you could get bite-sized open source tasks delivered right to your inbox? You could work on them when you get some free time, while learning more about the underlying guts of the code you depend on. Well now you can with: Code Triage.

What is Code Triage?

Code triage sends you one issue a day from your favorite repos:

Code Triage Screenshot

These issues come in one at a time and it could be anything: from a feature request, to a bug report, to code attached to a pull request. It’s up to you to figure out if you can fix, give feedback, or grab someone with more experience. The more you can help, the more free time the software maintainers have.

Do you want:

  • To have your name in the commit log of famous projects?
  • To gain a better understanding of the libraries you’re using?
  • To use less buggy software?
  • To be a better developer?
  • To be a better person?

Then Code Triage is for you.

Maintainers: Increase your Firepower

You’ve got open source libraries? Add your repos to Code Triage and subscribe to them. I’ve a few of my own libraries: Wicked and Sextant to triage. On the rare ocasion when I have issues pile up, I make sure I can work them off at a sustainable pace.

If you know someone interested in your project, suggest that they sign up to triage the repo. Also consider putting a link on your README.

It has already worked well for me. When I first launched Code Triage into Beta, @neilmiddleton helped so much on issues that I gave him commit bit to the github repo. Now he works on the project and sometimes fixes issues before I even get a chance to take a look at them.

In fact it has worked out so well, Neil ended up asking me to co-author a Heroku book. Legal Disclaimer: Code Triage cannot guarantee you co-authorship of an O’Reilly book.

Programmers: Make a Difference

Open up your favorite editor, click “Recently Opened”, and then find a project. Take a good hard look at your dependencies, pick one, and then sign up to triage. It’s really that simple.

The era of “too busy”, “too novice”, and “too lost to start” are over. Now is the time to solve bugs, merge good pull requests, and prevent maintainer burn-out. Together we can do it.

Go make an impact: one issue at a time Code Triage.

Anatomy of an Exploit: An In-depth Look at the Rails YAML Vulnerability

Exploits happens, and this month the Rails and Ruby communities have seen no shortage. From a major exploit in Rails to a slightly different Rubygems.org attack, there has never been a better time to brush up on software security.

Maybe you’re wondering why these vulnerabilities happen in the first place, why they weren’t caught in the first place, or maybe you just want to know the specifics of this attack. We’ll start off by taking a look at the anatomy of a security exploit, and then dive into the gory details of the YAML issue.

Continue Reading…

Next page Something went wrong, try loading again? Loading more posts