Listing photo uploads, database seeding, and more! - clearbnb - Part 09

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
hey what's up welcome back in this episode we're going to work on adding photos to our listing so using active storage to upload some images and we'll attach those to our listings for this short short-term vacation rental platform that we're working on building out so yeah we're going to jump in we'll see how it goes and uh yeah so the very first start is we want to do like rails active storage colon install and this will install active storage and a couple other little libraries and so that copied a migration i've actually already got some active storage tables so we'll see if this works so railsdb migrate also like as part of the upgrade from six to seven i was trying to demonstrate some stuff and so things already existed but other things didn't so you should be able to just say like active storage colon install run your migrations and then you should be set up and ready to go so this thing right here i'm actually just going to remove this and i'm pretty sure that i've already got active storage set up and ready to rock so active storage here is a tool that you can use for storing files and it will handle the database so tracking like where the data is actually stored when you when you're uploading files to rails those those the data for the actual file itself doesn't typically store is not typically stored in the database instead it's usually stored on some file server like s3 gcp microsoft azure etc etc and so active storage is a tool that kind of coordinates taking the file uploading it storing it in one of those places based on some config and then letting you giving you sort of like nice ruby methods for interacting with those files that are technically on s3 or wherever when you're developing locally you can use the local storage and that will just kind of store the files onto your disk and that local storage in that case is different from like local storage you use in javascript but it'll store it on disk the reason why you don't want to use local storage in practice generally is that a lot of times when we're deploying rails apps we're deploying to heroku or render or these other there's other bunch of other tools where like the file systems are ephemeral and so anything that's not in like your git repo is going to get blown away and so generally it's just better practice to store on some service like amazon s3 or similar the way this works is we you kind of like set up some config we're just going to default to whatever whatever is already in storage.yaml we can like hold that up and take a look so config storage.yml so when we're in test mode or when we're in local we're just going to store all the data in like slash storage for from our rails route and then if we wanted to turn on aws gcp azure or some mirror service then we could just uncomment these so when we're ready to deploy we can do that but for now it should just store it locally the next thing is we want to go into development rb and make sure that we have that set up so development.rb and storage should be here local okay so that's set as local the next thing uh yeah so in production you can kind of like turn on whatever uh whatever one that you want to use and some of those are going to require like keys and authentication and whatever um and then a lot of the rest of this documentation is setting it up for deploy or for production public access blah blah blah okay so now when we're attaching files to records we use these methods inside of the activerecord models so it has one attached or has many attached and this allows you to say you just kind of give it the name of what the file is describing and then you create a form field and then everything else is sort of handled for you and you can call methods like user.avatar.url or something like that it'll give you back the url to the file um you can also yeah like there's there's a few different options that you can pass to these attachment things where you can tell it which service you can also give it a bunch of variations which is a nice feature of it's a nice feature of rails seven there was a bunch of stuff that was released as part of the variations that let you get like cropped yeah so here you go you got like different variants so you can say like resize to limit 100 by 100 or resize to whatever um so i yeah we'll come back and look at this variant stuff in a bit and i'm not sure i'll be able to install this image magic or vips thing but yes we will come back to that all right what else we got here i really like the example where you can select like several different files click open and then it shows you the progress when you start uploading and so these are actually uploading client-side using javascript to upload directly to the to the third-party service or to your local system or whatever and then there's a bunch of javascript that you can hook into in terms of events so these are going to be javascript events that are firing on client-side objects or client-side yeah dom elements when um when the upload process is happening for direct uploads and i do think this is kind of the slickest uh solution there's a tool called drop zone that i really like to use generally with images that kind of gives you like a nice uh javascript format um or javascript tool for allowing people to kind of like just drag images and drop them onto the page but for now let's just try to go through this process of adding this to our application so inside of app uh javascript packs yeah inside of packs here we want to oh we've already got active storage here and it's already started okay so we've already got that set up and then um direct upload true to your form field um for attachments if you're using a form builder if you're not using a form builder you give it this data dash direct upload dash url and you pass in the rails direct uploads url um okay so let's just mess around with that for a little bit and see what we can do so inside of right now let's see let's not get too far ahead of ourselves so inside of host listings host listings here we have our list of listings if we drill into one of them this is what we see right now just json blob edit details edit rooms i think what we want to do is also have photos edit photos and edit photos will be a place where we can upload new photos and rather than just having our listing has many attachments for each individual photo what i want to do is actually create a photo model that is related to a listing and the reason is that i want to be able to add captions and i want to be able to run each photo through certain processes to like analyze it for you know is this like uh yeah is this is this some sort of like explicit photo that shouldn't have been uploaded and things like that so let's generate a model rails g model um photo and it is going to have a photo and that's going to be the actual like image file thing the active storage image file thing we'll also have a caption sometimes on some rental platforms you can also associate models with specific rooms so you might say like oh this is a picture of the kitchen or this is a picture of the backyard or whatever um but for now i think we can just start with those two fields on our photo oh you know what we also need is um reference back to the listing so it's going to be like t dot references listing and i think that should be good um i guess we want it to be something like this uh actually no um okay so foreign key it's gonna be we're gonna have a foreign key from photo back to the listing id uh and then this string photo that's gonna be our attachment and i can't remember if when we do the attachment if we need a different kind of migration oh no because oh you know what we don't actually even need the photo column on this table when we use has one attachment the data ultimately lives in the active storage tables um and follows like this pattern where like the data is stored in a centralized table in kind of like a polymorphic association but yeah so we actually don't even need that um so this should be fine so we'll say rails db migrate okay that's going to give us a new photo table photos already exists what okay did i uh i may have blown it away in the middle of it right let's see db migrate none of these should have created photo tables all right whatever um okay so if we go to the photo model then in here we can say um has one attached photo okay now inside uh we need to create a controller for this so rails g controller host photos and uh let's just give it in we'll create an index to start with and i'm using the slash again so that we get a namespaced controller so it's namespaced under the host namespace or the host module so inside of our routes here we should have resources uh photos only uh only index and create and destroy i think that makes sense host photos controller all right so now we've got this namespace under the host module we have an index here we've also got this create method we will have like photo params and that's gonna be params.require photo dot permit um caption and i don't remember if we actually need to permit uh yeah okay we need to permit photo also this is a little confusing like this top level photo is the name of the model that we're using by convention and then this is going to be like the actual data for the file maybe we should have called like one photo and one picture or whatever but um whatever that's fine and then here we're going to say something like photo equals well at listing is current user.listings.find params oh you know what i'm wondering do we want to nest this under yeah i think we do okay um listing id yeah okay so this is gonna be like slash host slash listings slash one slash photos and that'll give us the index and that'll also be where we send a post request to create a new listing and this will be like at listing.photos.new photo params if at photo dot save so if the photo is saved then we want to redirect to um host listing photos path for the uh listing and then otherwise we want to say like flash um flash errors is at photo dot errors dot full messages and then i think we can actually redirect in either case so we'll just move that down here so if if it didn't save then we'll populate some errors we'll redirect back if it did save we're going to redirect back but it should have should have saved all right so then the in the index we'll we'll do these two things so listing is going to be find the listing and then photos is going to be listing.photos also we need to go to the listing model and add a relationship has many photos and then we need to go to here and say this belongs to a listing all right so then if we come back to our thing here and go to photos you have a pending migration railsdb migrate why are you crashing okay rails db uh drop db create db migrate uh all right i'm just gonna like drop the entire thing and recreate it because i think something might have like failed in the middle of something oh no uh active storage blobs does not exist ah migrations uh db migrate okay add service name to active storage blobs okay something got messed up like inside of git i was setting up active storage and then part like i think the database was just in a wacky state so i'm going to drop the entire thing i'm going to remigrate it huh uh railsdb drop you gonna drop drop the database rails db create rails db migrate all right cool now we want to say rails active storage install and this should like set up the migrations and now i should be able to say rails db migrate again and it should not get sad okay now when we restart our server and fire up this page here we should no longer have pending oh right okay so now we also want to go into our photos controller and add before filter i forget what it's called already authenticate user ah not before filter before action it used to be called before filter all right now when you're working locally and the database gets in a wacky state you have a couple options one you can fiddle around with the database and try to fix it and make it happy again or you can just drop the whole thing and start over the problem with dropping the whole thing and starting over is that you don't have any users anymore you don't have any test data anymore and if you were manually creating all the test data then it can be a pain to like recreate it all and so what i want to do now is i'm going to go into instead of manually creating the users and all the data i'm going to go into dbseeds.rb and i want to i want to set this up so that we can like create some users and create some listings so here i'm going to say let's actually go to our gem file oops and inside of the gem file i'm going to add the to development and test gem faker bundle install faker is an amazing gem it's super fun i'm a really big fan of faker it's basically just like a way to it's a tool for generating fake data so if we say reload here we let's see uh we'll restart faker okay so now we have the faker gem installed faker is really cool so what's also really neat is because we're using pry rails we can actually use cd and like change directory into classes so we can cd into faker and then ls and this shows us like all of the class methods i don't know why it's so nasty with all this like shift a shift b thing it should print it out much prettier than this but you can kind of get an idea of all the different things that it can generate so you can generate addresses or chuck norris things or emotions or um bill murray phil murray uh military stuff measuring marketing markdown lorem ipsum etc etc etc so oh there's even a cannabis one neat super interesting um so what we want is pretty boring i think it might be under internet l-m-n-o-p-q-r-s um we kind of just want like user data lmnop qrs wait is it um let's go to the faker gem docs because this is not spitting this out as i would expect or prefer and this is okay so faker internet.email so you might want to say something like uh dbc'd inside here we might say something like 10 dot times do we're going to create a user so we say user dot find or create i guess user dot where no yeah user.create one of the goals of making these seed files is to make them item potent but in this case it i don't really care so we can say email is faker internet email password is faker internet password does that work faker um faker internet password cool and faker faker internet dot methods let's see minus class dot methods so we've got email domain name user username uh password uh okay um yep so that should work fine i guess maybe is there a name uh name faker internet faker internet why do i keep saying internet internet username okay i don't know why that took so long uh okay faker internet username um all right whatever this is this is going to be our hosts so we're going to say like hosts is an empty array and this is going to shovel into hosts so we're going to just add a bunch of hosts and i guess here we can use create bang so that it forces the creation all right so then the next thing we want to do is i guess like inside of here we can also do like 10 times do again and here we can create the listings so listing.create and this is going to have the host be this user host is this hosts host and host is going to be host i don't know if we even need to keep track of that array or not let's let's see so what else does a listing have listing a listing has the host it's going to have a title and let's see faker um well faker address we're definitely gonna want that but faker construction what what does this do material heavy equipment trade subcategory wow interesting uh trade electrician plumber laborer hvac wow that's super cool okay but that still doesn't give us everything we want okay so what we're trying to do is build out a house so um what is is this oh my gosh no way faker dot house what room furniture faker house star room drawing room kitchen bedroom ensuite uh okay that's got more stuff than our houses have furniture stool drawers stool bedside table interesting okay but that doesn't give us like uh the title of the house which let's just use lorem for that so faker lorem dot methods minus class.new uh okay so we can just get a sentence or lorem.words5 and we can just yeah um so faker lorem words five dot join all right about faker lorem what is this got paragraphs paragraph by characters paragraphs let's see paragraph paragraphs okay can we tell it how many we want no um actually i think this might not even work yep dot join with a new line all right max guests this is gonna be let's just do like 1 to 15 dot 2 a dot sample address line 1 and faker address um city country postcode so faker address dot uh does it have a whole oh street address there we go street address it's so fun like it's crazy that it can give you like full-on addresses like that that's pretty sweet city faker address dot city state faker address dot state country for now let's just say us and the status is going to be draft or published dot sample so let's have like some that are randomly published and some that aren't okay yes that was a lot of work right but the nice thing is that now we can just full sail blow away our entire database and then be up and running pretty quickly let's also create a user with the email that we want to test with so wave at cjab.dev password is password for now okay so then we can say db seed coal and seed and that should run our seed.db or c.rb file and okay look we're getting a bunch of different emails for us to verify our our email address um and you can see the host is being created and it's alyssa coleman antone goodrun orlando joanna carl marissa claude renee lisa wave at okay so this one we do want to confirm your email address has been successfully confirmed wave at cgive dev password and we hit sign in and host photos okay so this maybe this isn't our listing um oh right i guess yeah so the other thing we need is to create some listings for ourselves um c dot rb um uh are like me and then here we can create 10 of our own listings also uh okay now if i try to rerun this watch what happened so railsdbc'd i i want to like rerun it but because the code we've written is not item potent meaning um if we re if we try to rerun it it's failing here because the email has already been taken because we already technically created that user so we can improve c dot seeds.rb by saying something like find or create by email user and then user.password equals password i think this is how it works so let's look it up rails find or create by so this takes i believe this should take a block where you pass it something that might uniquely identify it and then if that does work then um create with find or create buy finds the first record with the given attributes or creates a record with those attributes if it's not found so um if you want to find or create by first name uh okay so yeah so this is this is what it's doing right like find or create by whatever we pass in here is what's going to be used in the where clause where it's like try to find a user that already has the first name scarlet if you find one then just return that one if you don't find one then create one and then run the block i'm pretty sure this is how it works so it always returns a record if creation attempt and failed blah blah blah it's not atomic blah blah blah okay so yeah so let's let's update to that so i think that should work and the host in this case is me and then we could do the same thing technically down here but i don't think we're gonna have email collisions because we're using faker we'll just get like duplicate listings or like more listings every time we run it and more of these emails which i think we can turn off like somehow at the top of uh or like when you first start doing that but okay so if we refresh now we can see all these listings some of them are published some of them are in draft they have fun names and they also have addresses which are beautiful and now if we try to look at slash photos we get this page which is great because that's where we want to be photos index.html this is going to be class text 2 xl margin bottom 4 and font bold and we're just going to save photos and then here we want to have a form that will be um like that'll allow us to upload photos uh but what is this actually going to look like so the action is going to be like what is this host listing photos path for at listing and the method is going to be post but what's what's interesting here is that we want to s also have the label for the caption and that's going to have the okay so it's going to be photo caption is the name of it and the value is nothing for right now um and then separately we need to have uh our what do we need here the um we need to have an input that is hidden with the value of authenticity token or something like that or maybe it's rails authenticity token for our csrf token this is called uh form authenticity token okay so here's our here's our form right now we've got an upload button we've got a caption we also need to add in the file upload so let's go back to our docs for active support and we want to find that form field input type file direct file upload blah blah blah so we'll drop that in there and then refresh our page here i guess this goes over here refresh okay so now i can say choose file we've got to pick a file so i pick one click open and um all right so i don't know if there's any javascript that's actually running when we pick that but if we hit upload then what happened direct uploads so what we can do is we can go to our local storage file here and we can just take a look and see if anything got uploaded and it looks like some stuff might have been uploaded here so if we're in storage uh today at 3 25 so maybe this is the file oh look at that boom that is a picture that is a house picture right there amazing okay so at least that seems to be working so we're able to upload files so here if we choose another file and we say give me number two and then i don't know this is a caption for number two and we say upload and did this one yep so this one added another file here and that is number two the bathroom okay so now that we have these uploading let's make sure that photo.count we've got two photos photo.last all right so that's our caption for number two photo.last.photo um has the photo record and so how do we get out the url for that so if we go back to the docs for active storage then we should be able to call like.url or something on this i believe so um let's see what's it called uh path uh linking to files so okay so here we go url for or rails blob path so if we want to create a download link we use the rails blob and then if we want a permanent url that points to the data we can use url4 i think there's a couple others too for variants different variants here so we have this image tag variant whatever but i don't have image magic stuff set up so let's just see if we can get this working so if we come back over to listing show and say like um if listings.listing.photos.com are exists then we want to put a image tag for um at listing.photos dot first dot photo dot variant let's see if we can get this to work resize to limit 100 100 and we'll go back to the listing show page here and what do we got nothing is showing for that oh this is on this is on the proper listings show page uh exist it should be exists refresh location can't be provided so at listing.photos.first.photo dot url i don't know blob how do i get stuff out of this methods uh minusclass.new.methods purge purge later detach attach attachment so dot attachment uh dot attached dot record uh okay so that gives me back that brings me back to the photo um i thought this is gonna i thought this would have something inside of attachment it does not okay i wonder if in the form we didn't set the name [Music] correctly for the direct download thing so listing edit or no photo photo index so here we have this file we're saying direct upload but um once we've direct uploaded it we've got the file the file is being uploaded but when the direct upload is finished then this file or this field should have like a name and that name should get back some data that's then up then used to upload and so what i think we're missing here is name is equal to photo photo i think something like this so let's go back to host listings and jump into a specific one and then go to slash photos and we're going to upload a photo here testing we say upload and when we say upload we get the direct upload so that's posted and then we get back um oh this is a new tab the payload tab that's cool instead of having it at the bottom here that makes a lot more sense great so that's the file blob and then we get the response what why don't we see the response that's odd uh okay but then we come back to the photos tab all right let's look in the rails logs and see what's going on so we are getting uh okay so what's going on here photo create that came in and it has the photo and this is just like a long id which i'm guessing references the id of the direct upload and there was like something in the response of that direct upload um and i have a feeling this just worked but let's go let's go check so listings 101. can't find listings blah blah blah oh cause it's not published so listing.find 101.update status published i also thought of like a reason why we don't want to be able to manage that status as part of the as part of the edit for that view and it's basically um i think we want to take other actions when that state changes for the listing when the listing is becoming published we want to maybe run some checks on the listing we want to make sure that the person posting the listing is legit they've already got like their merchant account set up so that they can receive payments that they are not sort of like yeah laundering money or anything um and that they're like good actors on the system all right so at least the page is loading now and there seems to be some sort of representation situation going on in here uh so if we go back to listing show and we okay so we were using this variant thing but i don't think the variant works yeah in fact like our rails server crashed and it says down here generating image variants requires the image processing gem please add gem image processing 1.2 to your gem file and this is kind of where i crashed and burned last time so the image processing gem if i recall correctly has like a ton of dependencies let's see if i'm remembering that correctly i think like one of them was not yeah something broke last time when i tried to do that oh wow look at that it totally worked holy smokes okay this is amazing so that that absolutely worked and now we have one that is of a variant 100 by 100 holy smokes okay this is super cool did we get it's like not clear but that's okay uh okay so then i guess the other thing we might want to do is just say like since there are some photos why don't we iterate over all of them at listing.photos.each do photo and we will create image tags for all the photos and they're all going to be resized to that variant um uh and they should show actually we need to add some more listing so host listings 101 slash photos so this is kind of a pain to like pick another one and upload and say bathroom and then pick another one and upload and say blah blah blah blah blah blah but what's yeah so we can come back and we can improve this and make it even better over time um but what i'm hoping is that this will now show ah several photos very cool okay awesome awesome awesome so that is neat i like that a lot uh and we've got at least we've got some photos we can just use the first one as sort of the the listing photo and so um from like host listings here like this image i want to make that image the first photo so if we're in um host listings index here um we are printing out this image which right now i don't want to do that one anymore i want to do instead uh this one which will be the first photo for the listing so l.photos.first dot photo and we're going to give it that variant and i guess we want to just give it those classes so i think we can just say um class maybe uh i can't remember image tag for rails i think rails image tag i think we can just pass the class in some html helpers but i can't remember the exact format here so image tag and what does it look like size class yep okay so we can just we can just do like class is h12 width 12 and rounded rounded full and let's see how that looks oh right it might not have a photo so if l.photos.exists then we do this else we're going to do something else and that'll be some default image for now we'll just put back that person's face can't build a uri eldaphotos.first.photo.variant blah blah blah l l dot photos first uh photo dot variant resize to limit oh you know what i think it's crashing and burning because we created a couple of ah yeah we created a couple photo objects photo.first dot destroy we created a couple that didn't didn't actually work so let's try this again all right so all right look at that now we've got one that has uh some sort of actual picture so if we come to this draft and we say um i think on that listing show for hosts i also want to have edit photos so now we can come in here we can say pick a photo let's make it this one upload and now when we go back to our listings we should have another one with a picture there and we do cool okay fantastic uh all right so now we are able to upload images of our listings that's super cool and it allows us to yeah get um some better i don't know better experience if you can actually like see pictures of the listing right um so yeah let's leave it at that and then yeah we'll play around in the next episode thanks so much for watching and we'll see you next time cheers [Music] you
Info
Channel: CJ Avilla
Views: 141
Rating: undefined out of 5
Keywords: cjav_dev, web development tutorials, web development for beginners, vim, ruby, rails, javascript
Id: 9rDuCaTreJA
Channel Id: undefined
Length: 46min 43sec (2803 seconds)
Published: Thu Dec 02 2021
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.