之前Phoenix的部分示範到如何快速產生CRUD頁面,這對新手來說自然是遠遠不足的,所以既然鐵人賽還有時間,接下來會示範如何用Phoenix建立一個購物網站。我參考的教材雖然是phoenix 1.2.1 但我這邊會使用最新版phoenix 1.3.0。因為版本的差異,修正的幅度還挺大的。
首先我們重新建立一個名為 shop 的1.3.0專案:
$ mix phx.new shop
如果按照教材上mix phoenix.new project_name
的做法,會產生1.2.5的專案版本。這兩個版本資料夾與檔案結構略有差異,使用上要特別留意。
按照提示,接下來我們設定dev.exs
裡的資料庫參數,但這次我們不把帳號密碼直接寫進去,先將裡面關於資料庫設定的預設資料全部刪除,貼上這行import_config "dev.secret.exs"
,接著在config資料夾內新增一個檔案:
# /config/dev.secret.exs
use Mix.Config
# Configure your database
config :shop, Shop.Repo,
adapter: Ecto.Adapters.Postgres,
username: "username",
password: "password",
database: "shop_dev",
hostname: "localhost",
pool_size: 10
在username與password的地方替換為本地端Postgres資料庫的帳號密碼。如果你檢查.gitignore
,你會發現裡面已經預設將*.secret.exs
排除在版本追蹤裡面,所以這個檔案是不會被上傳到github或任何git server。這樣做的目的是避免帳號密碼外流,雖然本地端的資料庫帳密沒有這麼嚴重,但養成好習慣是新手的好開始。
當上面設定就緒後,依序執行下面的指令:
$ mix ecto.create
$ mix ecto.migrate
$ mix phx.server
接著打開瀏覽器輸入http://localhost:4000
,應該可以看到Phoenix的歡迎畫面,這樣第一步就完成了。
除了Django外,大部份的框架都需要自己建立後台,來管理我們所需的資料。我們先由路由開始,空白處貼上:
# /lib/shop_web/router.ex
scope "/admin", ShopWeb.Admin, as: :admin do
pipe_through :browser
resources "/products", ProductController
end
scope "/admin"
:路由的前綴,在這個block內都會套用ShopWeb.Admin.ProductController
這樣的效果as: :admin
:path的前綴,在path前增加admin完成後,檢查一下路徑是否如我們預期產生,檢查的指令為:
$ mix phx.routes
Compiling 6 files (.ex)
page_path GET / ShopWeb.PageController :index
admin_product_path GET /admin/products ShopWeb.Admin.ProductController :index
admin_product_path GET /admin/products/:id/edit ShopWeb.Admin.ProductController :edit
admin_product_path GET /admin/products/new ShopWeb.Admin.ProductController :new
admin_product_path GET /admin/products/:id ShopWeb.Admin.ProductController :show
admin_product_path POST /admin/products ShopWeb.Admin.ProductController :create
admin_product_path PATCH /admin/products/:id ShopWeb.Admin.ProductController :update
PUT /admin/products/:id ShopWeb.Admin.ProductController :update
admin_product_path DELETE /admin/products/:id ShopWeb.Admin.ProductController :delete
理論上應該會得到跟我一模一樣的結果(寬度不夠會自行換行)。路由完成後,接著我們產生產品model。產品有標題、描述、數量、價格四個欄位。有點麻煩的是,我們應該要產生在剛剛的admin之下,因為我一時沒查到語法,所以先用手動移動檔案的笨方法:
$ mix phx.gen.html Goods Product products title description:text quantity:integer price:integer
* creating lib/shop_web/controllers/product_controller.ex
* creating lib/shop_web/templates/product/edit.html.eex
* creating lib/shop_web/templates/product/form.html.eex
* creating lib/shop_web/templates/product/index.html.eex
* creating lib/shop_web/templates/product/new.html.eex
* creating lib/shop_web/templates/product/show.html.eex
* creating lib/shop_web/views/product_view.ex
* creating test/shop_web/controllers/product_controller_test.exs
* creating lib/shop/goods/product.ex
* creating priv/repo/migrations/20171223112244_create_products.exs
* creating lib/shop/goods/goods.ex
* injecting lib/shop/goods/goods.ex
* creating test/shop/goods/goods_test.exs
* injecting test/shop/goods/goods_test.exs
我們把四個欄位改為必填,在欄位後面加上null: false
# priv/repo/migrations/20171223112244_create_products.exs
...
create table(:products) do
add :title, :string, null: false
add :description, :text, null: false
add :quantity, :integer, null: false
add :price, :integer, null: false
timestamps()
end
因為我們的並不是在根目錄下而是在/admin
下,所以有一些動作要做:
複製product_controller.ex
到lib/shop_web/controllers/admin
下,並且把第一行改為defmodule ShopWeb.Admin.ProductController do
。接著把controller內的product_path
(應該是三個)都改為admin_product_path
。
在lib/shop_web/views/admin
下新增一個product_view.ex
defmodule ShopWeb.Admin.ProductView do
use ShopWeb, :view
end
在template下新增一個admin資料夾,把整個product拖進去,並把裡面所有的product_path
都改為admin_product_path
。
接著執行migrate,如果上面的修正沒完成,migrate會錯。
$ mix ecto.migrate
如果你完成上面的步驟,這時候打開瀏覽器輸入 http://localhost:4000/admin/products ,你就可以看到我們用工具產生的簡易後台,但目前還沒有權限管理,就只是個基礎的CRUD,唯一的差別只有路徑不同罷了。理論上在gem.html
的時候應該就可以直接產生在scope: admin之下,但我沒有查到作法,只好先有比較蠢的手動修改模式。
我把程式碼放在 https://github.com/bater/shop ,有需要可以參考。