Rails 3 upgrade part 3: Code fixes, views, and forms
This is part 3 of my Rails 2 to Rails 3 upgrade experience. Part 1 is about the initial code upgrade and getting the application to boot while part 2 deals with routes. While Part 2 is mainly about routes, getting it work involved changes in other parts of the code which I’ll share this time. So while you are updating your routes, you may need to check this post in between changes.
Update ApplicationController
After regenerating your application with rails (i.e. rails new appname -d dbadapter), your ApplicationController would look like this:
class ApplicationController < ActionController::Base
protect_from_forgery
end
There’s no need to panic because rails:upgrade:backup made a copy of the controller to application_controller.rb.rails2.
If you have a lot of helper modules, you’ll most likely have this code in your Rails 2 ApplicationController:
helper :all
If you encounter a missing method error while monkey clicking your application, you probably forgot to update your Rails 3 ApplicationController.
Update ApplicationHelper
The ApplicationHelper module was also modified by the rails upgrde. So don’t forget to update this, too.
RAILS_* constants are deprecated is not entirely true
When you run rails:upgrade:check, it will list items you need to update including deprecated code. There is no need to change these as the word ‘deprecated’ means but I encountered several “can’t convert nil into String” errors.
rake rails:upgrade:check
(in /mnt/hgfs/greg-mini/dev/projects/propsify)
Deprecated constant(s)
Constants like RAILS_ENV, RAILS_ROOT, and RAILS_DEFAULT_LOGGER are now deprecated.
More information: http://litanyagainstfear.com/blog/2010/02/03/the-rails-module/
The culprits:
...
The weird part is some constants are just doing fine. In any case, here are the conversion:
RAILS_ROOT -> Rails.root RAILS_ENV -> Rails.env RAILS_DEFAULT_LOGGER -> Rails.logger
You can also check your environment the Ruby way:
# before
if RAILS_ENV == 'production'
...
# Rails 3
if Rails.env.production?
Output strings are automatically escaped
We should all be rejoicing that Rails is now serious about XSS protection except now your pages have become ugly with all those HTML tags. For example the code below will not give you a clickable link.
- signup = link_to('create one here', signup_path)
= "If you do not have an account, #{signup}."
To fix this, use the raw() helper.
= raw "If you do not have an account, #{signup}."
Too bad for me, I got tons of views that were coded like this.
Check for ‘concat’
A popular technique to simplify your view code is to use content blocks. You create a helper that takes a block and wraps it in some HTML tags. A simple implementation would look like this:
module LayoutHelper
def main_column(options={}, &block)
# calls column()
end
def column(options={}, &block)
# concat is not needed in Rails 3
concat content_tag(:div, capture(&block), options)
end
end
# in your view
- main_column do
= render 'form'
This works fine in Rails 2 but in Rails 3 the block gets outputted twice. concat is the way to output text in a non-output block (i.e. <% %> in erb) but it seems like erb blocks in Rails 3 do not need concat.
Helpers with blocks
Before Rails 3, form_for or fields_for use non-output syntax; it means no equals sign.
# erb
<% form_for @offer do |f| %>
# ...
<% end %>
# haml
- form_for @offer do |f|
# ...
In Rails 3, it should now be written as an output block.
# erb
<%= form_for @offer do |f| %>
# ...
<% end %>
# haml
= form_for @offer do |f|
= f.fields_for :items do |ff|
# ...
The rule is if the method is expected to return a string, it should use the output syntax. If it just buffering the returned string like content_for, it should NOT have the equals sign.