Programming Phoenix は Phoenix 1.0 をベースにして書かれていますが、バージョン 1.1.0 で gettext 対応が入ったため、下記引用の部分はそのままだとエラーになって動きません(ネット上のいくつかのサンプルも、同様のロジックのものがありますね)。
原因と対策がわかるまで2〜3時間悩んだため、他の人が同じ罠を踏まないように共有しておきます。
<%= if f.errors != [] do %>
<div class="alert alert-danger">
<p>
Oops, somthing went wrong! Please check the errors below:
</p>
<ul>
<%= for {attr, message} <- f.errors do %>
<li>
<%= humanize(attr) %> <%= message %>
</li>
<% end %>
</ul>
</div>
<% end %>
モデルの changeset() で、
validate_length(:password, min: 10)
などのように min/max を指定していると、その field の errors の値は{"should be at least %{count} character(s)", [count: 2]}
のような tuple として返ってきます。そのため、上記サンプルのように <%= message %>
としてセットしようとすると、
no function clause matching in Phoenix.HTML.Safe.Tuple.to_iodata/1
というエラーが表示されて動きません。
Phoenix 1.0.x to 1.1.0 upgrade instructions によると、1.1.0 からは web/views/error_helpers.ex
で translate_error というメソッドが追加されているため、下記のように message を translate_error に渡すことで、正常に表示されるようになります。
<%= for {attr, message} <- form.errors do %>
<li><%= humanize(attr) %> <%= translate_error(message) %></li>
<% end %>