Skip to content

Instantly share code, notes, and snippets.

@chrismccord
Last active February 12, 2016 09:52
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save chrismccord/b3975ba356dba902ec88 to your computer and use it in GitHub Desktop.
Save chrismccord/b3975ba356dba902ec88 to your computer and use it in GitHub Desktop.
Phoenix Upgrade Instructions 0.11.x 0.12.0

Build-embedded and start permanent

Elixir v1.0.4 ships with two new important options for new projects. For projects generated prior to Elixir 1.0.4, add these options to your project entries in mix.exs:

build_embedded: Mix.env == :prod,
start_permanent: Mix.env == :prod

Asset Digests (optional)

A new phoenix.digest task is now inluded which digests and compress static files and can be used during deploy. It also integrates with the static_path helper to render the proper asset paths from the manifest.

A new configuration called cache_static_manifest was added which should be set to "priv/static/manifest.json" in production which will preload the manifest file generated by the mix task in order to point to the digested files when generating static paths, ie:

# config/prod.exs
config :my_app, MyApp.Endpoint,
  ...
  cache_static_manifest: "priv/static/manifest.json"

Usage:

  mix phoenix.digest
  mix phoenix.digest priv/static -o /www/public

The first argument is the path where the static files are located. The -o option indicates the path that will be used to save the digested and compressed files.

If no path is given, it will use priv/static as the input and output path.

The output folder will contain:

  • the original file
  • a compressed file with gzip
  • a file containing the original file name and its digest
  • a compressed file containing the file name and its digest
  • a manifest file

Example of generated files:

  • application.js.erb
  • application.js.erb.gz
  • application.js-eb0a5b9302e8d32828d8a73f137cc8f0.erb
  • application.js-eb0a5b9302e8d32828d8a73f137cc8f0.erb.gz
  • manifest.json

Live-reload

Live reload has been updated to reload css changes without refreshing the browser. We also fixed a few bugs for windows users. Simply run mix deps.update phoenix_live_reload or bump the version in your mix.exs:

...
{:phoenix_live_reload, "~> 0.3.3"},

Test Helpers

Phoenix includes new test helpers for easily testing your endpoints, routers, controllers. See the test docs for example usage.

Code that used to require multiple assertions and manually wiring up the %Conn{} structs can now simply call into the endpoint stack. Phoenix generates tests files for these features for new projects. Existing projects can get up to speed by the following steps:

  1. $ mkdir test/support

  2. Save the following listing as test/support/conn_case.ex and replace MyApp with your app module. Note: the Ecto bits of this step can be excluded if not using Ecto.

defmodule MyApp.ConnCase do
  @moduledoc """
  This module defines the test case to be used by
  tests that require setting up a connection.

  Such tests rely on `Phoenix.ConnTest` and also
  imports other functionality to make it easier
  to build and query models.

  Finally, if the test case interacts with the database,
  it cannot be async. For this reason, every test runs
  inside a transaction which is reset at the beginning
  of the test unless the test case is marked as async.
  """

  use ExUnit.CaseTemplate

  using do
    quote do
      # Import conveniences for testing with connections
      use Phoenix.ConnTest

      # Alias the data repository and import query/model functions
      alias MyApp.Repo
      import Ecto.Model
      import Ecto.Query, only: [from: 2]

      # Import URL helpers from the router
      import MyApp.Router.Helpers

      # The default endpoint for testing
      @endpoint MyApp.Endpoint
    end
  end

  setup tags do
    unless tags[:async] do
      Ecto.Adapters.SQL.restart_test_transaction(MyApp.Repo, [])
    end

    :ok
  end
end
  1. Save the following listing as test/support/model_case.ex and replace MyApp with your app module. Note: this step can be skipped/modified if not using Ecto.
defmodule MyApp.ModelCase do
  @moduledoc """
  This module defines the test case to be used by
  model tests.

  Finally, if the test case interacts with the database,
  it cannot be async. For this reason, every test runs
  inside a transaction which is reset at the beginning
  of the test unless the test case is marked as async.
  """

  use ExUnit.CaseTemplate

  using do
    quote do
      # Alias the data repository and import query/model functions
      alias MyApp.Repo
      import Ecto.Model
      import Ecto.Query, only: [from: 2]
    end
  end

  setup tags do
    unless tags[:async] do
      Ecto.Adapters.SQL.restart_test_transaction(MyApp.Repo, [])
    end

    :ok
  end
end

Channels

terminate/2 in your channels is now always called when the channel server shuts down. Leaving the channel or closing the client will now trigger terminate on the channel, regardless of traping exits, with reasons {:shutdown, :left} and {:shutdown, :closed} respectively.

Views

New functions render_many/4 and render_one/4 have been added to make it easier to render collection and optional data. See the docs for example usage

render_existing/3 has been added to allow dynamic rendering of templates that may or may not exist. From the docs:

Consider the case where the application layout allows views to dynamically render a section of script tags in the head of the document. Some views may wish to inject certain scripts, while others will not.

<head>
  <%= render_existing view_module(@conn), "scripts.html", assigns %>
</head>

Then the module for the @inner view can decide to provide scripts with either a precompiled template, or by implementing the function directly, ie:

def render("scripts.html", _assigns) do
  "<script src=\"...\">"
end

Rendering based on controller template

In some cases, you might need render based on the template from the controller. For these cases, Phoenix.Controller.controller_template/1 can pair with render_existing/3 for per-template based content, ie:

<head>
  <%= render_existing view_module(@conn), "scripts." <> controller_template(@conn), assigns %>
</head>

def render("scripts.show.html", _assigns) do
  "<script src=\"...\">"
end
def render("scripts.index.html", _assigns) do
  "<script src=\"...\">"
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment