If you’ve spent any time doing Rails, you’ve undoubtably had a moment where you were doing project work in a specific version and upgrading to the latest and greatest was out of the question. This happened to me while working on a multitude of (at the time) greenfield projects that started life in the days of Rails 3. When Rails 4 shipped, the team made a decision NOT to upgrade due to the lack of value provided by the upgrade.
I’ve recently had exposure to a Rails 4.1 project and would like to share my experiences on upgrading my mind to think in Rails 4 conventions.
Starting up with Rails 4 is as simple ever. Let’s see what happens when a new project is generated.
$ rails new hello_rails4
The generated Gemfile is a lot cleaner than what you were used to with older versions of Rails. Gone are the
assets group and other stuff that made it feel cluttered.
One interesting addition is this line:
# Spring speeds up development by keeping your application running in the background. Read more: https://github.com/jonleighton/spring gem 'spring', group: :development
The spring gem really does speed up development. It loads the Rails environment only once when running rake tasks, for example, that used to take forever. I’ve been using the zeus gem for this, but the spring gem is built-in and feels much more lightweight.
To set it up, all you have to do is run this command
$ bundle exec spring binstub --all
and run your commands from the ./bin directory. If you’re like me and tire of specifying “./bin” for these commands, you can install direnv (via homebrew if you’re on a Mac) and add this line to a .envrc file in the project.
Now, you can try running
rake. The first time you have to wait as usual, but subsequent calls are instantaneous.
If you use rspec and cucumber for your tests, you’ll also want to add spring-commands-rspec and spring-commands-cucumber to your Gemfile.
gem "spring-commands-rspec" gem "spring-commands-cucumber"
You’ll need to rebuild your binstubs for it to take effect.
$ bundle exec spring binstub --all
When you do, you’ll experience the same speed-up running your tests as you do with running other Rails tasks.
If you like a good controversy, Turbolinks is one one of the most debated features to hit Rails since the asset pipeline. Just like the asset pipeline, turning it off is no big deal, so the controversy is (again) unfounded.
If you decide to use turbolinks, you may run into the some gotchas. I know I did and it took me a while to figure them out.
jQuery DOM loaded
When using turbolinks, you don’t always get the jQuery “DOM loaded” event when the page changes. Remember, the page is loaded only once and subsequent requests only refresh the page content.
jQuery -> $('.fancybox').fancybox()
To fix this, you need to bind to two events. The original DOM loaded event and a new
$(document).on 'ready page:load', -> $('.fancybox').fancybox()
When you run into issues with Rails 4.1, it’s usually with 3rd party libraries and gems that haven’t been updated and presume a clean slate everytime a page is shown.
I’ve had a problem with the recaptcha gem where the captcha would load fine when the page was refreshed, but did not display at all when a turbolink to the page was clicked. Often, in cases like this, you’ll find an issue with the authors of the library discussing options for using it with turbolinks. In this particular case, the form helper has to have ajax enabled:
recaptcha_tags ajax: true
Turning It Off
When you encounter a problem for which there is no easy fix, there is always the option to turn turbolinks off for a single page. Simple add a
data-no-turbolink attribute to the link. The page will now load via a standard request.
To disable turbolinks completely you have to:
gem 'turbolinks'from you Gemfile
//= require turbolinksfrom application.js
Rails 4 Configuration and Heroku
In Rails 3, there are a lot of ways to perform application configuration. From the simple-but-broken
if Rails.env.production Braintree::Configuration.environment = :production Braintree::Configuration.merchant_id = "merchant_id" Braintree::Configuration.public_key = "public_key" Braintree::Configuration.private_key = "private_key" else Braintree::Configuration.environment = :sandbox Braintree::Configuration.merchant_id = "sandbox_merchant_id" Braintree::Configuration.public_key = "sandbox_public_key" Braintree::Configuration.private_key = "sandbox_private_key" end
to loading application configuration files yourself, like Ryan Bates descibes in his railscast #85 YAML Configuration.
None of these ever seemed appropriate, especially when Heroku is your deployment platform. Heroku’s use of environment variables is a good design decision, but we’re Rails developers and we’re lazy. The “good” kind of lazy, so we’ve settled on using the figaro gem.
I’m not going to go deep into how the gem works (the docs for it are great). Suffice it to say that the figaro gem provides best of both worlds:
- Simplicity to have the configuration in files you control and not have them checked inside source control. We’re lazy so no more fiddling with loading environment variables is a good thing.
- Power to deploy and have real environment variables kick in on Heroku.
I could have continued using figaro with Rails 4, but since I came across this article by the author of the figaro gem, I’ve wanted to use the built-in functionality in Rails 4.1 – secrets.yml.
Not having to install yet another gem to handle something the framework should have included from the start is always a win in my book. To be fair, the built-in functionality is not the most feature rich. If you’re doing manual configuration of app servers, copying secrets.yml files may be an option, but if you want to deploy to Heroku, you have a problem since Heroku uses environment variables.
Hopefully the environment variable issue will get addressed sometime in the near future. In the meantime, I’m going to be adding this lightweight extension for the secrets.yml feature in Rails 4.1:
gem 'heroku_secrets', github: 'alexpeattie/heroku_secrets'
To use it, create a config/secrets.yml file. Notice you can use anchor and reference syntax to DRY it up a little.
default: &default recaptcha_public_key: "" recaptcha_private_key: "" development: <<: *default secret_key_base: '' test: <<: *default secret_key_base: '' production: <<: *default secret_key_base: '' google_analytics_code: '' smtp_username: 'email@example.com' smtp_password: 'xxx' smtp_domain: 'example.com' smtp_address: 'smtp.example.com'
You can have the gem copy your production configuration to Heroku via a rake task and automatically pick up the variables:
$ rake heroku:secrets[heroku_app_name] RAILS_ENV=production
And that’s it! You now have your app configured and can use Rails to do your configuration for you
Braintree::Configuration.environment = Rails.application.secrets.braintree_environment Braintree::Configuration.merchant_id = Rails.application.secrets.braintree_merchant_id Braintree::Configuration.public_key = Rails.application.secrets.braintree_public_key Braintree::Configuration.private_key = Rails.application.secrets.private_key
Don’t forget to add this file to your .gitignore file, as Rails isn’t doing that by default yet.
Rails 4 is a much easier upgrade that its predecessor. Most of the changes are in the form of new features that (if used properly) enhance your life as a developer. Opting out is easier than ever if something isn’t working for your particular situation.
This article sums up what I went through while trying to upgrade my thinking to the latest and greatest. You can always dig deeper when you read the documentation, but, hopefully, this article gives you a good start.