Today I Learned

A Hashrocket project

147 posts about #elixir

Send an event to a Channel from outside Phoenix

So this one was non-obvious to me.

In the following example, any module on any process can call TopicChannel.send_to_channel/1and that will be handled by the handle_info call below and sent to the socket.

defmodule MyAppWeb.TopicChannel do
  use Phoenix.Channel

  def send_to_channel(data) do
    Phoenix.PubSub.broadcast(
      MyApp.PubSub, 
      "topic:subtopic",
      %{type: "action", payload: %{data: data}
    )
  end

  def join("topic:subtopic", message, socket) do
    {:ok, socket}
  end
  
  def handle_info(%{type: "action"}=info, socket) do
    push socket, "action", info

    {:noreply, socket}
  end
end

Parameter filtering in Elixir Phoenix logs

Sometimes you want to filter out parameters that are being logged (think GDPR compliance). Enter Phoenix’s handy config filter_parameters :

config :phoenix, :filter_parameters, ["password", "birthday"]

Or if you want to be extra safe, you can filter all parameters and only whitelist ones you want to see. For example: id and order:

config :phoenix, :filter_parameters, {:keep, ["id", "order"]}

Enable gzip for all phoenix responses

Enabling gzip for static assets in phoenix couldn’t be simpler. In lib/myapp_web/endpoint.ex change gzip from false to true:

 plug(Plug.Static, at: "/", from: :tilex, gzip: true, only: ~w(assets ...))

But why stop there? We can compress our dynamic document bodies just as easily. In config/prod.exs, add compress: true to the http config of the endpoint.

config :my_app, MyAppWeb.Endpoint,
  http: [port: {:system, "PORT"}, compress: true]

Client Connection Vars with Ecto

Postgres has dozens of connection variables it will take, a couple of my favorite ones are statement_timeout and application_name.

Ecto takes a parameters connection option, which is a keyword list of connection parameters.

# dev.exs

...

# Configure your database
config :myapp, Myapp.Repo,
  adapter: Ecto.Adapters.Postgres,
  database: "myapp_dev",
  socket_dir: "/var/run/postgresql",
  parameters: [application_name: "My App Development", statement_timeout: "5000"],
  pool_size: 10



Example of statement_timeout being respected in Ecto:

Ecto.Adapters.SQL.query!(Myapp.Repo, "select pg_sleep(86400)")

** (Postgrex.Error) ERROR 57014 (query_canceled): canceling statement due to statement timeout
    (ecto) lib/ecto/adapters/sql.ex:200: Ecto.Adapters.SQL.query!/5


Client Connection Variables references: https://www.postgresql.org/docs/current/static/runtime-config-client.html

Use a unix socket with Ecto

Ecto allows the use of a unix socket to connect to postgres, instead of TCP. In order to use a unix socket in a exs file, you should remove the hostname list item, and provide the socket_dir list item.

# dev.exs

...

# Configure your database
config :myapp, Myapp.Repo,
  adapter: Ecto.Adapters.Postgres,
  database: "myapp_dev",
  socket_dir: "/var/run/postgresql",
  pool_size: 10

Elixir String Manipulation

To get the list of string that compose a longer string, use String.codepoints/1

iex> cdp =  String.codepoints("abcdefg")
["a", "b", "c", "d", "e", "f", "g"]
iex> Enum.at(cdp, 0)
"a"

To get the list of codepoints that represent each letter in the string, use String.to_charlist/1

iex> chr = String.to_charlist("abcdefg")
'abcdefg'
iex> Enum.at(chr, 0)
97

Shell Out With Elixir

Today I wrote a staging and production deploy script for Tilex, learning about System.cmd/3 along the way. The first argument to this function is the command, the second are arguments, and the third are options.

Here’s an example implementation from our script that deletes a Git tag and pushes that updated reference to origin:

System.cmd("git", ["tag", "-d", "staging"])
System.cmd("git", ["push", "origin", ":refs/tags/staging"])

Get application's current version in production

If you use Distillery to produce Elixir releases for production you may be in a situation where your application is deployed and running but you are not sure what version is loaded into memory.

To verify the version:

  1. SSH into your server
  2. navigate into the bin directory of your release (e.g. app_release/your_project/bin)
  3. run the remote console ./your_project remote_console
  4. Run the spec function on Application: Application.spec(:your_project, :vsn)

You will get back a string such as ‘0.0.1’.

Mix xref and Elixir compiler warnings

The release of Elixir v1.3 added a mix task called xref for performing cross reference checks of your code. mix xref gives us some handy tools!

Find unreachable code:

❯ mix xref unreachable
lib/exonk8s/foo.ex:16: SomeModule.non_existant/0

Find callers of modules and functions:

❯ mix xref callers SomeModule
lib/exonk8s/foo.ex:16: SomeModule.non_existant/0

Generate a dependency graph:

> mix xref graph
lib/exonk8s.ex
├── lib/exonk8s/repo.ex
└── lib/router.ex
    └── lib/exonk8s/musician_controller.ex (compile)
        ├── lib/exonk8s/foo.ex
        ├── lib/exonk8s/musician.ex
        └── lib/exonk8s/repo.ex
...snipped for brevity

The release of Elixir v1.6 added the module attribute @deprecated to enable library authors to warn users of deprecated functions.

❯ mix xref deprecated
Compiling 2 files (.ex)
Foo Loaded
warning: ExOnK8s.Foo.lazy/0 is deprecated. You should be more eager.
  lib/exonk8s/musician_controller.ex:10

lib/exonk8s/musician_controller.ex:10: ExOnK8s.Foo.lazy/0

Lastly I should note that xref deprecated and xref unreachable are included in the compiler warnings, so you you’ve likely seen these at work even if you didn’t know they were there.

Learn more

Add Elixir files to your compiled list

While working on an Elixir package today, I wanted to add the test/support directory to my compiled files. I knew the Phoenix Framework did this so I went there to take a look and discovered elixirc_paths.

The Phoenix frameworks example looks like this:

  # mix.exs
  def project do
    [
      ...
      elixirc_paths: elixirc_paths(Mix.env),
      ...
    ]
  end
  defp elixirc_paths(:test), do: ["lib", "test/support"]
  defp elixirc_paths(_),     do: ["lib"]

Perfect! Now we can add additional directories to our compiled path that are environment specific.

Your slowest Elixir tests

Sometimes its handy to see what tests are taking the longest in an Elixir project.

Enter mix test --slowest N

Just replace N with how many slow tests you would like to see and you’ll get some handy output:

$ mix test --slowest 5

Top 5 slowest (17.6s), 30.2% of total time:
  * test enters a body that is too long (4504.4ms) (DeveloperCreatesPostTest)
  * test the page does not have a Create Post link (4384.9ms) (VisitorVisitsHomepageTest)
  * test and clicks 'like' for that post (3944.2ms) (VisitorViewsPostTest)
  * test fills out form and updates post from post show (2558.6ms) (DeveloperEditsPostTest)
  * test fills out form and submits (2255.5ms) (DeveloperCreatesPostTest)

Phoenix Select Form Helper

The select form helper allows you to easily add a select input to your forms.

= form_for @changeset, resource_path(@conn, :create), fn f ->
  = select f, :book_id, @books
  = submit "Save Post", class: "btn"

Among the types of arguments that the select helper can accept are two-item tuples. The first item in the tuple is used as the label for the option and the second item is used as the value for the option.

Media.list_books returns a list of structs representing all of the books in the database. We’ll need to get from a list of structs to a list of tuples.

To do that, we’ll pipe the list of Book structs to Enum.map and use an anonymous function to generate two-value tuples from those structs.

def new(conn, _params)
  ...
  books =
    Media.list_books
      |> Enum.map(&{"#{&1.title} by #{&1.author}", &1.id})

  render conn, "new.html", changeset: changeset, books: books
end

Aliasing an Elixir Module Within Itself

I was attempting to compile a Phoenix application and I got this error:

Post.__struct__/0 is undefined, cannot expand struct Post

The issue was in a function I defined in the module.

def changeset(%Post{}= post, attrs \\ %{}) do
    ...
end

I assumed that you would get references to a module within said module for free. That’s not the case. There are two ways to fix the error. One is to use the full module name in the parameter list.

def changeset(%Forum.Post{}= post, attrs \\ %{}) do
    ...
end

Alternatively, I can alias the module within itself.

alias Forum.Post

Comply with the erlang IO protocol

Below is a basic IO server/device implementation, it receives an :io_request message and responds with a :io_reply message.

defmodule MYIODevice do
  def listen() do
    receive do
      {:io_request, from, reply_as, {:put_chars, :unicode, message}} ->
        send(from, {:io_reply, reply_as, :ok})
        IO.puts(message)
        IO.puts("I see you")
        listen()
    end
  end
end

pid = spawn_link(MYIODevice, :listen, [])

IO.puts(pid, "Hey there")

The above code outputs the following to stdout:

Hey there
I see you

The first argument of IO.puts/2 is a pid representing the device that is being written to, it is generally defaulted to :stdio)

