2022年4月28日

使用 Remix、Prisma & MongoDB 構建全棧應用:參照完整性 & 圖片上傳

12 分鐘閱讀

歡迎閱讀本系列的第四篇文章,您將學習如何使用 MongoDB、Prisma 和 Remix 從零開始構建一個全棧應用程式!在本部分中,您將構建應用程式的個人資料設定部分,包括影像上傳元件,並配置您的模式以在資料中提供參照完整性。

Build A Fullstack App with Remix, Prisma & MongoDB: Referential Integrity & Image Uploads

目錄

介紹

在本系列的上一部分中,您構建了此應用程式的主要區域,包括 Kudos 動態、使用者列表、近期 Kudos 列表和 Kudos 傳送表單。

在本部分中,您將透過構建一種方式讓使用者更新其個人資料資訊和上傳個人資料圖片來結束此應用程式的開發。您還將對您的模式進行一些更改,這將為您的資料庫提供參照完整性。

注意:此專案的起點可在 GitHub 倉庫的 part-3 分支中找到。如果您想檢視本部分的最終結果,請前往 part-4 分支。

開發環境

為了理解所提供的示例,您需要...

注意:這些可選擴充套件為 Tailwind 和 Prisma 提供了非常好的智慧感知和語法高亮。

構建個人資料設定模態框

您應用程式的個人資料設定頁面將顯示在一個模態框中,透過點選頁面右上角的個人資料設定按鈕即可訪問。

app/components/search-bar.tsx

  • 為匯出的元件新增一個名為 profile 的新 prop,型別為 Prisma 生成的 Profile
  • 匯入 UserCircle 元件。
  • form 內容的末尾渲染 UserCircle 元件,並向其傳遞新的 profile prop 資料。這將作為您的個人資料設定按鈕。

如果您的開發伺服器已經執行,這將導致您的主頁丟擲錯誤,因為 SearchBar 元件現在期望有個人資料資料。

app/routes/home.tsx 檔案中,使用本系列第二部分app/utils/auth.server.ts 中編寫的 getUser 函式。在 loader 函式中,使用此函式載入已登入使用者的資料。然後將該資料提供給 SearchBar 元件。

您的 SearchBar 現在將可以訪問其所需的 profile 資料。如果您之前因為缺少此資料而收到錯誤,重新整理瀏覽器頁面應該會成功顯示頁面右上角的個人資料按鈕。

建立模態框

目標是在點選個人資料設定按鈕時開啟一個個人資料設定模態框。與本系列上一部分中構建的 kudos 模態框類似,您需要設定一個巢狀路由來渲染新的模態框。

app/routes/home 中新增一個名為 profile.tsx 的新檔案,其內容如下以開始

上面的程式碼片段...

  • ... 將模態框渲染到一個新的 ProfileSettings 元件中。
  • ... 在 loader 函式中檢索並返回已登入使用者的資料。
  • ... 使用 useLoaderData 鉤子訪問從 loader 函式返回的 user 資料。

要開啟這個新的模態框,在 app/components/search-bar.tsx 中,為 UserCircle 元件新增一個 onClick 處理程式,該處理程式使用 Remix 的 useNavigate 鉤子將使用者導航到 /home/profile 子路由。

如果您現在點選個人資料設定按鈕,您應該會看到螢幕上顯示新的模態框。

構建表單

您將構建的表單將有三個欄位,允許使用者修改其個人資料詳細資訊:名字、姓氏和部門。

透過新增名字和姓氏輸入開始構建表單

以下是上面新增內容的概述

  1. 添加了所需更改的匯入。
  2. 在狀態中建立了一個 formData 物件,用於儲存表單的值。這些值預設為已登入使用者的現有個人資料資料。
  3. 建立了一個函式,該函式將 HTML change 事件和欄位名作為引數。當元件中輸入欄位的值發生變化時,這些引數用於更新 formData 狀態。
  4. 渲染表單的基本佈局以及兩個輸入欄位。

此時,尚未進行錯誤處理,表單也未執行任何操作。在新增這些部分之前,您需要新增部門下拉選單。

app/utils/constants.ts 中,新增一個新的 departments 常量來儲存 Prisma 模式中定義的可能選項。將以下匯出新增到該檔案

