iT邦幫忙

2022 iThome 鐵人賽

DAY 14
0
Modern Web

速成 Phoenix, 2022年最受喜愛框架系列 第 14

{14, Phoenix, "Controller show"}

  • 分享至 

  • xImage
  •  

做單個文章的顯示頁面 show

我們來為每個發文做出專屬的連結與頁面吧,因為我們在做 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 %>

這樣就完成一個可以閱讀的網站了,有文章列表,又可以點入各個文章


上一篇
{13, Phoenix, "Controller index"}
下一篇
{15, Phoenix, "用 form 顯示 changeset"}
系列文
速成 Phoenix, 2022年最受喜愛框架30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言