🕰️ Chapters
- Refactoring Our Avatars Route as a Generic Storage Route
- Inspecting Wildcard Route Parameters
- Getting Requested Image File Path
- Reviewing the File Upload Documentation
- Normalizing and Testing the File Path Validity
- Downloading the Requested Image
- Accessing Our Images
- Testing Our Storage Download Route
Using A Wildcard Route Param to Download Storage Images
In this lesson, we'll learn how we can utilize a wildcard route parameter to dynamically download images that've been uploaded and stored within our application storage.
- Author
- Tom Gobich
- Published
- Jun 20, 24
- Duration
- 7m 57s
Developer, dog lover, and burrito eater. Currently teaching AdonisJS, a fully featured NodeJS framework, and running Adocasts where I post new lessons weekly. Professionally, I work with JavaScript, .Net C#, and SQL Server.
Adocasts
Burlington, KY
slideOverOpen && setActive());">
Transcript
Using A Wildcard Route Param to Download Storage Images
-
Introduction
-
Fundamentals
-
2.0Routes and How To Create ThemLesson 2.05m 24s
-
2.1Rendering a View for a RouteLesson 2.16m 30s
-
2.2Linking Between RoutesLesson 2.27m 52s
-
2.3Loading A Movie Using Route ParametersLesson 2.39m 18s
-
2.4Validating Route ParametersLesson 2.46m 7s
-
2.5Vite and Our AssetsLesson 2.56m 39s
-
2.6Setting Up Tailwind CSSLesson 2.67m 5s
-
2.7Reading and Supporting Markdown ContentLesson 2.74m 32s
-
2.8Listing Movies from their Markdown FilesLesson 2.88m 51s
-
2.9Extracting Reusable Code with ServicesLesson 2.97m 4s
-
2.10Cleaning Up Routes with ControllersLesson 2.104m 52s
-
2.11Defining A Structure for our Movie using ModelsLesson 2.119m 38s
-
2.12Singleton Services and the Idea of CachingLesson 2.126m 11s
-
2.13Environment Variables and their ValidationLesson 2.134m 16s
-
2.14Improved Caching with RedisLesson 2.1410m 44s
-
2.15Deleting Items and Flushing our Redis CacheLesson 2.156m 46s
-
2.16Quick Start Apps with Custom Starter KitsLesson 2.166m 28s
-
2.17Easy Imports with NodeJS Subpath ImportsLesson 2.178m 40s
-
-
Building Views with EdgeJS
-
3.0EdgeJS Templating BasicsLesson 3.08m 49s
-
3.1HTML Attribute and Class UtilitiesLesson 3.16m 9s
-
3.2Making A Reusable Movie Card ComponentLesson 3.210m 24s
-
3.3Component Tags, State, and PropsLesson 3.34m 53s
-
3.4Use Slots To Make A Button ComponentLesson 3.46m 56s
-
3.5Extracting A Layout ComponentLesson 3.55m 13s
-
3.6State vs Share Data FlowLesson 3.62m 59s
-
3.7Share vs Global Data FlowLesson 3.76m 8s
-
3.8Form Basics and CSRF ProtectionLesson 3.86m 13s
-
3.9HTTP Method Spoofing HTML FormsLesson 3.93m 3s
-
3.10Easy SVG Icons with Edge IconifyLesson 3.107m 57s
-
-
Database and Lucid ORM Basics
-
4.0Configuring Lucid and our Database ConnectionLesson 4.04m 3s
-
4.1Understanding our Database SchemaLesson 4.19m 35s
-
4.2Introducing and Defining Database MigrationsLesson 4.218m 35s
-
4.3The Flow of MigrationsLesson 4.38m 28s
-
4.4Introducing Lucid ModelsLesson 4.45m 43s
-
4.5Defining Our ModelsLesson 4.56m 49s
-
4.6The Basics of CRUDLesson 4.611m 56s
-
4.7Defining Required Data with SeedersLesson 4.711m 11s
-
4.8Stubbing Fake Data with Model FactoriesLesson 4.813m 48s
-
4.9Querying Our Movies with the Query BuilderLesson 4.915m 30s
-
4.10Unmapped and Computed Model PropertiesLesson 4.103m 24s
-
4.11Altering Tables with MigrationsLesson 4.117m 6s
-
4.12Adding A Profile Model, Migration, Factory, and ControllerLesson 4.122m 57s
-
4.13SQL Parameters and Injection ProtectionLesson 4.139m 19s
-
4.14Reusable Query Statements with Model Query ScopesLesson 4.148m 11s
-
4.15Tapping into Model Factory StatesLesson 4.159m 15s
-
4.16Querying Recently Released and Coming Soon MoviesLesson 4.164m 59s
-
4.17Generating A Unique Movie Slug With Model HooksLesson 4.177m 59s
-
-
Lucid ORM Relationships
-
5.0Defining One to One Relationships Within Lucid ModelsLesson 5.05m 49s
-
5.1Model Factory RelationshipsLesson 5.12m 54s
-
5.2Querying Relationships and Eager Vs Lazy LoadingLesson 5.25m 17s
-
5.3Cascading and Deleting Model RelationshipsLesson 5.35m 16s
-
5.4Defining One to Many Relationships with Lucid ModelsLesson 5.46m 56s
-
5.5Seeding Movies with One to Many Model Factory RelationshipsLesson 5.55m 24s
-
5.6Listing A Director's Movies with Relationship Existence QueriesLesson 5.68m 41s
-
5.7Listing and Counting a Writer's MoviesLesson 5.78m 41s
-
5.8Using Eager and Lazy Loading to Load A Movie's Writer and DirectorLesson 5.85m 18s
-
5.9Defining Many-To-Many Relationships and Pivot ColumnsLesson 5.99m 48s
-
5.10Many-To-Many Model Factory RelationshipsLesson 5.104m 50s
-
5.11A Deep Dive Into Relationship CRUD with ModelsLesson 5.1118m 5s
-
5.12How To Create Factory Relationships from a Pool of DataLesson 5.1213m 55s
-
5.13How To Query, Sort, and Filter by Pivot Table DataLesson 5.139m 47s
-
-
Working With Forms
-
6.0Accepting Form DataLesson 6.012m 15s
-
6.1Validating Form Data with VineJSLesson 6.19m 29s
-
6.2Displaying Validation Errors and Validating from our RequestLesson 6.27m 16s
-
6.3Reusing Old Form Values After A Validation ErrorLesson 6.32m 3s
-
6.4Creating An EdgeJS Form Input ComponentLesson 6.45m 28s
-
6.5Creating A Login Form and ValidatorLesson 6.55m 1s
-
6.6How To Create A Custom VineJS Validation RuleLesson 6.69m 7s
-
-
Authentication & Middleware
-
7.0The Flow of MiddlewareLesson 7.07m 49s
-
7.1Authenticating A Newly Registered UserLesson 7.14m 14s
-
7.2Checking For and Populating an Authenticated UserLesson 7.22m 10s
-
7.3Logging Out An Authenticated UserLesson 7.32m 24s
-
7.4Logging In An Existing UserLesson 7.46m 54s
-
7.5Remembering A User's Authenticated SessionLesson 7.56m 55s
-
7.6Protecting Routes with Auth, Guest, and Admin MiddlewareLesson 7.65m 36s
-
-
Filtering and Paginating Queries
-
8.0Creating A Movie List PageLesson 8.03m 43s
-
8.1Filtering A Query By Pattern LikenessLesson 8.17m 9s
-
8.2Filtering Our List by Movie StatusLesson 8.25m 47s
-
8.3How To Apply A Dynamic Sort Filter To Your QueryLesson 8.37m 12s
-
8.4Joining SQL Tables To Order By A Related ColumnLesson 8.44m 49s
-
8.5Validating Query String Filter ValuesLesson 8.57m 24s
-
8.6How To Paginate Filtered Query ResultsLesson 8.69m 15s
-
8.7Pagination First, Last, Next, and Previous ButtonsLesson 8.74m 3s
-
-
User Watchlist
-
9.0An Alternative Approach to Many-To-Many RelationshipsLesson 9.04m 56s
-
9.1Toggling A Movie in an Authenticated User's WatchlistLesson 9.19m 56s
-
9.2Listing and Filtering User Watchlist ItemsLesson 9.27m 31s
-
9.3Allowing Users To Toggle A Movie As WatchedLesson 9.34m 44s
-
9.4Filtering By User's Watched StatusLesson 9.46m 7s
-
9.5Defining A Composite Unique ConstraintLesson 9.54m 47s
-
9.6Persist Filters Easily with Lucid's Query String MethodLesson 9.63m 58s
-
-
User Profiles
-
10.0How to Create and Fix Missing User Profiles in Your ApplicationLesson 10.07m 37s
-
10.1Using Dependency Injection to Update A User's ProfileLesson 10.19m 46s
-
10.2Saving All Or Nothing with Database TransactionsLesson 10.25m 15s
-
10.3Uploading and Displaying User AvatarsLesson 10.315m 29s
-
10.4Displaying A User's ProfileLesson 10.46m 1s
-
10.5Filtering, Preloading, and Sorting By RelationshipLesson 10.57m 6s
-
-
Admin Panel
-
11.0Creating An Admin LayoutLesson 11.07m 14s
-
11.1Counting Stats for our Admin DashboardLesson 11.15m 43s
-
11.2Paginated Admin Movie TableLesson 11.213m 2s
-
11.3Allowing Admins to Create MoviesLesson 11.316m 39s
-
11.4Allowing Admins to Update Movies and Clear ValuesLesson 11.413m 27s
-
11.5How To Use One Form to Create or Edit MoviesLesson 11.55m 32s
-
11.6Uploading Movie Cover Images in our Create or Edit FormLesson 11.610m 29s
-
11.7Using A Wildcard Route Param to Download Storage ImagesLesson 11.77m 57s
-
11.8Posting Objects, Arrays, and an Array of Objects in HTML FormsLesson 11.826m 26s
-
11.9Managed Transactions and Syncing Movie Cast MembersLesson 11.915m 55s
-
11.10Allowing Admins to Delete Movies and their RelationshipsLesson 11.107m 42s
-
11.11Thank You for Watching!Lesson 11.110m 31s
-
Join The Discussion! (8 Comments)
Please sign in or sign up for free to join in on the dicussion.
gribbl
Hello,
When I try to access uploaded file, for example
/storage/avatars/filename.png
, without a route or controller, the file displays just fine. TheStorageController
isn’t called.Finally, I get this error when I try to delete a movie’s poster :
'ENOENT: no such file or directory, unlink'
, I think the error comes from this line:'await unlink(app.makePath('storage', movie.posterUrl))'
. The generated path seems to be incorrect.But I don’t understand why it seems to work for you.
Please sign in or sign up for free to reply
tomgobich
Hi Gribbl!
If you're able to directly access the file via the URL without going through a route definition, that leads me to believe the file is actually within your
public
directory. Files within this directory are made accessible by the AdonisJS static file server.That would also explain the "no such file" error on the attempted deletion, as
app.makePath('storage')
is going to be looking in the~/storage
directory directly off your application root, not within thepublic
directory.Can't say for certain though - just making an educated guess based on the info provided.
Hope this helps!
Please sign in or sign up for free to reply
gribbl
I don’t have a
public
directory, onlystorage
at the root of the project.The line
router.get('/storage/*', [StorageController, 'show']).as('storage.show')
is commented, and I can still access my downloaded files in that directory. 🤔And for file deletion, it seems like the
makePath
method generates the following path:.../storage/storage/posters/filename.png
sinceposterUrl
also contains/posters
. So, I usedapp.makePath('.', movie.posterUrl)
instead, and it works. 😁Please sign in or sign up for free to reply
tomgobich
Sorry for the delayed response! Are you able to share the repo url? Neither should be the case, and I can't immediately think of anything that would cause either of those.
Please sign in or sign up for free to reply
gribbl
No problemo.
That's strange. I have the exact same code as you. But just to confirm, if I understood correctly (and correct me if I'm wrong), when we save a movie's poster, we use the following lines in the movie service:
So, the file is saved at
storage/posters
, and in the database,poster_url
will have the value/storage/posters/filename.png
.And when we want to delete the poster, we do this:
So, the generated path will contain
storage
twice. As a result, since no file is located instorage/storage/posters
, the deletion will not work. Right? Or did I misunderstand?Please sign in or sign up for free to reply
tomgobich
I'm so sorry, my head was in the wrong spot! You're absolutely right, the
/storage
gets added to the saved value in the database so theunlink
should be:Terribly sorry for the confusion there! I'll make a note to correct this lesson.
Please sign in or sign up for free to reply
gribbl
No problem at all. Thank you for your response.😊
Please sign in or sign up for free to reply
tomgobich
Anytime! 😊
Please sign in or sign up for free to reply