departments 匯入到您的 app/routes/home/profile.tsx 檔案中,以及 SelectBox 元件,並使用它們向您的表單新增一個新的輸入欄位

此時,您的表單應該會渲染正確的輸入及其選項。它會將它們的值預設為與已登入使用者個人資料關聯的當前值。

允許使用者提交表單

您將構建的下一部分是 action 函式,它將使此表單功能化。

在您的 app/routes/home/profile.tsx 中,新增一個 action 函式,該函式從 request 物件中檢索表單資料,並驗證 firstNamelastNamedepartment 欄位

上面的 action 函式執行以下操作

  1. request 物件中提取您需要處理的表單資料點。
  2. 確保您關注的每一部分資料都是 string 資料型別。
  3. 使用先前編寫的 validateName 函式驗證資料。
  4. 重定向到 /home 路由,關閉設定模態框。

上面的程式碼片段在各種驗證失敗時也會丟擲相關錯誤。為了將經過驗證的資料投入使用,請編寫一個允許您更新使用者的函式。

app/utils/user.server.ts 中,匯出以下函式

此函式允許您傳入任何 profile 資料並更新 id 與所提供的 userId 匹配的使用者。

返回到 app/routes/home/profile.tsx 檔案,匯入該新函式並使用它在 action 函式中更新已登入使用者

現在,當用戶點選儲存按鈕時,其更新的個人資料資料將被儲存,並且模態框將關閉。

新增影像上傳元件

設定 AWS 賬戶

您的使用者現在可以更新其個人資料中的一些關鍵資訊,但是,新增允許使用者設定個人資料圖片的功能會更好,這樣其他使用者可以更容易識別他們。

為此,您將設定一個 AWS S3 檔案儲存桶來儲存上傳的影像。如果您還沒有 AWS 賬戶,可以在此處註冊。

注意:Amazon 提供免費套餐,讓您免費訪問 S3。

建立 IAM 使用者

擁有賬戶後,您需要在 AWS 中設定一個 身份和訪問管理 (IAM) 使用者,以便生成訪問金鑰 ID秘密金鑰,這兩者都是與 S3 互動所需的。

注意:如果您已經有一個 IAM 使用者及其金鑰,請隨意跳過。

前往 AWS 控制檯主頁。在頁面右上角,點選標有您使用者名稱的下拉選單,然後選擇 安全憑證

進入該部分後,點選左側選單“訪問管理”下的使用者選項。

在此頁面上,點選頁面右上角的新增使用者按鈕。

這將引導您完成一個簡短的嚮導,允許您配置使用者。按照以下步驟操作

第一部分要求填寫

  1. 使用者名稱:提供任何使用者名稱。
  2. 選擇 AWS 訪問型別:選擇訪問金鑰 - 程式設計訪問選項,這會啟用訪問金鑰 ID秘密金鑰的生成。

在嚮導的第二步,做出以下選擇

  1. 選擇“直接附加現有策略”選項。
  2. 搜尋詞語“S3”。
  3. 勾選標記為AmazonS3FullAccess的選項旁邊的複選框。
  4. 點選表單底部的“下一步”。

如果您想為您的使用者新增標籤以幫助更輕鬆地管理和組織您賬戶中的使用者,請在此處(嚮導的第三步)新增。在此頁面完成後,點選下一步

如果此頁面的摘要看起來不錯,請點選頁面底部的建立使用者按鈕。

點選該按鈕後,您將進入一個顯示您的訪問金鑰 ID秘密金鑰的頁面。複製它們並將其儲存在您可以輕鬆訪問的地方,因為您很快就會用到它們。

設定 S3 儲存桶

現在您已經有了使用者和訪問金鑰,請前往 AWS S3 控制檯,您將在此處設定檔案儲存桶。

在此頁面右上角,點選建立儲存桶按鈕。

系統會要求您提供儲存桶的名稱和區域。填寫這些詳細資訊,並將您選擇的值與之前儲存的訪問金鑰 ID秘密金鑰一起儲存。稍後您也需要這些資訊。

填寫完成後,點選表單最底部的建立儲存桶

