Friday, December 27, 2013

Upgrading Application from Rails 3 to Rails 4

A few notes about upgrading a Rails 3 app to Rails 4. Looking back at all this effort now, it does not seem like I had to change much. Just a few little things -- but in a lot of places. The pain was in tracking down all the various changes. Took a lot of time along with trial and error. The right solution was not always obvious at first. And when I say "right" I mean the one that works for me. That's the only thing I claim: these appear to be working for me.

  • First a word about "webrick:" In the course of all the changes I was making, I finally stopped using webrick and went to 'thin.' This eliminated some annoyances like 'Request URL too long'. To switch over to 'thin' was easy. Once the following steps were complete, "rails server" ran the 'thin' web server instead of 'webrick'
    • run: "gem install thin"
    • edit Gemfile to add the line: gem 'thin'
    • run "bundle install"
  • Routes needed a lot of attention as usual with any major upgrade. Routes seem now much more secure than they were. I found one trick that helped me understand the issues better. I added the following to one of my controllers temporarily:
    • url = url_for :controller => :messages, :action => :message_to_group, :users => @users
    • raise url
  • I don't claim to be an expert at routes by any means, but most of my definitions now look like the following and work:
  controller :preferences do
    get 'preferences/edit' => 'preferences#edit'
    post 'preferences/edit' => 'preferences#edit'
  end
  • Speaking of security: now I have to "require" and "allow" parameters when updating records. Example:
    • @hour.update_attributes(params[:hour]) is now:
    • @hour.update_attributes(hours_params_for_update) where hours_params_for_update is a function containing code like params.required(:hour).permit(:field1,:field2, etc.)
  • ActionMailer has changed. Statement like:
    bcc to
    from       from
    reply_to   from
    sent_on    sent_at

    • Becomes:
    mail(
      :bcc => to,
      :subject => my_subject,
      :reply_to => from,
      :from => from
    )
  • Visibility of methods that were "protected" changed, and I removed "protected" spec from them.
  • As I started into this, I saw it was a mistake to ignore the deprecation warnings I saw during the upgrade to Rails 3. So, this time I eliminated ALL of them:
    • DEPRECATION WARNING: #apply_finder_options is deprecated.
    • DEPRECATION WARNING: This dynamic method is deprecated.
    • Many dynamic "finder options" methods are deprecated:
EmailGroupsUser.find_all_by_email_group_id(params[:email_group_id]) becomes:
EmailGroupsUser.where(["email_group_id = ?",params[:email_group_id]])
See http://edgeguides.rubyonrails.org/4_0_release_notes.html#active-record-deprecations
    • DEPRECATION WARNING: The following options in your EmailGroup.has_many :users declaration are deprecated: :order. Please use a scope block instead.
EmailGroup.paginate(:page => page,:per_page => EMAIL_GROUPS_PER_PAGE,
      :conditions => ['UPPER(description) like ?',"%#{search_for}%"],
      :order => "description desc") becomes:
EmailGroup.order("description desc").where(['UPPER(description) like ?',"%#{search_for}%"]).paginate(:page => page,:per_page => EMAIL_GROUPS_PER_PAGE)
    • DEPRECATION WARNING: Relation#all is deprecated
VolunteerType.order("sort_level").all.map { |type| [type.description,type.level] } becomes:
VolunteerType.order("sort_level").map { |type| [type.description,type.level] }
    • DEPRECATION WARNING: The following options in your User.has_many :email_groups declaration are deprecated: :order. Please use a scope block instead.
has_many :users, :through => :email_groups_users, :order => 'last_name,first_name,middle_name' becomes:
has_many :users, -> { order('last_name,first_name,middle_name') }, :through => :email_groups_users

    • DEPRECATION WARNING: :confirm option is deprecated and will be removed from Rails 4.1. 
link_to("Refresh Test Data from Live (Production) PFERD","/preferences/refresh" ,
        {:confirm => 'This may take a few moments. Please wait until the screen is updated with a new status' }, :title => 'Refresh Data') becomes:
link_to("Refresh Test Data from Live (Production) PFERD","/preferences/refresh" ,
        :data => {:confirm => 'This may take a few moments. Please wait until the screen is updated with a new status', :title => 'Refresh Data' })
  • Images, JavaScript files, and style sheets moved down under the "app/assets" folder in images, javascripts, and stylesheets folders respectively. 
  • In application.html.erb:
    • link to favicon changed:
<link rel="shortcut icon" href="/favicon.ico" /> becomes:
<%= favicon_link_tag 'favicon.ico' %>
    • stylsheet link changed:
<%= stylesheet_link_tag :all %> becomes:
<%= stylesheet_link_tag "scaffold", media: "all" %>

    • javascript include changed. "defaults" no longer works, and without this changed "confirm" popups were no longer working.
<%= javascript_include_tag :defaults %> becomes:
<%= javascript_include_tag "application" %>


  • config = Rails::Configuration.new becomes config = Rails.application.config so you can read the Rails configuration with lines like:

    host     = config.database_configuration[Rails.env]["host"]
    database = config.database_configuration[Rails.env]["database"]

    port     = config.database_configuration[Rails.env]["port"]
    password = config.database_configuration[Rails.env]["password"]

    user     = config.database_configuration[Rails.env]["username"]