Skip to content

Modify the project structure

Now that we have updated the Prisma schema and pushed these changes to the database, we need to update the project structure to reflect these changes.

The first thing we need to do is update the permissions in the app/utils/user.ts file.

Permissions describe what actions a user can perform on a specific entity. In our case, we are concentrating on two entities: user and article.

  1. Open the app/utils/user.ts file.

  2. We will update the Entity type definition to accept 'article' as well as 'user' and 'note'.

    Around line 28, add the code below:

    app/utils/user.ts
    25 collapsed lines
    import { type SerializeFrom } from '@remix-run/node'
    import { useRouteLoaderData } from '@remix-run/react'
    import { type loader as rootLoader } from '#app/root.tsx'
    function isUser(user: any): user is SerializeFrom<typeof rootLoader>['user'] {
    return user && typeof user === 'object' && typeof user.id === 'string'
    }
    export function useOptionalUser() {
    const data = useRouteLoaderData<typeof rootLoader>('root')
    if (!data || !isUser(data.user)) {
    return undefined
    }
    return data.user
    }
    export function useUser() {
    const maybeUser = useOptionalUser()
    if (!maybeUser) {
    throw new Error(
    'No user found in root loader, but user is required by useUser. If user is optional, try useOptionalUser instead.',
    )
    }
    return maybeUser
    }
    type Action = 'create' | 'read' | 'update' | 'delete'
    type Entity = 'user' | 'note' | 'article'
    type Access = 'own' | 'any' | 'own,any' | 'any,own'
    export type PermissionString =
    | `${Action}:${Entity}`
    | `${Action}:${Entity}:${Access}`
    // ...Code omitted for brevity...
  3. Remember to save your changes before moving on to the next step.

Inside the utils folder, there is a file called misc.tsx.

  1. Open app/utils/misc.tsx.

  2. Create a new function called getArticleImgSrc by adding the code below:

    This simply generates a URL for an article image:

    app/utils/misc.tsx
    import { useFormAction, useNavigation } from '@remix-run/react'
    import { clsx, type ClassValue } from 'clsx'
    import { useEffect, useMemo, useRef, useState } from 'react'
    import { useSpinDelay } from 'spin-delay'
    import { extendTailwindMerge } from 'tailwind-merge'
    import { extendedTheme } from './extended-theme.ts'
    export function getUserImgSrc(imageId?: string | null) {
    return imageId ? `/resources/user-images/${imageId}` : '/img/user.png'
    }
    export function getNoteImgSrc(imageId: string) {
    return `/resources/note-images/${imageId}`
    }
    export function getArticleImgSrc(imageId: string) {
    return `/resources/article-images/${imageId}`
    }
  3. Save your changes.

This new function simply generates a URL to load an article image from the database. However, the file for this new URL doesn’t exist yet.

Let’s create it in the next step.

The route file we are going to create is a little different from the others we have created so far. We are going to create something called a resource route.

  1. Create a new file inside app/routes/resources+/ called article-images.$imageId.tsx:

    Create article-images file

  2. Add the code below to it:

    app/routes/resources+/article-images.$imageId.tsx
    import { invariantResponse } from '@epic-web/invariant'
    import { type LoaderFunctionArgs } from '@remix-run/node'
    import { prisma } from '~/utils/db.server.ts'
    export async function loader({ params }: LoaderFunctionArgs) {
    invariantResponse(params.imageId, 'Image ID is required', { status: 400 })
    const image = await prisma.articleImage.findUnique({
    where: { id: params.imageId },
    select: { contentType: true, blob: true },
    })
    invariantResponse(image, 'Not found', { status: 404 })
    return new Response(image.blob, {
    headers: {
    'Content-Type': image.contentType,
    'Content-Length': Buffer.byteLength(image.blob).toString(),
    'Content-Disposition': `inline; filename="${params.imageId}"`,
    'Cache-Control': 'public, max-age=31536000, immutable',
    },
    })
    }
    1. Save your changes.

    2. Take a moment to look through the code, and see if you can understand what it does.

      What do you notice is missing from this route file that is present in the others?

Using VS Code’s file explorer, navigate to the folder app/routes/users+/$username_+.

To manually update each of these files inside $username_+ would take a disproportionately long time, so instead you can download an updated version of this folder here:

$username_+.zip
  1. After clicking on the blue download button above, navigate to your browser’s download button and click to ‘Show in Folder’

    Show in folder

  2. Open the Downloads folder on your computer, right-click on the $username_+.zip file, and select ‘Extract All…’.

    Extract zip

  3. In the pop-up window that appears, click ‘Browse’. Navigate to your ‘Downloads’ folder again, click ‘Select Folder’, and finally click ‘Extract’ to unzip the folder.

    Watch the gif below to make sure you extract the folder correctly:

    Extract folder

  4. Once you have extracted the folder, you are ready to replace the existing app/routes/users+/$username_+ folder with the new one.

    Start by right-clicking the existing $username_+ folder in your project (located at app/routes/users+/$username_+) and selecting ‘Delete’.

    Delete existing folder

  5. Finally, drag the new $username_+ folder from your Downloads folder into the app/routes/users+ folder in your project.

    Watch the gif below carefully to make sure you drag the new folder into the correct location:

    Copy article files to project

If placed correctly, your new folder structure should look like this:

New folder structure

Finally, we need to update the seed.ts file so that we can populate the database with new test data that reflects the changes we have made.

  1. Delete the existing seed file at prisma/seed.ts.

    Delete seed file

  2. Download the new seed file by clicking the link below:

    seed.zip
  3. Click the download icon in your browser and select ‘Show in folder’.

    Show seed file in folder

  4. Open the zip file.

    Drag the downloaded seed.ts file into the prisma folder in your project.

    Take extra care to place the file in the correct location.

    Place new seed file

Now that we have updated the seed script, we can run it to populate the database with new dummy data.

To do this, run the following command in your terminal:

Terminal window
npm run setup

After a few moments, you should see something similar to the following output (the time taken may vary):

Running seed command `tsx prisma/seed.ts` ...
🌱 Seeding...
prisma:query - 36ms - DELETE from "User"
🧹 Cleaned up the database...: 62.516ms
🔑 Created permissions...: 11.604ms
👑 Created roles...: 26.458ms
📝 Created article categories...: 27.36ms
👤 Created 5 users...: 1.489s
🐨 Created admin user "kody": 673.453ms
🌱 Database has been seeded: 2.292s
The seed command has been executed.

After seeing this message, we are ready to check the new database in Prisma Studio.

Run the following command in your terminal:

Terminal window
npx prisma studio

You should see your database has been populated with new data:

Database with seed data

Feel free to click into the database and explore how the categories appear in the new table.

In this tutorial, we updated the project structure to reflect the changes we made to the Prisma schema.

  • We updated the permissions in the app/utils/permissions.ts file to reflect the new entity name.
  • We replaced the note files in the app/routes/users+/$username_+ folder with the updated article files.
  • Updated the seed data to include new article categories and dummy articles.

In the next tutorial, we will modify the seed data to include some article categories and dummy articles that will be used to populate the database.