儲存桶建立完成後,您將進入儲存桶儀表盤頁面的物件選項卡。導航到許可權選項卡。

在此選項卡中,點選阻止公共訪問部分下的編輯按鈕。在此表單中,取消選中阻止所有公共訪問框,然後點選儲存更改。這將您的儲存桶設定為公共,這將允許您的應用程式訪問影像。

在該部分下方,您將看到一個儲存桶策略部分。貼上以下策略,並務必將<bucket-name>替換為您的儲存桶名稱。此策略將允許您的影像被公開讀取

您現在已經設定好了 AWS 使用者和 S3 儲存桶。接下來,您需要將金鑰和儲存桶配置儲存到您的 .env 檔案中,以便稍後使用。

更新您的 Prisma 模式

您現在將在資料庫中建立一個欄位,用於儲存上傳影像的連結。這些連結應與 Profile 嵌入文件一起儲存,因此請在 Profile 型別塊中新增一個新欄位。

要使用這些更改更新 Prisma Client,請執行 npx prisma generate

構建影像上傳元件

app/components 中建立一個名為 image-uploader.tsx 的新檔案,其內容如下

上面的程式碼片段是完整的影像上傳元件。以下是其工作原理概述

  1. 定義了一個 preventDefault 函式來處理元件中檔案輸入的更改。
  2. 定義了一個 handleDrop 函式來處理元件中檔案輸入的 drop 事件。
  3. 定義了一個 handleChange 函式來處理元件中檔案輸入的任何 change 事件。
  4. 渲染了一個帶有各種事件處理程式的 div,允許它對檔案拖放、拖動事件和點選做出反應。這些用於觸發影像上傳和樣式更改,這些更改僅在元素接收到拖動事件時出現。

只要此元件中 input 的值發生變化,就會呼叫 props 中的 onChange 函式,並傳遞檔案資料。該資料將被上傳到 S3。

接下來建立將處理影像上傳的服務。

構建影像上傳服務

要構建您的影像上傳服務,您需要兩個新的 npm 包

  • aws-sdk:暴露一個 JavaScript API,允許您與 AWS 服務互動。
  • cuid:一個用於生成唯一 ID 的工具。您將使用它來生成隨機檔名。

您的影像上傳服務將位於一個新的實用程式檔案中。在 app/utils 中建立一個名為 s3.server.ts 的檔案。

為了處理上傳,您將利用 Remix 的 unstable_parseMultipartFormData 函式,該函式處理 request 物件的 multipart/form-data 值。

注意multipart/form-data 是在表單中釋出整個檔案時使用的表單資料型別。

unstable_parseMultipartFormData 將接收兩個引數

  1. 從表單提交中檢索到的 request 物件。
  2. 一個 uploadHandler 函式,用於流式傳輸檔案資料並處理上傳。

注意unstable_parseMultipartFormData 函式的使用方式與我們之前使用的 Remix 的 request.formData 函式類似。

將以下函式和匯入新增到您建立的新檔案

此程式碼設定您的 S3 API,以便您可以與您的儲存桶互動。它還添加了 uploadHandler 函式。此函式

  1. 使用您在設定 AWS 使用者和 S3 儲存桶時儲存的環境變數來設定 S3 SDK。
  2. 只要資料鍵的名稱是 'profile-pic',就從 request 流式傳輸檔案資料。
  3. 將檔案上傳到 S3。
  4. 返回 S3 返回的 Location 資料,其中包含新檔案在 S3 中的 URL 位置。

現在 uploadHandler 已完成,新增另一個函式,該函式實際上接收 request 物件,並將其與 uploadHandler 一起傳遞給 unstable_parseMultipartFormData 函式。

此函式接收一個 request 物件,該物件稍後將從 action 函式傳送過來。

檔案資料透過 uploadHandler 函式傳遞,該函式處理到 S3 的上傳,並且 formData 將新檔案的位置返回到一個表單資料物件中。然後,從該物件中提取 'profile-pic' URL,並由該函式返回。

將元件和服務投入使用

現在,實現個人資料圖片上傳所需的兩個部分已經完成,將它們組合起來。

透過在 app/routes 中建立一個名為 avatar.ts 的新檔案,幷包含以下 action 函式,新增一個處理上傳表單資料的資源路由

