7 - 上傳商品圖片

做上傳圖片功能! 參考這篇這篇 首先在 product裡面加入 photo欄位,型態是 string command:
mix ecto.gen.migration add_photo_to_product


#web/priv/repo/migration/XXXX_add_photo_to_product.ex
  def change do
    alter table(:products) do
      add :photo, :string, default: ""
    end
  end

別忘了 product model也要手動加上 field

#web/models/product.ex
  schema "products" do
    field :title, :string
    field :description, :string
    field :quantity, :integer
    field :price, :integer

    field :photo, :string, default: ""

    timestamps()
  end

記得 mix ecto.migrate


arc 這個套件來上傳圖片 安裝 arc_ecto, arc

#mix.exs
...
defp deps do
  [
    ...
    {:arc_ecto, "~> 0.4.4"},
    {:arc, "~> 0.5.3"}
  ]
end
...

mix deps.get 安裝這兩個套件



然後建立一個 「 Uploader」,用來當上傳的工具
command: mix arc.g photo_uploader
會多出 web/uploader/photo_uploader.ex 這個檔案
新增 shopping_site/uploads這個資料夾,用來儲存圖片


檔案裡要做許多設定

#web/uploads/photo_uploader.ex
defmodule ShoppingSite.PhotoUploader do
  use Arc.Definition
 +use Arc.Ecto.Definition

  @versions [:original, :thumb] 

  # Define a thumbnail transformation:
  def transform(:thumb, _) do
    {:convert, "-strip -thumbnail 100x100^ -gravity center -extent 100x100 -format png", :png}
  end

  def __storage, do: Arc.Storage.Local

  def filename(version,  {file, scope}), do: "#{version}-#{file.file_name}"
end


versions 加入 :thumb讓 arc知道我們也要存縮圖,
縮圖這部分是 imageMagik幫忙做的
transform 裡面可以設定縮圖大小 (100x100)
__storge 則是指定存到 local地方,不寫這個會預設存在 S3
可以加入各種想要的版本,例如想要中 size,
那可以加 :medium到 @versions裡,
然後下面的 transfrom多一個

def transform(:medium, _), do: ...



product model也要改一下

#web/models/product.ex
defmodule ShoppingSite.Product do
  use ShoppingSite.Web, :model
 +use Arc.Ecto.Schema

  schema "products" do
    field :title, :string
    field :description, :string
    field :quantity, :integer
    field :price, :integer

    field :photo, ShoppingSite.PhotoUploader.Type

    timestamps()
  end

  @required_fields ~w(title description quantity price)
  @optional_fields ~w()

  @required_photo_fields ~w()
  @optional_photo_fields ~w(photo)

  @doc """
  Builds a changeset based on the `struct` and `params`.
  """
  def changeset(model, params \\ %{}) do
    model
    |> cast(params, @required_fields, @optional_fields)
   +|> cast_attachments(params, [:photo])
    |> validate_required([:title, :description, :quantity, :price])
    |> validate_length(:description, max: 200)
  end
end


加入 use Arc.Ecto.Schema
:photo 的型態改成 ShoppingSite.PhotoUploader.Type
changeset多增加一個檢查cast_attachments(params, [:photo]) 這樣 arc 就會都幫我們做好

資料庫要更新: mix ecto.migrate

新增產品時可以選圖片

#web/templates/admin/product/new.html.eex
<%= form_for @changeset, @action , [multipart: true], fn f -> %>
...
  <div class="form-group">
    <%= label f, :photo, class: "control-label" %>
    <%= file_input f, :photo, class: "form-control" %>
    <%= error_tag f, :photo %>
  </div>

  <div class="form-group">
    <%= submit "Submit", class: "btn btn-primary" %>
  </div>
<% end %>



在產品首頁顯示圖片~

#web/templates/admin/product/index.html.eex
<h1>Products</h1>

<ul>
  <%= for product <- @products do %>
    <div class="col-xs-6 col-md-3">
      <%= if product.photo.file_name != "" 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: admin_product_path(@conn, :show, product.id) %>  $<%= product.price %>
    </div>
  <% end %>
</ul>


不過這樣還圖片還是沒顯示
因為 phoenix天生不會去看 uploads 這個資料夾,
我們要告訴他要去找這個資料夾

加入這段 code, 不要刪掉已存在的 plug Plug.Static

#shopping_site/lib/shopping_site/endpoint.ex
plug Plug.Static,
    at: "admin/uploads", from: Path.expand('./uploads'), gzip: false

這樣應該可以看到圖片了!!!

也要記得把 /uploads 加到 .gitignore

results matching ""

    No results matching ""