建立訂單
我們需要 「訂單」、「訂單資訊」、「訂單物品」這幾個資料結構
訂單:
$> mix phoenix.gen.model order orders user_id:references:users total:integer
訂單資訊:
$> mix phoenix.gen.model order_info order_infos order_id:references:orders billing_name:string billing_address:string shipping_name:string shipping_address:string
訂單物品
$> mix phoenix.gen.model order_item order_items order_id:references:orders product_name:string price:integer quantity:integer
設定關係:
#web/models/order.ex
schema "orders" do
field :total, :integer
belongs_to :user, ShoppingSite.User
has_many :items, ShoppingSite.OrderItem, on_delete: :delete_all
has_one :info, ShoppingSite.OrderInfo, on_delete: :delete_all
timestamps()
end
@required_fields ~w(user_id total)
@optional_fields ~w()
def changeset(struct, params \\ %{}) do
struct
|> cast(params, @required_fields, @optional_fields)
|> cast_assoc(:info, required: true)
|> validate_required([:user_id, :total])
end
增加結帳按鈕
#web/router.ex
resources "/carts", CartController, only: [:index] do
get "/check_out", CartController, :check_out, as: :check_out
end
#web/templates/cart/index.html.eex
...
<div class="checkout clearfix">
<span class="pull-right">
<%= link "Check out",
to: cart_check_out_path(@conn, :check_out, current_cart(@conn).id),
class: "btn btn-lg btn-danger" %>
</span>
</div>
</div>
</div> //end
為了要在 cart/index 使用 current_cart
,在 cart_view
import current_cart
#web/views/cart_view.ex
import ShoppingSite.CartController, only: [current_cart: 1]
check_out
function
#web/controllers/cart_conotroller.ex
alias ShoppingSite.OrderInfo
alias ShoppingSite.Order
def check_out(conn, _params) do
order_info_changeset = OrderInfo.changeset(%OrderInfo{})
order_changeset = Order.changeset(%Order{info: order_info_changeset})
render conn, "check_out.html", order_changeset: order_changeset
end
這樣表示我們在建立訂單時會先建立 OrderInfo
然後把它放到 Order
的 changeset裡
填寫訂單資訊的頁面(check_out.html)
#web/templates/cart/check_out.html.eex
<div class="row">
<div class="col-md-12">
<table class="table table-bordered">
<thead>
<tr>
<th width="80%">product information</th>
<th>price</th>
</tr>
</thead>
<tbody>
<%= for product <- get_cart_items(@conn) do %>
<tr>
<td>
<%= link to: product_path(@conn, :show, product.id) do%>
<%= product.title %>
<% end %>
</td>
<td>
<%= product.price %>
</td>
</tr>
<% end %>
</tbody>
</table>
<div class="total clearfix">
<span class="pull-right">
total <%= cart_total_price(@conn) %>
</span>
</div>
<h2>Order information</h2>
<div class="order-form">
<%= render "order_form.html", changeset: @order_changeset,
action: order_path(@conn, :create) %>
</div>
</div>
</div>
cart_view
新增在 templates用到的方法
#web/views/cart_view.ex
def get_cart_items(conn) do
products =
Repo.preload(current_cart(conn), :products).products
end
還有order_form.html
,用來填入訂單人資訊
<%= form_for @changeset, @action, fn f -> %>
<%= if @changeset.action do %>
<div class="alert alert-danger">
<p>Oops! something went wrong!</p>
</div>
<%= end %>
<%= inputs_for f, :info, fn fp -> %>
<div class="form-group">
<%= label fp, :billing_name, class: "control-label" %>
<%= text_input fp, :billing_name, class: "form-control" %>
<%= error_tag fp, :billing_name %>
</div>
<div class="form-group">
<%= label fp, :billing_address, class: "control-label" %>
<%= text_input fp, :billing_address, class: "form-control" %>
<%= error_tag fp, :billing_address %>
</div>
<div class="form-group">
<%= label fp, :shipping_name, class: "control-label" %>
<%= text_input fp, :shipping_name, class: "form-control" %>
<%= error_tag fp, :shipping_name %>
</div>
<div class="form-group">
<%= label fp, :shipping_address, class: "control-label" %>
<%= text_input fp, :shipping_address, class: "form-control" %>
<%= error_tag fp, :shipping_address %>
</div>
<% end %>
<div class="form-group">
<%= submit "Check out", class: "btn btn-lg btn-danger pull-right" %>
</div>
<% end %>
我們也需要 Order
的 create
才能建立訂單