Migrate from Rails to Phoenix 
Tags: ruby, rails, elixir, phoenix
Published: 2020-07-11 22:02:52

---
title: Migrate from Rails to Phoenix 
published: true
description: Setup a Phoenix Application to use the existing Postgres Database created by Rails.
tags: ruby, rails, elixir, phoenix
//cover_image: https://direct_url_to_image.jpg
---

Say you have a running Rails app and want to migrate the app to Phoenix for whatever reason. 

I'll be honest - in my case, it's just because I'm curious about Phoenix and want to learn more about it. 

The Rails app in question is a relatively simple JSON API backend for iOS- and Android mobile apps, as well as a Javascript Web Client. 

I want to be able to run both servers in parallel to compare both versions and to eventually switch over without interruption. For these reasons, I want to keep using the existing Postgres database.

In this post, I'm describing the steps that are necessary to get started. I'll assume you are already familiar with Phoenix and will only cover the special steps necessary to use the existing Postgres database from a Rails app.

## Dump Schema

In order to load your existing database schema from Rails in your Phoenix app, you'll need to dump the database schema as `structure.sql`

* Run `rails db:structure:dump` in your Rails App
* Copy the generated `structure.sql` file to `priv/repo/structure.sql` in your Phoenix App

You can now load the structure in your Phoenix App via `mix ecto.load`.

Alternatively, you can directly use the existing database. For tests, it's still necessary to have the `structure.sql` ready to create the test database.

## Create Schemas, delete Ecto Migrations

Create your schemas such that they exactly match your existing database structure.

This is not too hard since Ecto is a bit more configurable than ActiveRecord and naming conventions seem to match up pretty well anyway.

If you've used generators to generate your schemas, mix will also have created migrations for you. 

Since the database structure is already loaded, you'll need to delete these migration files. Otherwise, Phoenix will not run because of pending migrations.

## Fix Timestamps

By default, Ecto uses `inserted_at` and `updated_at` for timestamps while Active Record uses `created_at` and `updated_at`. 

The latter is not a problem, but the former is different, so you will get errors like this one

```
** (Postgrex.Error) ERROR 42703 (undefined_column) column "inserted_at" of relation "maps" does not exist
```

Its easy to tell Ecto to use custom names for timestamp columns, by using the following option in your schema:

```
  schema "maps" do
    # Your fields...

    timestamps(inserted_at: :created_at)
  end
```

## Adjust Ecto Tasks

By default, the provided mix tasks will run the migrations to create the database.

For normal development, you might not mind because you ran `mix ecto.load` manually or are using your existing rails database.

But when testing, `mix` will by default clear and re-create the test database on each run via migrations, which will not work.

To fix this, you can adjust the aliases in your `mix.exs` file to load the existing structure instead:

```
  defp aliases do
    [
      setup: ["deps.get", "ecto.setup", "cmd npm install --prefix assets"],
      "ecto.setup": ["ecto.create", "ecto.load", "run priv/repo/seeds.exs"],
      "ecto.reset": ["ecto.drop", "ecto.setup"],
      test: [
        "ecto.drop",
        "ecto.create --quiet",
        "ecto.load --quiet --skip-if-loaded",
        "ecto.migrate --quiet",
        "test"
      ]
    ]
  end
```

Pay attention to the `--skip-if-loaded` option in the `test` alias, otherwise you'll need to confirm that the schema is already loaded on each test run.

## Use the existing database from your Rails App

To use the existing database directly instead of creating a new database that just has the same structure, all you need to do is setup your Repo in `dev.exs` or `prod.exs` with the same configuration from your Rails' `database.yml` 

## Phoenix Migrations

To use Phoenix for further migrations, you'll need to change one more config. Both, Rails and Phoenix use the same table, `schema_migrations`, to manage migrations, but they have slightly different format.

To circumvent this issue, you'll have to configure Ecto to use a different table to manage migrations by setting a custom name for `migration_source`, e.g.:

```
# Configure your database
config :myApp, MyApp.Repo,
  username: "postgres",
  password: "postgres",
  database: "myapp-development",
  hostname: "localhost",
  show_sensitive_data_on_connection_error: true,
  pool_size: 10,
  # The App was started from Rails which used the `schema_migrations` table with the same name but different schema
  # To continue with migrations from ecto from now on, we use choose a custom name for the ecto migrations
  # !!! From now on, migrations should only be done from Ecto !!!
  migration_source: "ecto_schema_migrations"
```

One word of caution though: From that point onward, you should ONLY use Phoenix for your new migrations! Since Phoenix does not know about Rails migrations and vice versa, if you mix them it would be too easy to fuck up and break your database schema!

## Thats it

Now have fun re-writing your Rails App in Phoenix 😇