How to implement tagging with Ecto and Elixir

Tagged tagging, tags, elixir, ecto  Languages elixir
defmodule Snippets.Tagging do
  import Ecto.Query
  alias Ecto.Changeset
  alias Snippets.Repo
  @doc """
  Tags a model.

  ## Model

    defmodule Snippets.Tag do
      import Ecto.Query
      use Ecto.Schema

      schema "tags" do
        field :name
        many_to_many :snippets, Snippets.Snippet, join_through: "snippet_tags"

    defmodule Snippets.Snippet do
      import Ecto.Query
      use Ecto.Schema
      schema "snippets" do
        field :tag_list, :string, virtual: true

  ## Schema

    create table(:tags) do
      add :name, :text, null: false
    create index(:tags, ["lower(name)"], unique: true)

    create table(:snippet_tags) do
      add :tag_id, references(:tags)
      add :snippet_id, references(:snippets)
    create index(:snippet_tags, [:tag_id, :snippet_id], unique: true)

  ## Code

    |> Changeset.cast(conn.params, @required_params, @optional_params)
    |> Tagging.changeset(Snippets.Tag, :tags, :tag_list)
    # Supports multiple types of tags
    |> Tagging.changeset(Snippets.Language, :languages, :language_list)

  def changeset(changeset, model, association, tag_list_attr) do
    # Parse tags into Enum
    tag_list = changeset.changes
                |> Map.get(tag_list_attr, "")
                |> String.split(",")
                |> Enum.map(&(String.strip(&1)))
                |> Enum.reject(fn(name) -> name == "" end)
                |> Enum.map(&(String.downcase(&1)))
                |> Enum.uniq
                |> Enum.sort
    # Find existing tags
    existing_tags = from(t in model, where: t.name in ^tag_list) |> Repo.all
    # Create or find all tags
    tags = Enum.map(tag_list, fn(name) ->
      # Initialize new tag. Equivalent to:
      # new_tag = %Snippets.Tag{name: name}
      new_tag = struct(model, name: name)
      tag = Enum.find(existing_tags, new_tag, fn(existing_tag) ->
        existing_tag.name == name
    tag_changeset = Enum.map(tags, &Ecto.Changeset.change/1)
    # Add tags to changeset
    changeset |> Changeset.put_assoc(association, tag_changeset)

Logging to a file with Elixir

Tagged elixir, logging, file  Languages elixir


  def application do
      applications: [:logger, :logger_file_backend, ...],
      mod: {Snippets, []}

  def deps do
      {:cowboy, "~> 1.0.0"}, # web server
      {:logger_file_backend, "~> 0.0.7"} # writes log messages to a file, LOL


config :logger, :error_log,
  path: "log/app.log",
  level: :debug

Pagination with Phoenix and Ecto

Tagged phoenix, pagination, ecto, elixir  Languages elixir

Tested with Ecto 2.2 and Phoenix 1.3.

This module allows you to perform pagination with Phoenix and Ecto:

defmodule Pagination do
  import Ecto.Query
  alias Snippets.Repo
  # ## Example
  #    Snippets.Snippet
  #    |> order_by(desc: :inserted_at)
  #    |> Pagination.page(0, per_page: 10)
  def page(query, page, per_page: per_page) when is_nil(page) do
    page(query, 0, per_page: per_page)

  def page(query, page, per_page: per_page) when is_binary(page) do
    page = String.to_integer(page)
    page(query, page, per_page: per_page)

  def page(query, page, per_page: per_page) do
    count = per_page + 1
    result = query
             |> limit(^count)
             |> offset(^(page*per_page))
             |> Repo.all
    has_next = (length(result) == count)
    has_prev = page > 0
    total_count = Repo.one(from t in subquery(query), select: count("*"))
    page = %{
      has_next: has_next,
      has_prev: has_prev,
      prev_page: page - 1,
      next_page: page + 1,
      page: page,
      first: page*per_page+1,
      last: Enum.min([page+1*per_page, total_count]),
      count: total_count,
      list: Enum.slice(result, 0, count-1)


|> order_by(desc: :inserted_at)
|> Pagination.page(0, per_page: 10)

View helper

defmodule PaginationHelpers do
  import Phoenix.HTML
  import Phoenix.HTML.Form
  import Phoenix.HTML.Link
  import Phoenix.HTML.Tag

  def pagination_text(list) do
    Displaying <%= list.first %>-<%= list.last %> of <%= list.count %>

  def pagination_links(conn, list, route) do
    content_tag :div, class: "pagination" do
      children = []
      if list.has_prev do
        children = children ++ link "Previous", to: route.(conn, :index, page: list.prev_page), class: "btn btn-secondary col-md-1"
      if list.has_next do
        children = children ++ link "Next", to: route.(conn, :index, page: list.next_page), class: "btn btn-secondary col-md-1"


<%= pagination_text(@snippets) %>
<%= pagination_links(@conn, @snippets, &snippet_path/3) %>

Annotated Plug and Elixir Example

Tagged erlang, genserver, otp, cowboy, plug, elixir  Languages bash, elixir

This is an annotated example of a web application written using Elixir and Plug.

Create mix.exs:

# Mix is a build tool that provides tasks for creating, compiling, and testing
# Elixir projects, managing its dependencies, and more.
# https://github.com/hexpm/hex_web/blob/master/mix.exs
defmodule PlugExample.Mixfile do
  # In order to configure Mix, a developer needs to use Mix.Project in a module
  # and define a function named project that returns a keyword list with
  # configuration.
  # http://elixir-lang.org/docs/stable/mix/Mix.Project.html
  use Mix.Project

  # Configure project.
  def project do
    [app: :Router,
      version: "0.0.1",
      elixir: "~> 1.2",
      deps: deps]

  # Returns applications that should be started.
  # In OTP, application denotes a component implementing some specific
  # functionality, that can be started and stopped as a unit, and which can be
  # re-used in other systems as well.
  # http://erlang.org/doc/man/application.html
  def application do
      applications: [:logger, :plug], # 3rd-party applications
      mod: {PlugExample.Supervisor, []} # own application

  # Returns project dependencies:
  # https://hex.pm/
  def deps do
      {:cowboy, "~> 1.0.0"}, # Erlang web server
      {:plug, "~> 1.0"} # Elixir's rack (Ruby), wsgi (Python), servlet (Java) API

Create lib/router.exs

defmodule PlugExample.Router do
  # Plug ships with a router that allows developers to quickly match on
  # incoming requests and perform some action:
  # https://hexdocs.pm/plug/readme.html#the-plug-router
  use Plug.Router
  # This module defines a Plug.Conn struct and the main functions for working with Plug connections.
  # https://hexdocs.pm/plug/Plug.Conn.html
  import Plug.Conn
  # Logs request to STDOUT
  plug Plug.Logger
  # Matches request to a route
  plug :match
  # Dispatches request to a route
  plug :dispatch

  # Start a GenServer, i.e., a server instance:
  # http://elixir-lang.org/getting-started/mix-otp/genserver.html
  # https://blog.drewolson.org/understanding-gen-server/
  def start_link do
    # Cowboy adapter:
    # https://hexdocs.pm/plug/Plug.Adapters.Cowboy.html
    {:ok, _} = Plug.Adapters.Cowboy.http PlugExample.Router, []

  # HTTP GET /
  # Use conn.private to access route options:
  #   conn.private[:protected]
  get "/", private: %{protected: false} do
    conn |> send_resp(200, "Hello world")

  get "/favicon.ico" do
    conn |> send_resp(200, "LOL")
  # Forward /about to another router's get "/" route
  # forward "/about", to: PlugExample.About

  # A catch-all route
  match _ do
    conn |> send_resp(404, "Not found")

Create lib/supervisor.ex

# A supervisor is a process which supervises other processes, called child
# processes. Supervisors are used to build a hierarchical process structure
# called a supervision tree, a nice way to structure fault-tolerant applications.
# http://elixir-lang.org/docs/stable/elixir/Supervisor.html
defmodule PlugExample.Supervisor do
  # In Elixir (actually, in Erlang/OTP), an application is a component
  # implementing some specific functionality, that can be started and stopped as a
  # unit, and which can be re-used in other systems.
  # http://elixir-lang.org/docs/stable/elixir/Application.html
  # http://erlang.org/doc/man/application.html
  # http://erlang.org/doc/design_principles/applications.html
  use Application

  # The type argument passed to start/2 is usually :normal unless in a
  # distributed setup where application takeovers and failovers are configured.
  # start/2 typically returns {:ok, pid} or {:ok, pid, state} where pid
  # identifies the supervision tree and state is the application state.
  def start(_type, _args) do
    # Convenience functions for defining a supervision specification.
    # http://elixir-lang.org/docs/stable/elixir/Supervisor.Spec.html
    import Supervisor.Spec, warn: false
    # A list of children (workers or supervisors) to supervise
    children = [
      worker(PlugExample.Router, [])
    # If a child process terminates, only that process is restarted:
    # http://elixir-lang.org/docs/stable/elixir/Supervisor.html
    opts = [strategy: :one_for_one, name: PlugExample.Supervisor]
    # Start supervisor by passing the children to start_link/2.
    # You may want to use a module-based supervisor.
    Supervisor.start_link(children, opts)

Start the server:

$ mix deps.get
$ iex -S mix

Continue reading: How to deploy an Elixir web application.

How to send emails with Mailgun and Elixir

Tagged httpotion, elixir, mailgun  Languages elixir

This example shows how to send emails with Mailgun and Elixir:

url = "https://api.mailgun.net/v3/xxx.mailgun.org/messages"
headers = [
  "User-Agent": "My App",
  "Content-Type": "application/x-www-form-urlencoded"
params = %{
  "from" => "christian@xxx.mailgun.org",
  "to" => "christian@aktagon.com",
  "subject" => "Hello Christian",
  "text" => "Hello"
body = URI.encode_query(params)
auth = { "api", "key-xxx" }
response = HTTPotion.post url, [body: body, headers: headers, basic_auth: auth]
if !HTTPotion.Response.success?(response) do

Replace the API key and mailgun URL with your own API key and URL.


How to fix "the response was already sent" error in Elixir

Tagged plug, phoenix, elixir  Languages elixir

If you get an “(Plug.Conn.AlreadySentError) the response was already sent” error:

Server: localhost:4000 (http)
Request: POST /api/v1/xxx
** (exit) an exception was raised:
    ** (Plug.Conn.AlreadySentError) the response was already sent
        (plug) lib/plug/conn.ex:332: Plug.Conn.put_status/2

Verify that you have not defined the action plug more than once:

plug :action

Multi-tenancy in Ecto and Phoenix

Tagged multi-tenancy, postgres, phoenix, ecto, elixir  Languages elixir, bash

Creating a new tentant

A new tenant requires a namespace, which is a schema in Postgres, and a prefix in Ecto:

$ psql -U postgres database_x
> create schema aktagon; 

Querying data

import Ecto.Query
email = "christian@aktagon.com"
q = from(m in User, where: m.email == ^email)
Repo.all(%{q | prefix: "aktagon"})

Documentation: https://hexdocs.pm/ecto/Ecto.Query.html#module-query-prefix

Inserting data

   %User{ email: "christian@aktagon.com" },
   prefix: "aktagon"


$ mix ecto.migrate --prefix "aktagon"


  • (KeyError) key :__meta__ not found

I got this error when passing a changeset to Ecto.put_meta instead of a User struct.

Elixir Deployment

Tagged rollback, deployment, elixir, exrm, deploy, upgrade, distillery  Languages elixir, bash


Development environment:

  1. Sign up for a Gitlab account, or use your favorite git server
  2. Create a (private) repository
  3. Create a deploy key that allows read-only access to your private repository (optional, if public)
  4. Commit code to the repository


You will need Elixir:

$ sudo apt-get install elixir


Add distillery to the list of dependencies:

def deps do
   {:distillery, "~> 0.9.9"},

Run mix release.init and follow the instructions:

$ mix release.init

An example config file has been placed in rel/config.exs, review it,
make edits as needed/desired, and then run `mix release` to build the release

Next, run mix release:

You can run it in one of the following ways:
  Interactive: rel/xxx/bin/xxx console
  Foreground: rel/xxx/bin/xxx foreground
  Daemon: rel/xxx/bin/xxx start


Production environment:

  1. Clone project
$ cd /var/www
$ git clone git@gitlab.com:christianhellsten/aktagon-snippets.git
  1. Create a release
$ MIX_ENV=prod mix do deps.get, clean, compile
$ MIX_ENV=prod mix release --verbosity=verbose
  1. Create a monit start script
# Run "ps -ef | grep beam, if you get status "Does not exist" from "monit status"
check process snippets MATCHING "rel/snippets"
    start program = "/bin/su - deploy -c '/var/www/aktagon-snippets/rel/snippets/bin/snippets start'"
    stop program = "/bin/su - deploy -c '/var/www/aktagon-snippets/rel/snippets/bin/snippets stop'"
  1. Start server
$ sudo monit start snippets

Deploying a new version

First increment the version number. Then perform the hot upgrade:

$ git pull
$ export MIX_ENV=prod
$ mix do compile
$ mix release --upgrade 

$ rel/snippets/bin/snippets upgrade "0.0.2"

Rolling back to a previous version

How to perform hot downgrades:

$ rel/snippets/bin/snippets downgrade "0.0.1"

See https://hexdocs.pm/distillery/getting-started.html


See Using Distillery With Phoenix.