14 - 建立訂單
我們在check_out.html
裡面引入 order_form.html
,並將 submit連到 order
的 create
,所以需要 OrderController
的 create
方法才能建立訂單,而且要先登入才能結帳
#web/controllers/order_controller.ex
alias ShoppingSite.Order
alias ShoppingSite.OrderItem
alias ShoppingSite.Repo
import ShoppingSite.UserController, only: [authenticate: 2]
import ShoppingSite.CartController, only: [current_cart: 1]
plug :authenticate when action in [:create]
def create(conn, %{"order" => order_params}) do
new_order_params =
order_params
|> Map.put("user_id", Integer.to_string(conn.assigns.current_user.id))
|> Map.put("total", Integer.to_string(get_total_price(conn)))
order_changeset =
Order.changeset(%Order{}, new_order_params)
if order_changeset.valid? do
case Repo.insert(order_changeset) do
{:ok, order} ->
build_order_item(conn, order)
ShoppingSite.Cart.clean_cart_items(current_cart(conn))
conn
|> put_flash(:info, "Order created successfully")
|> redirect(to: cart_path(conn, :index))
{:error, order_changeset} ->
render(conn, "index.html", changeset: order_changeset)
end
else
conn
|> put_flash(:warning, "something wrong")
|> redirect(to: cart_path(conn, :index))
end
end
在 app.html
加入 warning
#web/templayes/layout/app.html.eex
<p class="alert alert-info" role="alert"><%= get_flash(@conn, :info) %></p>
<p class="alert alert-danger" role="alert"><%= get_flash(@conn, :error) %></p>
+<p class="alert alert-warning" role-"alert"><%= get_flash(@conn, :warning) %></p>
我們從填寫表單建立好 order
的 :info
後,就會進來這個create
方法建立訂單,但order
有兩個欄位我們要自己加入,就是是哪個使用者以及總共多少錢,也就是
new_order_params =
order_params
|> Map.put("user_id", Integer.to_string(conn.assigns.current_user.id))
|> Map.put("total", Integer.to_string(get_total_price(conn)))
要注意在網路傳送都是要送 string,所以我們轉成 string
再來把這個訂單資訊插入到資料庫裡,插入成功就接著做兩件事:建立訂單物品快照和清空購物車
為什麼要建立訂單物品快照? 因為建立訂單之後購物車會清空,之後就不知道你的訂單有什麼物品,因此要在 order
裡面存入物品資訊,以後可以直接從訂單取得物品資訊
首先將購物車裡的所有物品做成 map集合,形式為 %{product: x, quantity: y}
接著將每一個 map的元素用 build_assoc
跟 order 連結上關係,最後再更新這個快照 changeset
#web/controllers/order_controller.ex
def build_order_item(conn, order) do
products =
Repo.preload(current_cart(conn), :cart_items).cart_items
|> Repo.preload(:product)
|> Enum.map(& &1.product} end)
for item <- products do
order_item_changeset =
build_assoc(order, :items)
|> OrderItem.changeset(%{"product_name" => item.title,
"price" => item.price,
"quantity" => 1})
case Repo.insert(order_item_changeset) do
{:ok, _order_item} ->
conn
{:error, _changeset} ->
render(conn, "show.html")
end
end
end
訂單建立後清空購物車
#web/models/cart.ex
alias ShoppingSite.Repo
def clean_cart_items(cart) do
Repo.preload(cart, :cart_items).cart_items
|> Enum.map($ Repo.delete(&1))
end