All about Phoenix, the elixir framework

Find out versions being using in your application

:application.which_applications

run from within iex

Phoenix Console is less good than rails console. Rails Console loads your entire application, Phoenix does not. I’m sure this is something that I will eventually get used to, but not today.

$ iex -S mix

Common things to import

import Ecto.Query
alias DecideTheNight.Repo

Query the databse

Repo.all(Yelp)

yelp_token = Repo.get!(Yelp, 1)
# returns first result

yelp_token.access_token

Insert into the database

Yelp.changeset(%Yelp{}, %{"access_token": "fuck"})
Repo.insert(changeset)

Update the database

token_to_update = Repo.get!(Yelp, 1)
changeset = Yelp.changeset(token_to_update, %{"access_token": "fuckme"})
Repo.update(changeset)

Migrations

http://wsmoak.net/2015/07/27/adding-fields-to-an-ecto-model-in-phoenix.html

$ mix ecto.gen.migration add_fields_to_users

alter table(:users) do
  add :user_id, :string
  add :access_token, :binary
  add :access_token_expires_at, :datetime
  add :refresh_token, :binary
end

$mix ecto.migrate

I ALSO NOTICED SOMETHING THAT WASN'T MENTIONED IN THAT POST. I NEEDED TO ADD THE FIELDS TO MY MODEL AS WELL? THAT WAY I CAN ACCESS THEM WITHIN IEX.

schema "search_results" do
  field :mood, :string
  field :address, :string
  field :lat, :decimal, precision: 9, scale: 6
  field :lng, :decimal, precision: 9, scale: 6
  field :radius, :integer
  field :budget, :string

  timestamps
end

Rollback

    $ mix ecto.rollback

The paramerter data sent to the changeset should be a map. Example Map

episode = %{
  name: "Data types",
  author: "Daniel Berkompas"
}

it’s also possible to add this to a root level .iex.exs file which will be loaded when you start iex.

Recompile Your Iex

You need to recompile when you make a change to your application. http://stackoverflow.com/questions/36490089/how-do-i-recompile-an-elixir-project-and-reload-it-from-within-iex

IEx.Helpers.recompile

or Recompile a specific module

r DecideTheNight.Yelp

ENV VARIABLES

Create env variables

I generally follow this guys advice… http://blog.danielberkompas.com/elixir/2015/03/21/manage-env-vars-in-elixir.html

create a .env file, remove it from source control. Add export TWILIO_ACCOUNT_SID="<SID HERE>" to it (or whatever). When I change it run $ source .env. Then I can access that with System.get_env("TWILIO_ACCOUNT_SID"). Lastly, in your dev.exs add config :ex_twilio, account_sid: System.get_env("TWILIO_ACCOUNT_SID")

Accessing it can be done with

Application.get_env(:decideTheNight, :yelp_app_id)

Very fucking difficult.

Retrieve env variables

Application.get_all_env(:app_vars)

Application.get_env(:my_large_app_name, MyLargeAppName.Endpoint)[:my_var]
Application.get_env(:decideTheNight, DecideTheNight.Endpoint)[:url]

http://stackoverflow.com/questions/30995743/how-to-get-a-variable-value-from-environment-files-in-phoenix/30996122?noredirect=1#comment67252045_30996122

Eh I don’t use this… http://elixir-lang.org/docs/stable/elixir/System.html#put_env/1

Run commands within iex

http://stackoverflow.com/questions/22594988/run-shell-commands-in-elixir

Generators

$ mix phoenix gen.model Yelp yelps access_token:string access_token_expires_at:datetime
$ mix phoenix.gen.html User users name:string

Don’t forget to create your postgres database on heroku…

heroku addons:create heroku-postgresql
heroku run mix ecto.create
heroku run mix ecto.migrate

http://stackoverflow.com/questions/19814740/heroku-postgres-too-many-connections-how-do-i-kill-these-connections

I am learning Phoenix. Seeing where it will take me. The version I am using while writing this is 1.1.4. The current version of Phoenix can be found on their website, http://www.phoenixframework.org/ in the upper right hand corner. To find out what version you’re using locally, create a phoenix application, then open you hex file, mix.exs. And scroll down to see your dependencies.

Errors I ran into the first time I used Phoenix

  1. iex(1)> 20 Apr 15:15:01 - error: Compiling of web/static/js/socket.js failed. Couldn’t find preset “es2015” relative to directory “web/static/js” ; Compiling of web/static/js/app.js failed. Couldn’t find preset “es2015” relative to directory “web/static/js”

