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_item裡面有 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)

正確的話可以看到商品名稱、照片位置等等

results matching ""

    No results matching ""