大部分的網頁框架都有額外的 helper 來幫助我們產生複雜的 <a>
(anchor tag),Phoenix 也不例外。
目前我們使用的 <a>
都是用在預設的 GET 要求,所以我們不需要帶入額外的東西,也沒有其他安全疑慮,但是這一次我們要使用 <a>
來產生 DELETE 要求,所以最好是使用 Phoenix 提供的 <.link>
component 代替。
Link component 有許多的使用方法,在 Controller-View 的範圍裡,都是使用 href
attribute 來加上目標路徑 (其他跳轉選項會在後面的 LiveView 章節介紹)。
取代 <a>
tag 最常見的 GET 寫法:
<.link href={~p"/notes/new""}>到新筆記頁面</.link>
這次刪除需要的是 DELETE 要求,所以我們要加上 method
attribute:
<.link href={~p"/notes/#{note}"} method="delete">刪除</.link>
另外 Phoenix 也提供了 data-confirm
attribute 來幫助我們加上確認視窗:
<.link href={~p"/notes/#{note}"} method="delete" data-confirm="確定要刪除?">
刪除
</.link>
把刪除按鈕加到 index.heex.html 中:
<ul class="flex flex-col gap-4">
<li
:for={note <- @notes}
class="flex justify-between bg-amber-50 p-4 rounded-lg font-bold border-2 border-amber-300"
>
<%= note.content %>
<div>
<a href={~p"/notes/#{note}/edit"} class="text-amber-800">編輯</a>
<.link
href={~p"/notes/#{note}"}
class="text-amber-800"
method="delete"
data-confirm="確定要刪除?"
>
刪除
</.link>
</div>
</li>
</ul>
<a>
都改成 <.link>
。刪除與 create 和 update 相當相似,甚至更簡單,因為沒有資料需要處理,找到目標,刪除即可。
def delete(conn, %{"id" => id}) do
note = Notes.get_note(id)
{:ok, _note} = Notes.delete_note(note)
conn
|> put_flash(:info, "感激筆記刪除成功")
|> redirect(to: ~p"/notes")
end
替刪除功能加上測試
describe "delete note" do
test "deletes chosen note", %{conn: conn} do
{:ok, note} = Notes.create_note(%{content: "待刪除的筆記內容"})
conn = delete(conn, ~p"/notes/#{note}")
assert redirected_to(conn) == ~p"/notes"
conn = get(conn, ~p"/notes")
html = html_response(conn, 200)
assert html =~ "感激筆記刪除成功"
refute html =~ "待刪除的筆記內容"
end
end