This is a problem documented here… https://github.com/phoenixframework/phoenix/issues/1410 . I was running node v4.4.1. You can check the node version… $ node --version. So, I can either upgrade node or specify babel-preset-es2015 as a dependency and run npm install. I MEAN FUCKING HELL, HOW IS ANYONE SUPPOSED TO REMEMBER ALL THIS SHIT? Oh… anyways. To install this dependency you can update your package.json file.

{
  "dependencies": {
    ...
    "babel-preset-es2015": "~6.6.0",
    ...
  }
}

OR use npm to install it…

$ npm install --save-dev babel-preset-es2015

Phoenix 0 to Deploying to Heroku

$ mix phoenix.new heroku_deploy
=> Y to install dependencies
$ cd heroku_deploy
$ git init
$ git add .
$ git commit -m 'initial commit'
$ heroku create
$ heroku config:set BUILDPACK_URL="https://github.com/HashNuke/heroku-buildpack-elixir.git"
$ heroku buildpacks:add https://github.com/gjaldon/heroku-buildpack-phoenix-static.git

Update .gitignore

heroku requires prod.secret.exs to work…Comment out the last line to look like this.

#/config/prod.secret.exs

Update /config/prod.secret.exs to use env variables

# Your config/prod.secret.exs should look like...

use Mix.Config

config :deploy_heroku, DeployHeroku.Endpoint,
  secret_key_base: System.get_env("SECRET_KEY_BASE")

config :heroku_deploy, HerokuDeploy.Repo,
  adapter: Ecto.Adapters.Postgres,
  url: System.get_env("DATABASE_URL"),
  pool_size: 20,
  ssl: true

Generate a Secret Key

$ mix phoenix.gen.secret
=> YK8khBqI69DafdsYb23vK8HJze64ncvh5MJonTQL7EoPEa2YaX+5xmPlApUvzYV1

(This will also force you app to compile, which takes about 25 seconds)

Add the key as a config variable

$ heroku config:set SECRET_KEY_BASE=YK8khBqI69DafdsYb23vK8HJze64ncvh5MJonTQL7EoPEa2YaX+5xmPlApUvzYV1

OF COURSE YOU’LL GENERATE YOUR OWN KEY AND THEN ADD IT YOURSELF. DON’T NECESSARILY COPY THE KEY I USED

Generate a scaffold

$ mix phoenix.gen.html User users name:string

Update web/router.ex

scope "/", DeployHeroku3 do
  pipe_through :browser # Use the default browser stack
  resources "/users", UserController
  get "/", PageController, :index
end

Create the local DB and Migrate the db

$ mix ecto.create
$ mix ecto.migrate

Deploy it heroku

$ git add .
$ git commit -m 'damn, lots of work'
$ git push heroku master

After deploy completes, create db, migrate

$ heroku addons:create heroku-postgresql:hobby-dev
$ heroku run mix ecto.migrate