The documentation is dense, enjoy! Erlang IO Protocol

H/T Brian Dunn

Checking that an association is loaded

Ecto will NOT load associations automatically, that is something that you must do explicitly and sometimes you might expect an association to be loaded but because of the code path travelled, it is not.

You can check to see if an association is loaded with Ecto.assoc_loaded?

case Ecto.assoc_loaded?(post.channel) do
  true -> IO.puts('yep its loaded')
  false -> IO.puts('you do not have the data')
end

Mix tasks accessing the db with `Mix.Ecto`

When running reports or one-off data operations it might be necessary to create a mix task that can access the database. Ecto provides convenience functions in the Mix.Ecto module to help facilitate setting up and starting the Ecto repos.

The function parse_repo(args) will process the arguments used when calling the mix task. It looks specifically for -r MyApp.Repo but if you don’t pass anything it will return all the repos from the configuration.

The function ensure_started(repo) takes the repo as an argument ensures that the Repo application has been started. Without calling this function the Repo will throw an error when used.

Put it all together:

defmodule Mix.Tasks.MyApp.SayHi do
  use Mix.Task
  import Mix.Ecto

  def run(args) do
    repo = parse_repo(args) |> hd

    ensure_started(repo)

    result = repo.query("select 'hi!';")

    result.rows
    |> hd
    |> hd
    |> IO.puts
  end