上述函式執行以下步驟來處理上傳表單

  1. 獲取請求使用者的 id
  2. 上傳請求資料中傳遞的檔案。
  3. 使用新的 profilePicture URL 更新請求使用者的個人資料資料。
  4. 使用 imageUrl 變數響應 POST 請求。

現在您可以使用 ImageUploader 元件來處理檔案上傳,並將檔案資料傳送到新的 /avatar 路由。

app/routes/home/profile.tsx 中,匯入 ImageUploader 元件並將其新增到您的表單中,位於輸入欄位的左側。

還在 formData 變數中新增一個新函式來處理 ImageUploader 元件發出的 onChange 事件,以及一個新欄位來儲存個人資料圖片資料。

現在,如果您轉到該表單並嘗試上傳檔案,資料應該會正確儲存在 S3、資料庫和表單狀態中。

顯示個人資料圖片

太棒了!影像上傳執行流暢,現在您只需要在使用者頭像出現的地方顯示這些影像即可。

開啟 app/components/user-circle.tsx 中的 UserCircle 元件,並進行以下更改,以便在可用時將圓圈的背景影像設定為個人資料圖片

如果您現在為幾個使用者設定了個人資料圖片,您應該會看到它們顯示在整個網站上!

新增刪除賬戶功能

您的個人資料設定模態框所需的最後一個功能是刪除賬戶的能力。

刪除資料,尤其是在無模式資料庫中,可能會產生“孤立文件”,即曾經與父文件關聯的文件,但其父文件在某個時候被刪除了。

在本節中,您將針對這種情況設定保護措施。

新增刪除按鈕

您將以類似於處理登入和登錄檔單的方式處理此表單。此表單將傳送一個 _action 鍵,讓 action 函式知道它接收到的是哪種請求。

app/routes/home/profile.tsx 中,對 ProfileSettings 函式返回的 form 進行以下更改

現在,根據點選的按鈕,您可以在 action 函式中處理不同的 _action

更新 action 函式以使用 switch 語句來執行不同的操作

現在,如果使用者儲存表單,將命中 'save' 情況並執行現有功能。'delete' 情況目前不執行任何操作。

app/utils/user.server.ts 中新增一個新函式,該函式接收一個 id 並刪除與之關聯的使用者

您現在可以填充個人資料頁面上 "delete" 情況的其餘部分。

您的使用者現在可以刪除他們的賬戶了!

更新資料模型以新增參照完整性

此刪除使用者功能唯一的問題是,當用戶被刪除時,他們所有編寫的 Kudos 都會變成孤立的

您可以使用參照操作在作者被刪除時觸發任何 kudos 的刪除。

執行 npx prisma db push 以傳播這些更改並生成 Prisma Client。

現在,如果您刪除一個賬戶,該賬戶建立的任何 Kudos 都將隨之刪除!

新增表單驗證

快要結束了!最後一部分是在個人資料設定表單中連線錯誤訊息處理。

您的 action 函式已經返回了所有正確的錯誤訊息;它們只需要被處理。

app/routes/home/profile.tsx 中進行以下更改以處理這些錯誤

上面程式碼片段中進行了以下更改

  1. 使用 useActionData 鉤子檢索錯誤訊息。這些訊息儲存在狀態變數中,並在使用者提交了錯誤的表單後返回到模態框時用於填充表單。
  2. 添加了錯誤輸出以顯示任何表單級別的錯誤。
  3. 錯誤資料已傳遞給 FormField 元件,以便它們可以在需要時顯示其欄位級別的錯誤。

進行上述更改後,您將看到任何表單和驗證錯誤都顯示在表單上。

總結 & 下一步

透過本文所做的更改,您成功完成了您的 Kudos 應用程式!網站的所有部分都已功能完備,可以交付給您的使用者了。

在本節中,您瞭解了

  • Remix 中的巢狀路由
  • AWS S3
  • Prisma 和 MongoDB 的參照操作和完整性

本系列的下一部分,您將透過將您構建的應用程式部署到 Vercel 來結束這一切!

不要錯過下一篇文章!

訂閱 Prisma 新聞通訊

© . This site is unofficial and not affiliated with Prisma Data, Inc.