2

Working With Remix, Prisma, and SQLite To Save Data Using Forms

 2 years ago
source link: https://dev.to/aaronksaunders/working-with-remix-prisma-and-sqlite-to-save-data-using-forms-1b3j
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

Overview

A simple application tutorial with Prisma Setup, creating objects, saving objects, and saving objects with relationships. We also show a Remix page with multiple Forms on one page that can support multiple actions from the form submission

Remix - Remix is a full-stack web framework that lets you focus on the user interface and work back through web fundamentals to deliver a fast, slick, and resilient user experience. People are gonna love using your stuff.

Prisma - Next-generation Node.js and TypeScript ORM

Prisma helps app developers build faster and make fewer errors with an open-source database toolkit for PostgreSQL, MySQL, SQL Server, SQLite, and MongoDB

Video

Create Remix Project

npx create-remix@latest

Enter fullscreen mode

Exit fullscreen mode

Prisma Stuff

Install Prisma specific packages

npm install prisma@latest typescript ts-node @types/node --save-dev
npm install @prisma/client@latest
npx prisma init --datasource-provider sqlite

Enter fullscreen mode

Exit fullscreen mode

Create the database models for the CMS

// prisma/schema.prisma

// This is your Prisma schema file,
// learn more about it in the docs: <https://pris.ly/d/prisma-schema>

generator client {
  provider = "prisma-client-js"
}

datasource db {
  provider = "sqlite"
  url      = env("DATABASE_URL")
}

// NEW STUFF !!
// ------------
model User {
  // We set an `id` variable
  // - @id (because it's an ID)
  // - @default(autoincrement()) (default value is auto-incremented)
  id Int @id @default(autoincrement())

  // - @unique (because we want the user to be unique
  // based on the email - two users can't have the same)
  email String @unique

  username String

  // With a `BookMark[]` type (one-to-many relationship)
  // Because each user can have between 0 and an infinite number of bookmarks
  bookmarks BookMark[]
}

model BookMark {
  id Int @id @default(autoincrement())

  createdAt DateTime @default(now())

  // note about the bookmark
  text String

  url String @default("")

  // It will link the `id` of the `User` model
  userId Int

  // We set a `user` variable
  // With a `User` type (many-to-one relationship)
  // Because each bookmark is associated with a user
  // 
  // We link the `User` to a `Bookmark` based on:
  // - the `userId` in the `Bookmark` model
  // - the `id` in the `User` model
  user User @relation(fields: [userId], references: [id])
}

Enter fullscreen mode

Exit fullscreen mode

run command to migrate the changes into the database and create the prisma client

npx prisma migrate dev --name initialize_db

Enter fullscreen mode

Exit fullscreen mode

view content in the database using Prisma Studio client

npx prisma studio

Enter fullscreen mode

Exit fullscreen mode

Remix Stuff

// index.tsx

import { PrismaClient, User } from "@prisma/client";
import { Form, Link, useLoaderData, useTransition } from "remix";

export async function loader() {
  const prisma = new PrismaClient();
  const allUsers = await prisma.user.findMany();
  console.log(allUsers);
  await prisma.$disconnect();
  return allUsers;
}

export async function action({ request }) {
  const form = await request.formData();

  const prisma = new PrismaClient();
  const allUsers = await prisma.user.create({
    data: { email: form.get("email"), username: form.get("username") },
  });
  console.log(allUsers);
  await prisma.$disconnect();
  return true;
}

export default function Index() {
  const users = useLoaderData();
  const { state } = useTransition();
  const busy = state === "submitting";

  return (
    <div
      style={{
        fontFamily: "system-ui, sans-serif",
        lineHeight: "1.4",
        width: 600,
        margin: "auto",
      }}
    >
      <h2>Users and Bookmarks: Sample App Tutorial</h2>
      <h4>Remix with Prisma and SQLite</h4>
      <Form method="post">
        <div>
          <input name="email" placeholder="Email" size={30} />
        </div>
        <div>
          <input name="username" placeholder="User Name" size={30} />
        </div>
        <button type="submit" disabled={busy}>
          {busy ? "Creating..." : "Create New User"}
        </button>
      </Form>

      {users.map((user: User) => (
        <div style={{ border: "1px solid grey", padding: 6, margin: 8 }}>
          <div>{user.username}</div>
          <div>{user.email}</div>
          <div>
            <Link to={`/bookmarks/${user.id}`}>
              <button>View Details</button>
            </Link>
          </div>

        </div>
      ))}
    </div>
  );
}

Enter fullscreen mode

Exit fullscreen mode

// bookmarks/$id.tsx
import { BookMark, PrismaClient, User } from "@prisma/client";
import { Form, Link, useLoaderData, useParams, useTransition } from "remix";

/**
 *
 * @param param0
 * @returns
 */
export async function loader({ params }) {
  const prisma = new PrismaClient();

  // get the user
  const user = await prisma.user.findUnique({
    where: {
      id: parseInt(params?.id),
    },
  });
  console.log("user with id = " + params?.id + " ", user);

  // get the bookmarks
  const usersBookmarks = await prisma.bookMark.findMany({
    where: {
      userId: parseInt(params?.id),
    },
    // include : {
    //     user : true
    // }
  });
  console.log("usersBookmarks with id = " + params?.id + " ", usersBookmarks);
  await prisma.$disconnect();
  return { bookmarks: usersBookmarks, user };
}

/**
 *
 * @param param0
 * @returns
 */
export async function action({ request }) {
  const form = await request.formData();

  const prisma = new PrismaClient();

  // HANDLE CREATION
  if (request.method === "POST") {
    const bookmark = await prisma.bookMark.create({
      data: {
        text: form.get("text"),
        url: form.get("url"),
        user: {
          connect: {
            id: parseInt(form.get("id")),
          },
        },
      },
    });
    console.log("created bookmark ", bookmark);
  }

  // HANDLE DELETE
  if (request.method === "DELETE") {
    const delResponse = await prisma.bookMark.delete({
      where: {
        id: parseInt(form.get("id")),
      },
    });
    console.log(delResponse);
  }
  await prisma.$disconnect();
  return true;
}

/**
 *
 * @returns
 */
export default function BookMarksById() {
  const { bookmarks, user } = useLoaderData();
  const { state } = useTransition();
  const busy = state === "submitting";

  const { id } = useParams();

  return (
    <div
      style={{
        fontFamily: "system-ui, sans-serif",
        lineHeight: "1.4",
        width: 600,
        margin: "auto",
      }}
    >
      <div>
        <Link to={`/`}>
          <button>HOME</button>
        </Link>
      </div>
      <h2>Manage Book Marks for {user?.username}</h2>
      <Form method="post">
        <div>
          <input name="text" placeholder="description" size={30} />
          <input name="url" placeholder="url" size={30} />
          <input type={"hidden"} value={id} name="id" />
        </div>
        <button type="submit" disabled={busy}>
          {busy ? "Creating..." : "Create New Bookmark"}
        </button>
      </Form>

      {bookmarks?.map((bookmark: BookMark) => (
        <div
          style={{ border: "1px solid grey", padding: 6, margin: 8 }}
          key={bookmark.id}
        >
          <div>{bookmark.createdAt}</div>
          <div>{bookmark.text}</div>
          <div>{bookmark.url}</div>

          <Form method="delete" >
            <input type={"hidden"} value={bookmark.id} name="id" />
            <button type="submit">DELETE</button>
          </Form>
        </div>
      ))}
    </div>
  );
}

Enter fullscreen mode

Exit fullscreen mode

Links


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK