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