Working With Remix, Prisma, and SQLite To Save Data Using Forms
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
Recommend
About Joyk
Aggregate valuable and interesting links.
Joyk means Joy of geeK