我們來為每個發文做出專屬的連結與頁面吧,因為我們在做 index 頁面的時候已經有用 resources
把整套都放進 Router 裡面的,如果要檢查目前有哪些路徑,可以使用指令:
mix phx.routes
來列出目前所有的 Routes
note_path GET /notes BlogWeb.NoteController :index
note_path GET /notes/:id/edit BlogWeb.NoteController :edit
note_path GET /notes/new BlogWeb.NoteController :new
note_path GET /notes/:id BlogWeb.NoteController :show
note_path POST /notes BlogWeb.NoteController :create
note_path PATCH /notes/:id BlogWeb.NoteController :update
PUT /notes/:id BlogWeb.NoteController :update
note_path DELETE /notes/:id BlogWeb.NoteController :delete
post_path GET /posts BlogWeb.PostController :index
post_path GET /posts/:id/edit BlogWeb.PostController :edit
post_path GET /posts/new BlogWeb.PostController :new
post_path GET /posts/:id BlogWeb.PostController :show
post_path POST /posts BlogWeb.PostController :create
post_path PATCH /posts/:id BlogWeb.PostController :update
PUT /posts/:id BlogWeb.PostController :update
post_path DELETE /posts/:id BlogWeb.PostController :delete
page_path GET / BlogWeb.PageController :index
後略
我們可以看到上面是給 notes 用的
下面是 posts 的
我們這次要用的是這個
post_path GET /posts/:id BlogWeb.PostController :show
這邊的 :id
會變成 params 傳到 controller 裡面,
我們來看看 id 傳到 controller 會長怎樣,先幫 PostController 加上 show 方法
defmodule BlogWeb.PostController do
use BlogWeb, :controller
alias Blog.Posts
def index(conn, _params) do
posts = Posts.list_posts()
render(conn, :index, %{posts: posts})
end
# 加上這個 show 方法
def show(conn, params) do
IO.inspect(params, label: "從網址來的 params 長這樣:")
text(conn, "先顯示這個") # 暫時用這個回傳文字,讓那一頁可以顯示
end
end
開發的時候可以用 IO.inspect 方法把給他的東西印在裝置上,我們可以在執行伺服器的終端機上面看到結果
label 選項可以讓我們加上標籤,我們要找的時候比較好找。
在這邊我們用來觀察從網址傳入的 params 長什麼樣子。
現在前往 /posts/1
位置,然後回到終端機看一下 params 的值
我們得到
從網址來的 params 長這樣:: %{"id" => "1"}
這代表我們可以利用 pattern matching 來接住 id
把 show 方法改成
def show(conn, %{"id" => id}) do
post = Posts.get_post(id) # 使用 Posts context 裡的 get_post 傳入 id 來找到該 post
render(conn, :show, %{post: post}) # 一樣把 post 傳入 assigns
end
剩下就跟 index 一樣,我們新增一個 lib/blog_web/templates/post/show.html.heex
檔案
並在裡面使用 @post
來顯示我們要的檢視單文章頁面,
例如這樣子
<article>
<h1><%= @post.title %></h1>
<p><%= @post.body %></p>
</article>
如果出現
key :title not found in: nil.
錯誤的話,那代表我們傳給@post
的值是nil
,
我們之後可以試著在 id 找不到文章的時候給提示,但現在沒關係,如果現在不知道哪些有哪些 id 有文章的話,
可以在 index 的文章列表頁面 在 for 迴圈裡面找一個地方加上 <%= post.id %> 讓他顯示該篇的 id
我們來加一個可以回到文章列表的連結吧
<article>
<h1><%= @post.title %></h1>
<p><%= @post.body %></p>
<%= link("回到選單", to: Routes.post_path(@conn, :index)) %>
</article>
這邊有兩個新的方法link
用法見文件
讓我們可以新增一個連結,用 to 選項給目標地址
Routes.post_path(@conn, :index)
Routes 其實是 BlogWeb.Router.Helpers
他是在這個檔案產生的 lib/blog_web.ex
alias BlogWeb.Router.Helpers, as: Routes
這種 Routes 方法是依照我們在 Router 裡寫的內容來產生連結地址,
可以依照 mix phx.routes
給的選項來填寫
這次用的是Routes.post_path(@conn, :index)
他會變成 /posts
待會我們會用Routes.post_path(@conn, :show, post)
他會變成 /posts/5
在即將到來的 Phoenix 1.7(寫稿當下為1.6) 將改用特殊的 sigil_p 有檢查功能又可以直接寫網址的新作法
可以從 Routes.post_path(@conn, :index) 改成寫 ~p"/posts/" 就好
當然 所有的連結都可以寫死 "/posts" 但是就失去 Phoenix 幫我們檢查網址的機會了
有了可以回到列表的連結後
我們也可以在列表的各個文章加入閱讀文章的按鈕來連進去各個發文
編輯 lib/blog_web/templates/post/index.html.heex
<h1>顯示 post 的 index 頁面</h1>
<%= for post <- @posts do %>
<article>
<h2><%= post.title %></h2>
<p><%= post.body %></p>
<%= link("閱讀更多", to: Routes.post_path(@conn, :show, post)) %>
</article>
<% end %>
這樣就完成一個可以閱讀的網站了,有文章列表,又可以點入各個文章