3 - 建立使用者
建立 User model: mix  phoenix.gen.model User users username:string password:string encrypted_password:string  email:string
修改一下 migration檔案, 讓 email欄位是唯一
#priv/repo/migration/XXXX_create_user.exs
  def change do
    create table(:users) do
      add :username, :string, null: false
      add :password, :string
      add :encrypted_password, :string
      add :email, :string,  null: false
      timestamps()
    end
    create unique_index(:users, [:email])
  end
model 檔案, password設定成 virtual這樣資料庫就不會把它記下來,因為想記下來的是加密過的密碼
#web/models/user.ex
  schema "users" do
    field :username, :string
    field :password, :string, virtual: true
    field :encrypted_password, :string
    field :email, :string
    timestamps()
  end
  @doc """
  Builds a changeset based on the `struct` and `params`.
  """
  def changeset(struct, params \\ %{}) do
    struct
    |> cast(params, [:username, :email])
    |> validate_required([:username, :email])
  end
再來做密碼加密
我們會用到 comeonin 這個 mix library
#mix.exs
def application do
  [mod: {Rumbl, []},
   applications: [:phoenix, :phoenix_pubsub, :phoenix_html, :cowboy, :logger, :gettext,
                  :phoenix_ecto, :postgrex, :comeonin]]
end
defp deps do
    [...,
   {:comeonin, "~> 2.0"}]
end
輸入 mix deps.get 安裝 comeonin
再來呢,剛剛在 models/user.ex 定義過 changeset
不過那只有 validate 帳號和使用者名稱
現在要 pipe 這個 function 去驗證密碼
並把密碼用 Comeonin 加密
新增兩個 function
#models/user.ex
  def registration_changeset(model, params) do
    model
    |> changeset(params)
    |> cast(params, ~w(password), [])
    |> validate_length(:password, mix: 6, max: 100)
    |> put_pass_hash()
  end
  defp put_pass_hash(changeset) do
    case changeset do
      %Ecto.Chageset{valid?: true, changes: %{password: pass}} ->
        put_change(changeset, :encrypted_password, Comeonin.Bcrypt.hashpwsalt(pass))
      _ ->
        chageset
    end
  end
新增 User controller
新增 controller 並加入 new, create
建立 User 的 index、show 頁面
#web/route.ex
  scope "/", ShoppingSite do
    pipe_through :browser # Use the default browser stack
    resources "/users", UserController, only: [:new, :create]
    get "/", PageController, :index
  end
建立 UserController
#web/controller/user_controller.ex
defmodule ShoppingSite.UserController do
  use ShoppingSite.Web, :controller
  alias ShoppingSite.User
  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.registration_changeset(%User{}, user_params)
    case Repo.insert(changeset) do
      {:ok, user} ->
        conn
        |> put_flash(:info, "#{user.username} created")
        |> redirect(to: page_path(conn, :index))
      {:error, changeset} ->
        render conn, "new.html", changeset: changeset
    end
  end
end
#web/views/user_view.ex
defmodule ShoppingSite.UserView do
  use ShoppingSite.Web, :view
end
新增 new.html頁面
#templates/user/new.html
<h1>Create an account</h1>
<%= if @changeset.action do %>
  <div class="alert alert-danger">
    <p>Oops! something went wrong!</p>
  </div>
<% end %>
<%= form_for @changeset, user_path(@conn, :create) , fn f -> %>
  <div class="form-group">
    <%= text_input f, :email, placeholder: "E-mail", class: "form-control" %>
    <%= error_tag f, :name %>
  </div>
  <div class="form-group">
    <%= text_input f, :username, placeholder: "Name", class: "form-control" %>
    <%= error_tag f, :username %>
  </div>
  <div class="form group">
    <%= password_input f, :password, placeholder: "Password", class: "form-control" %>
    <%= error_tag f, :password %>
  </div>
  <br>
  <%= submit "Create account", class: "btn btn-primary" %>
<% end %>