11
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

話題のSupabaseでサクッと投稿の削除機能をつくってみた!

Last updated at Posted at 2023-02-03

はじめに

こんにちは!かほです♪🐥
現在、本業では技術広報業務やエンジニア業務などに従事しています。
今回の記事では、Next.js×Supabaseを用いたアプリ開発における投稿の削除機能の実装について説明します。

前提

今回は、投稿の削除機能の実装を行います。
以下の記事の内容はすでに実装済みですので、まだ未実装の方は参考にしてみてください♪🐥

Next.js×Supabase×Vercelの連携方法について知りたい方

認証機能の実装について知りたい方

CRUD処理(投稿機能、一覧機能)の実装について知りたい方

この記事の読者対象

  • Next.js×SupabaseでCRUD処理(投稿の削除機能)を含むアプリを作ってみたい方
  • SupabaseRLS設定について知りたい方
  • Supabaseを今後使ってみたい方
  • Next.jsを使って高速でアプリを作りたい方

開発環境

package.json
"dependencies": {
    "@supabase/supabase-js": "^2.2.1",
    "eslint": "8.28.0",
    "eslint-config-next": "13.0.6",
    "next": "13.0.6",
    "react": "18.2.0",
    "react-dom": "18.2.0",
  },
  "devDependencies": {
    "@types/node": "^18.11.13",
    "@types/react": "18.0.26"
  }

認証済みアカウントのuser_idを投稿に設定しよう!

投稿の削除機能を実装するにあたり、投稿のユーザーIDを取得する必要があります。
その際に必要なコードの全体像を下記に記載します。

top.tsx
import { User } from "@supabase/supabase-js";

export default function Top() {
  const [user, setUser] = useState<User | null>(null);
  useEffect(() => {
    (async () => {
      await indexPost();
      const { data } = await supabase.auth.getUser();
      setUser(data.user);
    })();
  }, []);

  const addPost = async (e) => {
    if (user === null) return;
    
    e.preventDefault();
    try {
      const { error } = await supabase.from("posts").insert([
        {
          user_id: user.id,
          title: newTitle,
          content: newContent,
        },
      ]);
      if (error) throw error;
      await indexPost();
      setNewTitle("");
      setNewContent("");
    } catch (error) {
      alert("データの新規登録ができません");
    }
  };
}

コードを上から順に説明します。
getUser()を使用し、認証済みユーザーのデータを取得します。
getUser()を使用する方法は、下記のSupabase公式ドキュメントにも記載されていますので、ご興味のある方はご参照ください🙌

取得したユーザーのデータを状態管理するため、setUser(data.user)を記載します。

top.tsx
const [user, setUser] = useState<User | null>(null);
  useEffect(() => {
    (async () => {
      await indexPost();
      const { data } = await supabase.auth.getUser();
      setUser(data.user);
    })();
  }, []);

次に投稿したものにuser_idを付与します。

上記の記事で、投稿機能を実装していますが、insert()を用いて投稿データを挿入する際に
user_idを引数に入れます。user.idのuserは上記で取得し状態管理している認証済みのユーザー情報です。

top.tsx
      const { error } = await supabase.from("posts").insert([
        {
          user_id: user.id,
          title: newTitle,
          content: newContent,
        }
      ]);

実装後、投稿してみると下記の画像のように、postのuser_idに値が入ります!
投稿後はuser_idが取得できているか確認しましょう♪🐥
スクリーンショット 2023-02-03 22.14.41.png

RLSを設定しよう

Policyを作成しよう

次にPolicyを作成します。

  1. RLS有効化を確認した画面の右端にあるNew Policyというボタンを押します。
  2. ボタンを押すと下記の画面のように選択肢が2つ出てきます。
    テンプレートを使用してPolicyを作成したい方はGet started quicklyを選択し、完全にゼロからPolicyを作成したい方はFor full customizationを選択します。
    .
  3. 今回はテンプレートから作成したいので、Get started quicklyを選択しました。下記のような画面ができます。上から取得挿入更新削除の機能に対するSQLテンプレートがあります。
    .

削除機能に対する認可を設定しよう

