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 %>

results matching ""

    No results matching ""