end

Print Information about an Elixir Data Type

IEx ships with a neat feature, def i(term \\ v(-1)), which provides information about an argument. Here are two examples:

iex(1)> i ["one", "two"]
Term
  ["one", "two"]
Data type
  List
Reference modules
  List
Implemented protocols
  IEx.Info, Collectable, Enumerable, Inspect, List.Chars, String.Chars
iex(1)> i "three"
Term
  "three"
Data type
  BitString
Byte size
  5
Description
  This is a string: a UTF-8 encoded binary. It's printed surrounded by
  "double quotes" because all UTF-8 encoded codepoints in it are printable.
Raw representation
  <<116, 104, 114, 101, 101>>
Reference modules
  String, :binary
Implemented protocols
  IEx.Info, Collectable, Inspect, List.Chars, String.Chars

Use this to inspect an item, or learn more about Elixir.

`with` statement has an `else` clause

with statements are used to ensure a specific result from a function or series of functions, using the results of those functions to take actions within the with block. If a function does not return a specific result (think :error instead of :ok) then you can either define specific clauses for the things you expected to go wrong, or you can just return the result that did not conform to the with clause expectations.

This is the general form:

with {:ok, a} <- {:ok, 123} do
  IO.puts "Everythings OK"
end

A with with an else block:

with {:ok, a} <- {:error, 123} do
  IO.puts "Everythings OK"
else 
  result -> IO.puts("Not OK")
end

A with else clause with pattern matching:

with {:ok, a} <- {:error, "something went wrong"} do
  IO.puts "Everythings OK"
