In Deploying a Phoenix app to Heroku we looked at the absolute minimum necessary to get the Hello Phoenix app running on Heroku. This involved modifying config files and adding some environment variables.

Now let’s start over and deploy a slightly more realistic app, one that actually uses a database, so we can make sure everything works. We’ll be using Postgres and Ecto which is Elixir’s DSL for interacting with databases.

Note: This worked in mid-July 2015 with Elixir 1.0.4 and Phoenix 0.14.0. If it stops working at some point in the future, please let me know so I can update it or point readers to a more up-to-date resource!

Step 0: Prerequisites

Before you can begin, you need several things installed. These include but may not be limited to: Erlang, Elixir, Postgres, NodeJS, Heroku Toolbelt, Phoenix, and Git.

Here are some links to get you started:

If you have any problems at all, ask in #elixir-lang on Freenode IRC, in the Phoenix channel in Slack, or on the phoenix-talk Google Group. If you don’t know how to find or use those, ask below in the comments or send me an email, and I’ll help you find the right place.

Now, let’s begin.

Step 0.5: Install the latest hex

One thing first! There was a bug in hex (the package manager) that was fixed Sunday morning 7/12, however depending on what you have downloaded recently, you may have the bad version. Execute this command to install hex locally:

$ mix local.hex

Now we can get started.

Step 1: Create a sample app and put it under version control

The first steps are the same, create a new Phoenix app and get it under version control:

$ mix phoenix.new my_app
...
Fetch and install dependencies? [Yn] Y
...
$ cd my_app
$ git init && git add . && git commit -m "Initial commit of Phoenix app"

Now if anything goes wrong, we can back up to this point.

Step 2: Choose a License

The next thing to do is to choose a license for your project. If your project has a chance of ever getting out in public, for example if you are going to put it on GitHub, it’s important to include a license so that someone coming upon it later understands what your intentions are and what they are allowed to do with your code.

I’ve been involved with The Apache Software Foundation for years and years, and I prefer the Apache License. Many projects (and Phoenix itself) use the MIT License. GitHub has an excellent Choose A License tool to help you decide.

Enough of my soapbox. If you’re going to, add your LICENSE file and commit it.

$ curl http://www.apache.org/licenses/LICENSE-2.0.txt > LICENSE
$ git add LICENSE && git commit -m "Add Apache License 2.0"