Now you can visit, [application_url/users and create a user

in my case it was https://afternoon-anchorage-20106.herokuapp.com/users

Hopefully it worked for you.

  1. You need to use the custom elixir buildpack so that heroku recognizes your application as elixir

If you do not use the elixir buildback, heroku will recognize your application as a node application which is incorrect.

Create a heroku application with the correct buildpack

$ heroku create --buildpack "https://github.com/HashNuke/heroku-buildpack-elixir.git"

Add the buildpack to an existing heroku application

$ heroku config:set BUILDPACK_URL="https://github.com/HashNuke/heroku-buildpack-elixir.git"

Also need to add the static buildpack to your heroku application

$ heroku buildpacks:add https://github.com/gjaldon/heroku-buildpack-phoenix-static.git
  1. You need to create your own secret key for heroku.

    mix phoenix.gen.secret

  2. Then you also need to setup the DB in config/prod.exs

    config/prod.exs

    config :hellophoenix, HelloPhoenix.Repo, adapter: Ecto.Adapters.Postgres, url: System.getenv(“DATABASEURL”), poolsize: 20, ssl: true

  3. I received the error…

    ** (Mix) The database for HelloPhoenix.Repo couldn’t be created, reason given: psql: FATAL: role “postgres” does not exist This was somewhat challenging

  4. Then I needed to create a new pg user, postgress

I used homebrew to install postgres. You can find out if you used homebrew by running $ ls /usr/local/Cellar/postgresql/, if you see files in there, it’s likely you used homebrew to install. Then you need to find your latest version of PG. You can do that by typing $ psql --version. My latest version was 9.4.4.

/usr/local/Cellar/postgresql/9.4.4/bin/createuser -s postgres

The basics of Phoenix…

Phoenix is created from Elixir. To create a Phoenix application, you need to have elixir going.

Phoenix uses, I believe, both a package.json to manage front end dependencies and mix.exs to manage back end dependencies. This gives you the flexibility of using a legit front end framework, but also the challenges of implementing a front end framework. It’s nice if you can manage, but shit if you’re new.

Creating a Phoenix Application

$ mix phoenix.new blog_phoenix

blog_phoenix is the name of your application.

Starting the Server

$ mix phoenix.server

You can also run your app inside IEx (Interactive Elixir) as:

$ iex -S mix phoenix.server

Starting Phoenix Console

$ iex -S mix

Routes in Phoenix

$ mix phoenix.routes

Creating the Database locally

$ mix ecto.create

Creating the Database on heroku

$ heroku addons:create heroku-postgresql:hobby-dev

Generators in Phoenix

$ mix phoenix.gen.html
$ mix phoenix.gen.json
$ mix phoenix.gen.channel
$ mix phoenix.gen.model

However, this is not the complete command, you’ll need to add two other parameters into the command. One singular, one plural. So if we want a model of User, we’ll do this command. Then you can also add database attributes, so if we want to give the User a name attribute, we’d write the command like so…

$ mix phoenix.gen.html User users name:string

This is equivalent in rails of…

$ rails generate scaffold User name:string

Rails will make more guesses for you, Phoenix does less assumptions. One last difference, is you’ll need to add the route in web/router.ex Phoenix will let you know what route to add after you generate. It will say something like…

Add the resource to your browser scope in web/router.ex:
    resources "/users", UserController

Phoenix gives very good error messages. So if you forget that step, it will let you know.Lastly, just like in rails, you need to migrate the DB.

$ mix ecto.migrate

Cool. You should see something that compiles all the new files.

Example Query

FuckingTest.Repo.all(
  from p in FuckingTest.User,
  where: p.age == 30,
  select: p)

Umbrella projects

this allows us to separate concerns straight away

mix new cheater --umbrella
cd cheater
mix new solver
mix phoenix.new --no-html --no-ecto --no-brunch web

plug in phoenix is like rack in rails

def index(conn, %{“tiles” => tiles}) do

end

def render(“index.json”,

get “/:tiles”, APIController, :index

Example generated controller phoenix

defmodule DecideTheNight.UserController do
  use DecideTheNight.Web, :controller

  alias DecideTheNight.User

  plug :scrub_params, "user" when action in [:create, :update]

  def index(conn, _params) do
    users = Repo.all(User)
    render(conn, "index.html", users: users)
  end

  def new(conn, _params) do
    changeset = User.changeset(%User{})
    render(conn, "new.html", changeset: changeset)
  end

  def create(conn, %{"user" => user_params}) do
    changeset = User.changeset(%User{}, user_params)

    case Repo.insert(changeset) do
      {:ok, _user} ->
        conn
        |> put_flash(:info, "User created successfully.")
        |> redirect(to: user_path(conn, :index))
      {:error, changeset} ->
        render(conn, "new.html", changeset: changeset)
    end
  end

  def show(conn, %{"id" => id}) do
    user = Repo.get!(User, id)
    render(conn, "show.html", user: user)
  end

  def edit(conn, %{"id" => id}) do
    user = Repo.get!(User, id)
    changeset = User.changeset(user)
    render(conn, "edit.html", user: user, changeset: changeset)
  end

  def update(conn, %{"id" => id, "user" => user_params}) do
    user = Repo.get!(User, id)
    changeset = User.changeset(user, user_params)

    case Repo.update(changeset) do
      {:ok, user} ->
        conn
        |> put_flash(:info, "User updated successfully.")
        |> redirect(to: user_path(conn, :show, user))
      {:error, changeset} ->
        render(conn, "edit.html", user: user, changeset: changeset)
    end
  end

  def delete(conn, %{"id" => id}) do
    user = Repo.get!(User, id)

    # Here we use delete! (with a bang) because we expect
    # it to always work (and if it does not, it will raise).
    Repo.delete!(user)

    conn
    |> put_flash(:info, "User deleted successfully.")
    |> redirect(to: user_path(conn, :index))
  end
end

Post Content