Working with Ruby
Hi, I am Jan. This is my old Ruby blog. I still post about Ruby, but I now do it on idiosyncratic-ruby.com. You should also install Irbtools to improve your IRB.

Upgrading to Rails 3: Obstacles and helper scripts

Transferring an existing project to Rails 3 is not that hard, but it usually cannot be done in 5 minutes.

General upgrade approach

  • Get the rails_xss plugin and adjust your raw helper calls till everything is fine again.
  • Check, if your plugins work at railsplugins.org.
  • Get information about the changes and install the official rails_upgrade plugin. Run rake rails:upgrade:backup to backup important files. Then run rake rails:upgrade:check to analyse your project. The plugin displays useful information for various places where things need to be changed. It also has tasks for creating your Gemfile, updating your routes and configuration. But there is still some manual work required. I have written three little helper scripts that can assist you to solve some tasks.
  • When finished, replace some of the project’s Rails-specific files. You can do this by navigating to your project’s parent directory and running rails my_project_name as if you would want to create a new one. Then pick the files to overwrite.

Upgrade scripts

ERB syntax changes (the upgrade tasks complains about more, but this is wrong)

 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
#!/usr/bin/env ruby

# Upgrades all files in child directories to the new erb snytax in Rails 3
# Does not upgrade custom concatination helpers
# See <https://asciicasts.com/episodes/208-erb-blocks-in-rails-3> for more info

patterns =
%w|
fields_for
form_for
div_for
content_tag_for
field_set_tag
form_tag

remote_form_for
form_remote_for
form_remote_tag
| # don't forget to update remote helpers to hash option: remote => true


Dir['**/*.*'].each{ |filename|
  data = File.read filename
  File.open(filename,'w'){|f|
    f.print data.gsub(/<%\s+(#{ patterns*'|' }).*(do|\{)/){
      $&.sub '<%', '<%='
    }
  }
}
puts :Done

Add the config initializer to environment files

 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
#!/usr/bin/env ruby

# add the AppName::Application.configure command to all config/environments/* files

ENVIRONMENTS_PATH = 'config/environments/'
APPLICATION_PATH  = 'config/application.rb'

if !File.exist? ENVIRONMENTS_PATH
  raise 'Please call the script from the Rails root directory'
elsif !( File.exist?(APPLICATION_PATH) && ( File.read(APPLICATION_PATH)  =~ /module\s+(\w+)/ ) && $1 )
  raise "You need an already updated #{APPLICATION_PATH} to run this script"
else
  app_name = $1

  Dir[ENVIRONMENTS_PATH + '*'].each{|filename|
    lines = File.readlines filename

    unless lines.join =~ /#{app_name}::Application.configure/
      lines.map!{|l|'  ' + l}
      lines.unshift "#{app_name}::Application.configure do"
      lines << "end"

      File.open(filename,'w'){|file|
        file.print lines.join
      }
    end
  }
  puts :Done
end

Updade cookie secret store

(the syntax gem really sucks…)


#!/usr/bin/env ruby

# Upgrades the session store. Only run this script, if you use cookies for
#  session storage.
#
# This script is quite destructive and uses eval, so please check if
#  your config/initializers/session_store.rb file looks like this:
#
# ActionController::Base.session = {
#   :key     => ‘_app_session’,
#   :secret  => ‘secret’
# }
#
# Please upgrade manually, if you have changed more than the values

SESSION_PATH = 'config/initializers/session_store.rb'
SECRET_PATH  = 'config/initializers/cookie_verification_secret.rb'

if !File.exist? SESSION_PATH
  raise 'Please call the script from the Rails root directory'
else
  # get data
  old = File.read SESSION_PATH

  if matched = old =~ /ActionController::Base.session\s+=/
    old[/ActionController::Base.session\s+=/] = ''
    user_data = eval old
  end

  if !matched || !user_data.is_a?(Hash)
    raise "#{SESSION_PATH} has changed too much, aborting..."
  end

  # write new files
  File.open(SECRET_PATH,'w'){|file|
    file.puts "Rails.application.config.secret_token = '#{user_data[:secret]}'"
  }

  File.open(SESSION_PATH,'w'){|file|
    file.puts "Rails.application.config.session_store :cookie_store, :key => '#{user_data[:key]}'"
  } if File.exists? SECRET_PATH

  puts :Done
end

Subtleties I had to deal with

Uninstall rails_xss

ActionView::Template::Error (undefined method `append=' for #<ActiveSupport::SafeBuffer:0xb6e2e4cc>)

rails_xss is a Rails 2 plugin. Remove it after the upgrade.

Controller’s initialize method

After the upgrade, my views suddenly did not have any layouts, anymore! This was caused by overwriting the initialize method of a controller. Allowed in Rails 2, forbidden in version 3.

Add standard gems to Gemfile

In Rails 3, you need to put gems like sqlite and mongrel in your Gemfile, or they will not be used:

gem "sqlite3-ruby", :require => "sqlite3"
gem 'mongrel'

Upgrade thin

/home/jan/.rvm/gems/ruby-1.8.7-p249/gems/activesupport-3.0.0.beta3/lib/active_support/dependencies.rb:209:in `require': no such file to load -- dispatcher (LoadError)

thin-1.2.5 is too old ;).

cache_template_loading

I had to remove this line from my config/environments/production.rb:

config.action_view.cache_template_loading = true

Rails 3 Documentation

Rails 3 is updated almost every day and so do the docs change – so I relaunched PlasmaRails.org. It fetches Rails every day and generates its rdoc.

Creative Commons License