else 
  {:error, message} -> IO.puts(message)
  error -> IO.puts("I'm not sure what went wrong
end

A with without an else clause where the error is returned from the with block:

result = with {:ok, a} <- {:error, "something went wrong"} do
  IO.puts "Everythings OK"
end

{:error, message} = result
IO.puts "This went wrong #{message}"

Exit IEx Gracefully with `respawn()`

I love a debugger in my Elixir code. A pattern I follow is to load and call IEx in a Phoenix template or controller with:

require IEx; IEx.pry;

Then, I call functions and check data in the middle of an action, by starting my Phoenix server with the following command:

$ iex -S mix phx.server

Once finished, I usually end up just killing the server with CTRL-C.

Today I learned there’s a better way: respawn().

respawn() respawns the current shell by starting a new shell process. Which I think is a good thing. It lets me back out of my IEx session without killing my server, a much more graceful development experience.

View your outdated packages

To see which packages in a mix app need updating, you can run mix hex.outdated

$ mix hex.outdated
Dependency           Current  Latest  Update possible
appsignal            1.3.2    1.3.3   Yes
basic_auth           2.1.4    2.1.4
cachex               2.1.0    2.1.0
...

It prints out a handy table letting you quickly view the current and latest versions and if they can be updated. If Update possible is No, check your semantic version lockdown of that package in mix.exs.

mix hex.outdated accepts a few arguments:

  • --all which shows all outdated packages, including children of packages defined in mix.exs
  • --pre which include pre-releases when checking for newer versions (be adventurous!)

Happy updating!

Generate New Phoenix App Without Brunch

By default when you create a new Phoenix app using phx.new, a set of files and configurations will be generated for Brunch. Though the Phoenix team decided to use Brunch, you don’t have to. You may not want Phoenix to handle asset building or you may just prefer another build tool. Either way, if you’d like to opt out, you can include the --no-brunch flag when generating the project.

$ mix phx.new --no-brunch my_app

If you have an existing project that you’d like to remove Brunch from, there is some information in Phoenix’s Static Assets documentation.

Visualize Your Elixir Dependencies

To visualize your Elixir dependencies, try this:

$ mix deps.tree

This prints a tree showing your dependencies (and their dependencies):

$ mix deps.tree
tilex
├── gettext ~> 0.13 (Hex package)
├── hackney 1.8.0 (Hex package)
│   ├── certifi 1.1.0 (Hex package)
│   ├── idna 4.0.0 (Hex package)
│   ├── metrics 1.0.1 (Hex package)
│   ├── mimerl 1.0.2 (Hex package)
│   └── ssl_verify_fun 1.1.1 (Hex package)

This is really handy when trying to track down where a deprecation warning or error is coming from.

h/t Dorian Karter

Serve Static Assets From Custom Phoenix Directory

When you new up a Phoenix project, an endpoint.ex file will be generated. This file is full of different plugs for handling incoming traffic. The Plug.Static declaration specifies how your application will handle and serve requests for static files.

  plug Plug.Static,
    at: "/", from: :my_app, gzip: false,
    only: ~w(css fonts images js favicon.ico robots.txt)

The from options declares where these static files are located. In this case it references our application (:my_app) as the target which will translate to its priv/static directory.

If you instead want to serve your files from a different, custom directory, you can replace it with the path to that directory.

  plug Plug.Static,
    at: "/", from: "priv/my_frontend/static", gzip: false,
    only: ~w(css fonts images js favicon.ico robots.txt)

source

Implied applications and `extra_applications`

In your mix file (mix.exs) the application function returns a keyword list. Two options in that list determine what applications are started at runtime.

The applications is by default implied based on your app’s dependencies. The default list is thrown away through if this option is set in your mix.exs file.

If you want to add an extra application without disrupting the default, implied list then you can add the optionextra_applications. This leaves the default, implied list of applications untouched.

H/T Jose Valim PR

def application do
[
  mod: {Tilex, []},
  extra_applications: [:logger]
]
end

Specifying The Digest Directory For Phoenix

By default, Phoenix targets priv/static when preparing digested assets for production. This process happens when running mix phx.digest.

If you are doing some custom work with your assets such that they are in a different location, you’ll need to tell Phoenix where to look. To do this, just include an optional path argument.

$ mix phx.digest path/to/my/assets

The digests will be put in that target directory. If you’d like to specify a different output directory, such as priv/static, include the -o flag.

$ mix phx.digest path/to/my/assets -o priv/static

Joining URI parts in Elixir

Elixir 1.3 introduced a standard way to join URIs.

For example, say we have a base URI for an API: https://api.hashrocket.com and different endpoints on that URI: events, developers, applications.

To join the URI into one properly formatted string:

def endpoint_uri(endpoint) do
  "https://api.hashrocket.com"
  |> URI.merge(endpoint)
  |> URI.to_string()
end

# then call it

endpoint_url("events") # => "https://api.hashrocket.com/events"

URI.merge accepts both strings and URI structs as the first object so you can easily continue adding URI parts to the pipeline including query params:

"https://test.com"
|> URI.merge("events") 
|> URI.merge("?date=today") 
|> URI.to_string()

# => "https://test.com/events?date=today"

Conditional Variables in Phoenix Templates

A common Ruby on Rails technique is setting instance variables in a controller action, then using them in the view layer:

# app/controllers/users_controller.rb
def show
  @show_button = true
end
# app/views/users/show.html.haml
- if @show_button
  .button

Doing the same thing in Elixir/Phoenix is a little different.

Since Phoenix 0.14.0, the framework raises on missing assigns (link). Thus our conditional will fail on any loaded template whose controller function that does not define the variable.

One solution is to check if the variable is assigned:

# lib/my_app_web/templates/users/show.html.eex
<%= if assigns[:show_button] do %>
  <div class="button"></div>

If show_button is assigned in your controller function (via assign), the button will be displayed. If not, the button will not be displayed, and the application will not raise an error.

Run an Elixir function on Module load

If you want to run a function on Module load, you can turn to Modules @on_load hook.

#hello_world.ex
defmodule Example do
  @on_load :hello_world

  def hello_world do
    IO.puts("Hello World!")
    :ok
  end
end
$ elixir hello_world.ex
Hello World!

Your function must return :ok otherwise the module load will be aborted.

Using @on_load can be an efficient way to run examples, quick scripts, setup requirements, benchmarking or load in libraries from other languages.

Converting strings to atoms safely

If your elixir system accepts any outside inputs and takes any part of those outside inputs and calls String.to_atom with the input as an argument then your elixir system is subject to a denial of service attack.

Malicious actors can submit input designed to dynamically create a large number of atoms until the atom limit is reached, knocking out your elixir applications.

Consider using String.to_existing_atom instead. If the argument to this function cannot be converted to an existing atom then an exception will be thrown.

> String.to_existing_atom("I don't exist")
** (ArgumentError) argument error
    :erlang.binary_to_existing_atom("nothere", :utf8)
> String.to_atom("I don't exist")
:"I don't exist"
> String.to_existing_atom("I don't exist")
:"I don't exist"

Current number of atoms in the atoms table

In Elixir and Erlang there is a hard limit on the number of atoms you can create. Atoms are not garbage collected so its important to ensure you don’t exceed the limit. You can check what the limit is with:

> :erlang.system_info(:atom_limit)
1048576

Likewise, you can check the current number of atoms in the atoms table with:

> :erlang.system_info(:atom_count)
9654

On my system using Elixir 1.5.1 I use 9654 atoms just to start iex.

Magically insert `iex -S` in front of a command

Often times you need to execute an elixir function with iex to enable pry breakpoints.

I found that I was doing a lot of fumbling in zsh to go back to the previous command, jump to the beginning of it and type out iex -S.

Since I like to automate repeatitive processes, I came up with this:

bindkey -s "^Xi" "^[Iiex -S ^[A"

Dump this line in your .zshrc or .bashrc and then all you have to do is Ctrl+xi to insert iex -S in front of the previously ran command.

preview

Magic. 🎩

Looking at the state of processes in Elixir

When debugging gen_server, gen_statem and gen_event processes it can be helpful to take a look at the state.

Its easy to do this in Elixir by calling out to Erlangs sys.get_state/1:

iex(1)> defmodule Example, do: use GenServer
iex(2)> {:ok, pid} = GenServer.start_link(Example, %{ping: "pong"})
iex(3)> :sys.get_state(pid)
%{ping: "pong"}

For more common sys debugging functions, take a look here

CamelCase to underscore and back again w/Elixir

If you have a mix project name with multiple words, then those multiple words are generally separated with underscores in the project directory name, like honey_bears. The module name for the project however is HoneyBears.

Converting a string from underscore to CamelCase is built into Elixir. Its in the Macro module:

> Macro.camelize("honey_bear")
"HoneyBear"

The reverse case also can be solved with a Macro function.

> Macro.underscore("HoneyBear")
"honey_bear"

The Macro module has a number of convience functions for working with macros.

Configure max http header size in Elixir Phoenix

If you store lots of data in cookies, you may eventually run up against the maximum header value length in Cowboy which by default is 4096.

While storing that much data in cookies is maybe not the best idea, there is a configuration setting that can help you work around this issue:

config :myapp, MyAppWeb.Endpoint,                                                                                                                 
  http: [protocol_options: [max_request_line_length: 8192, max_header_value_length: 8192]]

There ya go! Now you can accept http header values up to 8192 bytes in length!

Phoenix will watch your JS for you, just watch!

With es6 javascript ecosystems most compilation/transpilation is done with watchers, programs that watch for changes in your code and then trigger compilation based on the changes you’ve made.

Phoenix has a method of integrating those watchers into the server itself.

config :myapp, MyApp.Endpoint,
  watchers: [yarn: ["run", "watch", cd: Path.expand("../assets", __DIR__)]]

The above configuration goes in config/dev.exs and runs the watch command whenever you start the server/endpoint. The keyword option cd is as of yet undocumented, but does what you think it does, changes the directory to the path you configure, which by convention in Phoenix 1.3 would be the assets directory. cd is the only keyword option.

The watchers start when you run your server. Just make a change to your javascript and refresh the page!

Execute raw parameterized sql with Ecto in Elixir

Using sql directly is a good way to use some of the more interesting parts of sqlthat Ecto does not provide a ready abstraction for in its dsl. And parameterization is necessary to avoid sql injection and just to be able to deal with single quotes correctly. Its fairly straight forward once you find the right module (Ecto.Adapters.SQL) and function (query or query!). Parameters are indicated by $1.

sql = """
  select * from users where name = $1;
"""

results = Ecto.Adapters.SQL.query!(MyApp.Repo, sql, ["chris"])

There is also a stream function on the Ecto.Adapters.SQL module with the same signature as query but the documentation doesn’t necessarily state the advantages or situations where it may be useful. More to learn.f8

Load all records for an association in Ecto

Lets say you get a collection of Posts with:

posts = Repo.all(Post)

If you try to access the associated developer for one of these posts, you get an error:

hd(posts).developer
#Ecto.Association.NotLoaded<association :developer is not loaded>

The same is true for all posts in the collection, none of them have a loaded developer. You can load them one by one with:

developer = Tilex.Repo.one(Ecto.assoc(post, :developer))

But if you need to do this for each developer you’ll get into an N+1 situation, making an additional trip to the database for each post.

Instead you can load all the developers at one time with:

posts = Repo.preload(posts, :developer)

Clearing Phoenix npm cache on Heroku

I recently encountered an issue where the solution, as found on the internet, was to remove all the npm_modules, re-install them and build again. My issue however was on Heroku rather than local.

If you’re using Elixier and Phoenix on Heroku then you’re likely using the heroku-buildpack-phoenix-static. This buildpack compiles the static assets for Phoenix.

This buildpack caches npm_modules by default, to clear the cache you must provide a configuration file at the root level of your project named phoenix_static_buildpack.config that looks like:

clean_cache=true

The buildpack will now download the npm_modules on each deployment.

What applications are running in your Elixir app?

Ever wonder what applications are running in your Elixir or Phoenix app?

Pop open IEx and take a look with Applications.started_applications/1

iex(1)> Application.started_applications
[{:tilex, 'tilex', '0.0.1'},
 {:ueberauth_google, 'An Uberauth strategy for Google authentication.',
  '0.6.0'},
 {:ueberauth, 'An Elixir Authentication System for Plug-based Web Applications',
  '0.4.0'}, {:oauth2, 'An Elixir OAuth 2.0 Client Library', '0.9.1'},
 {:timex,
  'Timex is a rich, comprehensive Date/Time library for Elixir projects, with full timezone support via the :tzdata package.\nIf you need to manipulate dates, times, datetimes, timestamps, etc., then Timex is for you!\n',
  '3.1.24'},
 {:combine, 'A parser combinator library for Elixir projects.', '0.9.6'},
 {:tzdata, 'Tzdata is a parser and library for the tz database.\n', '0.5.12'},
 {:postgrex, 'PostgreSQL driver for Elixir.', '0.13.3'},
 {:db_connection,
  'Database connection behaviour for database transactions and connection pooling\n',
  '1.1.2'},
 {:connection, 'Connection behaviour for connection processes\n', '1.0.4'},
 {:phoenix_html,
  'Phoenix.HTML functions for working with HTML strings and templates',
  '2.10.2'}, {:phoenix_ecto, 'Integration between Phoenix & Ecto', '3.2.3'},
 {:ecto, 'A database wrapper and language integrated query for Elixir.\n',
  '2.1.4'}, {:poolboy, 'A hunky Erlang worker pool factory', '1.5.1'},
 {:decimal, 'Arbitrary precision decimal arithmetic.', '1.4.0'},
........

Enable history in IEX through #erlang (OTP 20) ⏳

If you are using the latest version of Erlang, OTP 20 now ships with shell history, so you can use Ctrl-p / Ctrl-n or the up/down arrow keys.

The shell history is turned off by default though, so you will have to turn it on by adding the following to your .zshrc/.bashrc etc.

export ERL_AFLAGS="-kernel shell_history enabled"

Once you do that make sure to source your bash config file or open a new window.

Every subsequent iex session will now have shell history. 🚀

Setting breaks in IEx for debugging

With the release of Elixir 1.5 comes some handy new IEx helpers, one of which is the ability to add break points throughout your code.

You can add a break to any function using break!/2 or break!/4:

defmodule MyModule do
  def hello(name) do
    "hello " <> name
  end
end
iex(1)> break!(MyModule.hello/ 1)
or
iex(1)> break!(MyModule, :hello, 1)

Both break/2 and break/4 accept an additional argument for how many stops you want to make. Useful for recursive functions where you may want to stop multiple times.

To see what breaks you have use breaks/0

iex(1)> breaks()
 ID   Module.function/arity   Pending stops
---- ----------------------- ---------------
 1    MyModule.hello/1        1

Now when you call the function, you’ll be placed into the a debugger and you can inspect whats being passed in:

iex(4)> MyModule.hello("world")
Break reached: MyModule.hello/1 (lib/my_module.ex:2)
    1: defmodule MyModule do
    2:   def hello(name) do
    3:     "hello " <> name
    4:   end
pry(1)> name
"world"

To exit the break and start a new shell process use respawn/0

pry(2)> respawn
Interactive Elixir (1.5.0) - press Ctrl+C to exit (type h() ENTER for help)
"hello world"
iex(1)>

GenServer child_spec/1 in Elixir 1.5

Elixir 1.5 GenServer introduces overridable child_spec/1. Now instead of, in your application supervisor, calling;

# MyExample.Application
def start(_type, _args) do
  children = [
    worker(MyExample.MyChild, [], restart: :permanent, shutdown: 5000)
  ]
end

You can now let the child decide how its supposed to be implemented by overriding child_spec/1 in the child.

#MyExample.Application
def start(_type, _args) do
  children = [ 
    MyExample.MyChild
   ]
end

# MyExample.MyChild
def child_spec(_args) do
  %{
    id: __Module__,
    start: { __Module__, :start_link, []},
    restart: :permanent,
    shutdown: 5000,
    type: :worker
   }
end

You can view the defaults that child_spec/1 implements in the source code.

Arguments can be passed to child_spec/1 which can then be used for pattern matching and custom configurations based on the supervisor accessing it:

#MyExample.Application
def start(_type, _args) do
  children = [ 
    {MyExample.MyChild, "temporary"}
   ]
end

# MyExample.MyChild
def child_spec("temporary") do
  %{
    id: __Module__,
    start: { __Module__, :start_link, []},
    restart: :temporary,
    shutdown: 5000,
    type: :worker
   }
end

def child_spec(_) do
  %{
    id: __Module__,
    start: { __Module__, :start_link, []},
    restart: :permanent,
    shutdown: 5000,
    type: :worker
   }
end

Terminate incomplete expression in IEx

Occasionally you get stuck in an incomplete expression while in IEx. Instead of figuring out which character you need to type to terminate the expression, you can terminate early with #iex:break

iex(1)> ["ab
...(1)> c"
...(1)> "
...(1)> ]
...(1)> #iex:break
** (TokenMissingError) iex:1: incomplete expression
iex(1)>

Another shortcut to achieve the same result is hit ctrl-g (User switch command), i (interrupt job), c (connect to job). This puts you right back in IEx.

iex(1)> ["ab"
iex(1)>   <<<ctrl-g typed here>>>
User switch command
 --> i
 --> c
Bug Bug ..!!** (EXIT) interrupted
iex(1)>

Require local package in mix.exs

In Elixir as you are writing your application it is recommended to split parts of it into smaller applications (also can be called micro-services if you want to be buzzword compliant).

You don’t however need to publish those dependencies to the Hex package manager in order to load them, instead you can use the path argument when defining a dependency.

In this example we have our main application Foo and in the directory above it we have an application called Bar.

To make the Bar module available in Foo we can do it like so:

mix.exs

defp deps do
  [
    {:bar, path: "../bar"},
  ]
end