(If you’d like to automate adding the MIT license to your project, this looks like an interesting option: https://github.com/remy/mit-license .)

Step 3: Add a Users model

Let’s add a simple model for a User by following part of the Ecto Models guide.

$ mix phoenix.gen.html User users name:string email:string
$ git add . && git commit -m "Add generated User model"

The output tells us to

Add the resource to your browser scope in web/router.ex:

    resources "/users", UserController

Open web/router.ex and paste that line in:

  scope "/", MyApp do
    pipe_through :browser # Use the default browser stack

    get "/", PageController, :index
    resources "/users", UserController  # <------
  end

Remember to git commit your changes:

$ git add . && git commit -m "Add Users resource to browser scope"

NOTE: If you run into an Unchecked dependencies error at this point, see the Troubleshooting section below.

Step 4: Test locally

Provided you have Postgres installed and running locally, you can create the development database and run the migration. (The Ecto Models guide has all the details on this.)

$ mix ecto.create
$ mix ecto.migrate

At this point you can start the app with mix phoenix.server, visit the http://localhost:4000/users page, and check that adding, editing and deleting users works in the development environment.

Step 5: Modify prod configuration

The sample app generated by mix phoenix.new expects to import a prod.secret.exs file that we will not be using. Remove this section from config/prod.exs:

-
-# Finally import the config/prod.secret.exs
-# which should be versioned separately.
-import_config "prod.secret.exs"

Instead, add the following to prod.exs (copied and modified from config/prod.secret.exs):

# Configure secret_key_base for cookie-based session storage
  config :my_app, MyApp.Endpoint,
  secret_key_base: System.get_env("SECRET_KEY_BASE")

# Configure your database
  config :my_app, MyApp.Repo,
  adapter: Ecto.Adapters.Postgres,
  url: System.get_env("DATABASE_URL"),
  size: 20 # The amount of database connections in the pool

This tells Phoenix to get the DATABASE_URL and SECRET_KEY_BASE values from the environment, so that we don’t have to include passwords and keys in plain text in our source code. We’ll set those values a bit later.

Note: If your app is not named exactly my_app then you will need to modify the config lines above to match.

Remember to git commit your changes:

$ git add . && git commit -m "Update production configuration"

Step 6: Create the Heroku application

$ heroku create

You should see something like this:

Creating powerful-depths-1590... done, stack is cedar-14
https://powerful-depths-1590.herokuapp.com/ | https://git.heroku.com/powerful-depths-1590.git
Git remote heroku added

If this does not work, check that you have the Heroku Toolbelt installed.

(If you’re curious about what just happened, execute git remote -v to see the ‘remotes’ that were added to your local git repo.)

Step 7: Add Heroku buildpacks

A newly created Heroku application does not know anything about the language and frameworks used by the app. Buildpacks are used for this configuration, and have been provided by the community.

Add the Elixir buildpack first, followed by the Phoenix Static buildpack.

$ heroku buildpacks:add https://github.com/HashNuke/heroku-buildpack-elixir
$ heroku buildpacks:add https://github.com/gjaldon/phoenix-static-buildpack

Note: If heroku complains that buildpacks is not a recognized command, and you happen to be a Ruby developer who uses rbenv, then see if this helps.

Step 8: Add PostgreSQL to the Heroku app

Now add the PostgreSQL database to the Heroku application:

$ heroku addons:create heroku-postgresql

This will make the database available, but it will be empty. We’ll create the database tables and columns shortly.

Step 9: Set environment variables

Set the SECRET_KEY_BASE environment variable, which is used for cookie-based session storage.

$ heroku config:set SECRET_KEY_BASE=[copied from config/prod.secret.exs]

Step 10: Push changes to Heroku

At this point we need to push our changes to Heroku so that it will get the environment set up and build the app.

$ git push heroku master

Step 11: Create and migrate the database

Now that Elixir is installed, you have access to the mix command which is needed to run the following commands to create and migrate the database.

$ heroku run mix ecto.create
Running `mix ecto.create` attached to terminal... up, run.4208
** (Mix) The database for MyApp.Repo couldn't be created, reason given: Error: You must install at least one postgresql-client-[version] package.
.

Oops! This command results in an angry red error message. Fear not. According to http://stackoverflow.com/questions/17300341/migrate-not-working-on-heroku and in my experience, this can safely be ignored.

$ heroku run mix ecto.migrate
Running `mix ecto.migrate` attached to terminal... up, run.5618

15:51:38.879 [info]  == Running MyApp.Repo.Migrations.CreateUser.change/0 forward

15:51:38.879 [info]  create table users

15:51:38.932 [info]  == Migrated in 0.4s

Now the ‘users’ database table has been created.

Step 12: Success!

And finally:

$ heroku open

This should open the index page of your app. Add /users to the url and see it work, for example: https://powerful-depths-1590.herokuapp.com/users .

Hello Phoenix with Users on Heroku

Copyright 2015 Wendy Smoak - This post first appeared on http://wsmoak.github.io and is licensed CC BY-NC.

References

Troubleshooting

If you see this error when trying to generate the model in Step 3…

Generated phoenix_ecto app
==> my_app
Unchecked dependencies for environment dev:
* postgrex (Hex package)
  the dependency postgrex defined

  > In mix.exs:
    {:postgrex, ">= 0.0.0", [hex: :postgrex]}

  does not match the requirement specified

  > In deps/ecto/mix.exs:
    {:postgrex, "~> 0.8.3", [optional: true, hex: :postgrex]}

  Ensure they match or specify one of the above in your MyApp.Mixfile deps and set `override: true`
** (Mix) Can't continue due to errors on dependencies

… it is due to:

3:31 PM [ericmj] there was a bug in hex that has been fixed
3:32 PM [ericmj] if you update hex it is fine, but if you fetched deps with the broken hex you may have a locked postgrex 0.9.0 which you dont want

The mix local.hex command we ran earlier should have prevented this, but if not, execute these commands to install the latest one again and unlock the postgrex dependency:

$ mix local.hex
$ mix deps.unlock
$ mix deps.unlock postgrex
$ mix deps.get

Go back to Step 3