Use Synvert to automatically upgrade rails 4.2 to 5.0 (Part 1)

Synvert provides the ability to write code snippets that can automatically rewrite your source code. This video demonstrates how to automatically upgrade rails 4.2 to 5.0 (Part 1)

Rails is one of the most popular web application frameworks, rails team releases a new version every year. In this tutorial series, I will demonstrate how to use Synvert to automatically upgrade your Rails application from 4.2 to 5.0.

The first one is versioned migrations.

When you run the db:migrate task in rails 5.0, you will see the following warning:

Directly inheriting from ActiveRecord::Migration is deprecated. Please specify the Rails release the migration was written for:

So we need to change all migrations to inherit from ActiveRecord::Migration[4.2] instead of ActiveRecord::Migration.

To get started with Synvert, open VSCode and activate the Synvert Extension. Select the language as ruby and click “Show Generate Snippet Form”.

Set the File Pattern as db/migrate/*.rb

Set the Gem Version as activerecord >= 5.0

Set the Input as

class CreatePosts < ActiveRecord::Migration
end

and Output as

class CreatePosts < ActiveRecord::Migration[4.2]
end

Finally, click the “Generate Snippet” button. This will generate the following snippet:

Synvert::Rewriter.new 'group', 'name' do
  if_gem 'activerecord', '>= 5.0'
  within_files 'db/migrate/*.rb' do
    with_node node_type: 'class', name: 'CreatePosts', parent_class: 'ActiveRecord::Migration' do
      replace :parent_class, with: '[4.2]'
    end
  end
end

This is a simple and straightforward snippet that searches for the class node whose name is CreatePosts and parent_class is ActiveRecord::Migration, and replaces the parent_class with {{parent_class}}[4.2]. To make it works with all migrations, we just need to remove the rule that name is CreatePosts. So the updated snippet is as follows:

Synvert::Rewriter.new 'group', 'name' do
  if_gem 'activerecord', '>= 5.0'
  within_files 'db/migrate/*.rb' do
    with_node node_type: 'class', parent_class: 'ActiveRecord::Migration' do
      replace :parent_class, with: '{{parent_class}}[4.2]'
    end
  end
end

Now we can search in our project

And replace them with ActiveRecord::Migration[4.2].

The next one is ApplicationRecord

Active Record Models Now Inherit from ApplicationRecord by Default

It requires us to make two changes:

  1. add a new file app/models/application_record.rb.

  2. change all models to inherit from ApplicationRecord instead of ActiveRecord::Base.

Open the VSCode Synvert Extension. Select the language as ruby and click “Show Generate Snippet Form”.

Set the File Pattern as app/models/**/*.rb

Set the Gem Version as activerecord >= 5.0

Set the Input as

class Post < ActiveRecord::Base
end

and Output as

class Post < ApplicationRecord
end

Click the “Generate Snippet” button, then it will generate the following snippet:

Synvert::Rewriter.new 'group', 'name' do
  if_gem 'activerecord', '>= 5.0'
  within_files 'app/models/**/*.rb' do
    with_node node_type: 'class', name: 'Post', parent_class: 'ActiveRecord::Base' do
      replace :parent_class, with: 'ApplicationRecord'
    end
  end
end

It searches for the class node whose name is Post and parent_class is ActiveRecord::Base, then replaces the parent_class with ApplicationRecord. To make it works with all models, we just need to remove the rule that name is Post.

The updated snippet is as follows:

Synvert::Rewriter.new 'group', 'name' do
  if_gem 'activerecord', '>= 5.0'
  within_files 'app/models/**/*.rb' do
    with_node node_type: 'class', parent_class: 'ActiveRecord::Base' do
      replace :parent_class, with: 'ApplicationRecord'
    end
  end
end

Now we can search in our project.

And replace them with ApplicationRecord.

To add the app/models/application_record.rb file, we can use the add_file api to let synvert create the file automatically.

add_file 'app/models/application_record.rb', <<~EOS
  class ApplicationRecord < ActiveRecord::Base
    self.abstract_class = true
  end
EOS

We can do the same thing for ApplicationMailer and ApplicationJob.

That concludes this tutorial. In the next tutorial, I’ll show you more cases when upgrading rails from 4.2 to 5.0. See you then!

0 Comments
Authors
Richard Huang