9 - 商品加入購物車
之前有做商品的後台,商家可以上傳商品等等 但使用者要將商品加入購物車的話就不是在後台做 因此我們要區分這兩個功能
區分 admin/product, /product
#web/router.ex
scope "/", ShoppingSite do
pipe_through :browser # Use the default browser stack
get "/", PageController, :index
resources "/users", UserController, only: [:index, :show, :new, :create]
resources "/sessions", SessionController, only: [:new, :create, :delete]
resources "/products", ProductController, only: [:index, :show]
end
#web/controllers/product_controller.ex
defmodule ShoppingSite.ProductController do
use ShoppingSite.Web, :controller
def index(conn, _params) do
products = Repo.all(Product)
render conn, "index.html", products: products
end
def show(conn, %{"id" => id}) do
product = Repo.get(ShoppingSite.Product, id)
render conn, "show.html", product: product
end
end
別忘了 product_view.ex
#web/views/product_view.ex
defmodule ShoppingSite.ProductView do
use ShoppingSite.Web, :view
def present?(photo) do
photo.file_name != ""
end
end
#web/templates/product/index.html.eex
<h1>Products</h1>
<br>
<br>
<ul>
<%= for product <- @products do %>
<div class="col-xs-6 col-md-3">
<%= if present?(product.photo) do %>
<img class="thumbnail"
src="<%= ShoppingSite.PhotoUploader.url({product.photo, product}, :thumb) %>"/>
<% else %>
<img class="thumbnail" src="http://placehold.it/200x200&text=No Pic"/>
<% end %>
<%= link product.title , to: product_path(@conn, :show, product.id) %> $
<%= product.price %>
</div>
<% end %>
</ul>
#web/templates/product/show.html.eex
<div class="row">
<div class="col-md-6 col-centered">
<%= if present?(@product.photo) do %>
<img class="thumbnail" src="<%= ShoppingSite.PhotoUploader.url({@product.photo, @product}, :medium) %>"/>
<% else %>
<img class="thumbnail" src="http://placehold.it/400x400&text=No Pic"/>
<% end %>
</div>
<div class="col-md-6">
<h2><%= @product.title %></h2>
<div style="height:100px">
<p>
<%= @product.description %>
</p>
</div>
<div> Quantity: <%= @product.quantity %></div>
<div class="product-price"> $ <%= @product.price %></div>
<div class="pull-right">
<%= link "Add to Cart" ,
to: product_add_to_cart_path(@conn, :add_to_cart, @product.id),
class: "btn btn-primary btn-lg btn-danger" %>
</div>
</div>
</div>
把 navbar 的 product連結換成連到 "/product"
#web/templates/layout/navbar.html.eex
...
<ul class="nav navbar-nav">
<li class="active">
<%= link "Product" , to: product_path(@conn, :index)%>
</li>
...
新增 add_to_cart
方法
#web/router.ex
scope "/", ShoppingSite do
pipe_through :browser # Use the default browser stack
get "/", PageController, :index
resources "/users", UserController, only: [:new, :create]
resources "/sessions", SessionController, only: [:new, :create, :delete]
resources "/products", ProductController, only: [:show, :index] do
get "/add_to_cart", ProductController, :add_to_cart, as: :add_to_cart
end
end
在 product_controller
新增 add_to_cart
方法
#web/controllers/product_controller.ex
def add_to_cart(conn, %{"product_id" => product_id}) do
product = Repo.get(Product, product_id)
cart_item_changeset =
build_assoc(current_cart(conn), :cart_items)
|> CartItem.changeset(%{"cart_id" => current_cart(conn).id, "product_id" => product.id})
case Repo.insert(cart_item_changeset) do
{:ok, _cart_item} ->
conn
|> put_flash(:info, "add to cart successfully.")
|> redirect(to: product_path(conn, :show, product_id))
{:error, _changeset} ->
render(conn, "show.html")
end
end
build_assoc
那行意思是我們在 cart
裡面建立 cart_item
的 struct,這樣會自動的在新建立的 cart_ite
m裡面有 cart
的 id
通常是用在 has_many
, has_one
這種地方
參考: build_assoc
這裏還要注意一下我們要把 cart_id
, product_id
寫進 changeset裡面,這樣 cart_item
才知道要 reference的 cart、product是什麼
#web/models/cart_item.ex
def changeset(struct, params \\ %{}) do
struct
|> cast(params, [:cart_id, :product_id])
|> validate_required([:cart_id, :product_id])
end
進去網站點選 navbar的 Product應該會看不到圖片 因為跟之前一樣我們要去設定圖片顯示的網址
#lib/shopping_site/endpoint.ex
...
plug Plug.Static,
at: "/uploads", from: Path.expand('./uploads'), gzip: false
...
然後要設定 medium
的商品圖片
#web/uploaders/photo_uploader.ex
@versions [:original, :thumb, :medium]
...
def transform(:medium, _) do
{:convert, "-strip -thumbnail 300x300^ -gravity center -extent 300x300 -format png", :png}
end
...
重新刷新後就可以看到圖片囉,點進去商品看不到圖片是因為之前上傳圖片時沒有用 medium
壓縮,重新上傳就有圖片了,接著試試加商品到購物車裡
加完後進去 console 先找出購物車再把 cart_item
載出來檢查看看
$> cart = ShoppingSite.Repo.get(ShoppingSite.Cart, id)
$> cart_items = ShoppingSite.Repo.preload(cart, :cart_items)
$> ShoppingSite.Repo.preload(cart_items, :product)
正確的話可以看到商品名稱、照片位置等等