次に削除機能に対する認可の設定を行います。

  1. 削除機能に対する認可を設定したいので、4つのSQLテンプレートの中からEnable read access to everyone(上から4つ目)を選択し、Use this templateボタンを押します。すると下記の画面が出てきます。
    .
  2. Policy nameを設定します。今回は認証済みのアカウントでかつ、投稿者本人のみが投稿できるという名前を設定します。
  3. Allowed operationを設定します。全てのデータを選択して表示させたいのでDELETEを選択します。
  4. Target rolesを設定します。今回は認証済みのアカウントを対象とした認可のため、選択肢からauthenticatedを選択します。
  5. USING expressionを設定します。今回は、投稿者本人のみが投稿を削除できる状態にしたいので、認証済みのアカウント(auth.uid())と投稿のユーザー(post.user_id)が一致しているという意味でauth.uid() = posts.user_idと書きます。
  6. 右下のReviewのボタンを押します。設定したSQL情報が下記の画面のように出てくるため、情報に間違えがなければSave policyを押してPolicyを保存します。

Policyの作成を確認しよう

削除機能に対するPolicyの設定が終わりました。
Policyの設定が完了している場合は、下記の画像のように行として表示されるためご確認ください。また、Policyを編集・削除する場合は右端の縦3点のボタンを押すと可能です。
スクリーンショット 2023-02-03 21.49.15.png

削除機能を実装しよう

次に削除機能についての説明を行います。
下記がtop.tsxの削除機能における全体像です。

top.tsx
const handleDelete = async (postID: number) => {
    try {
      const res = await supabase.from("posts").delete().eq("id", postID);
      const { data: posts } = await supabase.from("posts").select("*");
      setPosts(posts);
    } catch (error) {
      alert(error.message);
    }
  };

return (
    <>
      <div className={styles.container}>
        <Head>
          <title>トップページ</title>
          <link rel="icon" href="/favicon.ico" />
        </Head>
        <main className={styles.main}>
          <div>
            <h1>トップページ</h1>
            <div>
              <table>
                <thead>
                  <tr>
                    <th>投稿日</th>
                    <th>タイトル</th>
                    <th>内容</th>
                  </tr>
                </thead>
                <tbody>
                  {posts.map((post) => (
                    <tr key={post.id}>
                      <td>{post.created_at.substr(0, 10)}</td>
                      <td>{post.title}</td>
                      <td>{post.content}</td>
                      <td>
                        <button
                          onClick={() => handleDelete(post.id)}
                          className="border-gray-300 border-2 rounded p-1 w-12"
                        >
                          削除
                        </button>
                      </td>
                    </tr>
                  ))}
                </tbody>
              </table>
            </div>
          </div>
        </main>
        <footer className={styles.footer}></footer>
      </div>
    </>
  );

削除機能の実装方法について、コードを上から順に説明します。

次にsupabase.tsを呼び出し、実装を行います。
今回はdelete()を使用し、postsテーブルのデータを削除します。
fromの引数にテーブル名を記載し、eqの引数にテーブルのidと削除したいデータidの変数を記載します。

delete()を使用する方法は、下記のsupabase公式ドキュメントにも記載されていますので、ご興味のある方はご参照ください🙌

データを削除した後に、削除していないデータを表示したいため、
select()を用いてsupabaseのデータを取得し、setPosts(posts)を用いてデータを表示します。
try-catch構文を用いることにより、例外処理を行い、エラーが出た場合の対処を行います。

top.tsx
const handleDelete = async (postID: number) => {
    try {
      const res = await supabase.from("posts").delete().eq("id", postID);
      const { data: posts } = await supabase.from("posts").select("*");
      setPosts(posts);
    } catch (error) {
      alert(error.message);
    }
  };

削除機能に関わるマークアップは下記です。
handleDeleteメソッドを呼び出し、引数に削除したデータのidを入れます。

top.tsx
<button
  onClick={() => handleDelete(post.id)}
  className="border-gray-300 border-2 rounded p-1 w-12"
>削除</button>
 

削除ができたか確認してみよう!

では、最後にデモ動画で投稿の削除ができたかを確認します。
すでにアカウントが認証済みの段階から、投稿の登録~削除を行いました!

「投稿を投稿者本人が削除できる」ことを確認できました!成功です🎉😊
.

最後に

これで実装はおしまいです!

今回は、Next.js×Supabaseを用いたアプリ開発における投稿の削除機能の実装について説明しました。今後は主にフロントエンド周辺、コミュニティ運営、Tech PR(技術広報)の記事を中心に書いていく予定ですので、気になる方はぜひフォローをよろしくお願いします♪ではでは〜🐥

Twitterアカウント:https://twitter.com/kaho_eng

参考資料

11
4
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
11
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?