Global Autocomplete Search with Rails

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
[Music] so in this week's episode we're going to be talking about adding a global autocomplete to your rails application it's something like you see on go rails where you can type in a keyword or a search term or whatever and it's going to make some Ajax requests to load the first five results of a couple different models so this is searching episodes and forum threads or as they are called here community discussions those then search the models appropriately it actually did two searches one to get the episode's results and community discussions was a separate search then that gets displayed via a library that you use to create the autocomplete functionality but you can also just hit search because this is normal textbox and do your real search and you can get a lot more results than just the first five here so every time you type into this box it's going to fire an ajax request the server is going to do a searches and combine those results into a JSON object that gets returned to the browser and then your JavaScript library for the autocomplete will take those results and then display them however you like so I'm using a library called easy autocomplete to pull this off and the feature that we're going to be using here is their categories feature so if you were to click on an autocomplete text box this is going to give you these options but as you can see here fruits and vegetables are the main categories and they're formatted a little bit differently than mine but if you click on any of these they will change the text there you can also type something like pepper and it will highlight and bold that and actually do your autocomplete search there now this shows you a good example of this you have a JSON object that you would get back from the server it has these groupings so we have fruits and the results for that are in a-and vegetables have an array as well and the way that you tell this library how'd it parse those out separately is you give it a list of categories and you tell it well it's going to pull fruits from the fruits property here and then the header for what you display will be fruits with a couple hyphens on both sides and the same thing goes for vegetables and that is exactly what I do in go rails it's just a little bit more complex because we are making these clickable so that when you click one it will take you to the right page on the app so this is basically what we're going to be doing this library already supports us out of the box so that means we don't have to worry about the fronted work of making sure that our groupings work appropriately and that these aren't selectable items and so on so that allows us to skip a lot of the front-end work we just have to implement easy autocomplete and make sure that we pass them the appropriate options and feed it with the proper JSON to make sure that it all works so let's dive into building out an example with this and see how all of that works behind the scenes now our example application here is really straightforward its rails 5.1 app we've got a model for movies and another model for directors and those are the two that we're going to be searching i've seated with some data already and I've installed bootstrap just so that we have a nav bar so that we can put the search box in there and make that look pretty now easy autocomplete has some installation instructions you can download the library and it comes with two CSS files and a JavaScript file you want to include your JavaScript and then optionally you can include the extra themes or you can use their default theme we will need to put those in our application and you also need to make sure that you have jQuery installed and whether you do that through a CDN or you do that through your own asset pipeline like using the jQuery Rails gem which is probably the best way to go for convenience of this example I'm just going to throw in this example using the CDN because I'm a little lazy on that aspect so for this we want to grab the CSS and we want to put those inside our application style sheets folder so I'm going to go ahead and do that and move those over here inside of there and then our jQuery easy autocomplete is going to go in the JavaScript folder and that's going to give us the ability to go into our app assets Java scripts and then you can see that file here we can go into application Jas and we can require jQuery dot autocomplete and do the same thing for our style sheets we can do a require easy autocomplete and if you would like you can do the themes as well and that will give us access to all of those in our app now the first thing I like to do after installing some of that JavaScript and CSS is to open up the browser and then manually test that out and make sure it is loaded and we can define some options here and if we grab the first input and really the only input on the page in this example easy autocompletes we can pass in those options and if all that works correctly you saw this change a little bit in styling as it got the CSS applied for easy autocomplete and now if we were to type in any of those options like blue or red we will see it automatically create though the autocomplete window and then highlight the word that you were typing and any of those matches and you can see if you type eeya you see that highlighted on four out of the five results so we do know easy autocomplete is working and now we need to go work on our search stuff on the back end so then we can then pass that in to easy autocomplete before these options here so we need a search endpoint that's actually generic to all of the models that we want to search in our case I'm going to be searching movies and directors and so it makes sense for us to have some sort of main controller with a search action on it so if we have get search we can also define the controller's main and that should give us a slash search URL that would go to the main search action and inside of there we can define in our main controller which I just created we can define a search here that will give us the results back that we want so really we want to render JSON from here all the time and we want to render from a JSON object and we want movies and array back and we also want directors and I want to pass it array back so if this is all wired up correctly we should be able to go to search and you can append dot JSON or you can just do dot search and you should always get that ruby hash back that's converted to JSON so we want to dynamically populate these results from a database search or elastic search or whatever kind of search you want to use but we want to populate these two sets of results with our search results so if we hop over to the gem file I've installed the ransack gem and I've already bundle installed this and this is what we're going to be using for basic search but of course you can use elastic search for this or search kick or PD search or any of those other search options all you need to be able to do really is to take the params run it query against your data and get our array of results back so as long as your search can do that you're afraid to use whatever you like to power this you just need to get those results back so that you can pass them in in that main controller and main controller will need to query those results so let's pull that up here we need to search both movies and directors here and if you are familiar with how to do that with right Zach it looks something like this where we have a query where we set up the query for ransack and then we ask for the results and we can optionally ask for distinct results so we don't get duplicates and so what I'm going to do is change this up a little bit we are not going to use that cue variable which is useful for rendering search forms with ransack we're just going to get the movies back so we'll say movie and we'll do directors and director will be our search there so we're going to use the exact same params queue for both of those and get distinct results for each one and then we'll take those results and then put them into our array here so we have two arrays of active record objects and we need to be able to convert these to the name and URL JSON objects and there's of course many different ways that you can convert active record to JSON you could do this in Ruby iterations with maps you could do this with jbuilder or activemodel serializers it doesn't really matter what option you take here and what I'm going to do is I'm going to add a jbuilder template for this just so that we can have our code organized appropriately there so I'm going to split the windows and we're going to add it app mate up views main search dot JSON J builder and here we can say json dot episodes du and JSON or json movies rather go rails would be episodes and json dot array we can pass in at movies and for each of those movies that we have we can have json named movie name and json dot URL is movie path and we can have the movie passed into that and if we take this and we do the exact same thing instead of movie we have director for all of those we should now be generating the JSON appropriately so that we have the name and the URL for each one of those and of course now we can go try that out by adding dot JSON to the URL and we're going to get our list of movies and directors and we get all of the movies and directors in the database as our results and the only other thing that I would say here is you can add a before action to say force JSON only on the search method there and that private method called force JSON consent requests up format equal to JSON and then that will make sure that your search doesn't have to have that dot JSON in the URL and you can hit slash search and it will always render JSON no matter what that format was like search HP ml it will automatically always return you JSON now we have to go and correct our movies and directors stuff because if we add in a query term here like cure cure for wellness should be a filtered result here but we don't actually see that filtering correctly so we need to go and address that make sure that we have our search stuff working so that when you pass in Q equals whatever we take that and do a proper search across our models so first off what we want to do is we want to limit the results to about five we don't ever want to return more than five otherwise the drop down would be enormous Li long and that wouldn't be very helpful so we want to only keep maybe you know three to five results for each one of those they want to display that will probably be your best results now with ransac this is actually designed for something more complex like searching against multiple columns and different ways of searching so what we want to do is take that params q which is whatever the user types in and we want to actually match that against the name and so we can say game name contains and we want to pass in that params queue into there so we're searching against the name column and we're saying we want to only match one that contained that string that would came from the URL so you can use your search any way you would like and you can pass in this into elasticsearch or anything like that as long as you get those results back and you can limit them to a reasonable number like three to five then you can assign them to this and your JSON jbuilder will automatically take those records and convert them to the proper column and the URL for each one of those so what this is how we're going to do it for ransack your implementation may be a little different if you're using a different search mechanism but here we should be able to say something like Q equals s and we will only get results that have the letter S in it but we can even go further than that and so we can have let's do split so SP and we'll find movies that have SP in it which is only split and there are no directors that have SP in their name in the list that I have in the database so we now know that our search is working appropriately which means that we can go connect easy autocomplete to the search URL and build out our JavaScript to make all of this work nice and easily so once we have that working all we have to do now is to go and add our options into the way that we call easy autocomplete when we set up the page now I'm going to add a new file in a passage JavaScript called search dot je s and this is where we're going to write all of our code now I'm going to try and write as much of this as I can with regular old JavaScript instead of jQuery even though we have jQuery available we're going to add an event listener for document for turbolinks load event and we'll have this function that will get called and then inside of there we want to have that element on the page so I'm going to go to our navbar HTML er via and this input which is that form in the browser we want this to actually have some sort of data behavior or tag or some way of grabbing it I'm going to have a data behavior equal to autocomplete you could call this search or something like that we can have our document query selector this will be for data behavior equal to autocomplete we'll grab that and we'll have our input and that input is what we will use later on to set up easy autocomplete with our options so we're going to have to pass in some options and so we'll set up options here and this is going to get kind of long because we have to define all that stuff that we actually want to implement now the other thing here is that we have a form tag here that we want to replace with a rails form with and I just paste it in here the final form with because it was going to be a lot to watch on camera and it wasn't very interesting but the important bits here are that we are pointing this form to the search path and actually that means that our main search action should probably respond to HTML and not just JSON the other thing is that we want it to be local is true because by default they also board submit as Ajax now by default and we want the method to be equal to get jumping back into our main controller this points out something that if our form is going to submit a get request our search method doesn't actually respond to HTML request it only responds to JSON formats so what we could do is we can actually duplicate the search method and rename one to autocomplete force the autocomplete to only respond to JSON and our regular search instead of doing limit of 5 we actually call our page nation here or have no limit and then we of course need to also rename our view for the main search JSON jbuilder this would need to be renamed to autocomplete JSON jbuilder and so that would allow you to separate out your autocomplete and your search which actually might be a good thing so for example if your search ends up searching maybe more models than you would actually autocomplete then you could add in some other queries down here or change the way that that works for the HTML search whereas your autocomplete is going to be very fine-grained and kept to only as a single one so this is something you would have to change and of course you'd have to change your routes a little bit so you could add autocomplete up here and so on but it may be something wise that you might want to do to separate those two out the other option that you have here is to actually do a respond to block and pass in the format's and you have your formats define what they do so HTML you could add in your page nation here format JSON could actually set up at movies equals app movies limit v and movies can be a change to directors here directors and then you could get rid of this over here and kind of combine them into the same action and this time you wouldn't want to force JSON for that either so this is another way of handling that it's kind of up to you if those are going to diverge then you would want to split these out into their own actions it can be very dedicated to them but it really comes down to your application for example Facebook the autocomplete is going to search common things like people or groups but if you actually hit the search and go to the results that actually can list out businesses or events or locations all that sort of stuff as well so they have their autocomplete that actually function separately from a real search and so you can do the exact same here but because we only have two models I'm going to keep them all together and let me fix this real quick so that should be directors and movies okay so let's dive into all these options there's a lot of them so we're going to run through these fairly quickly but you can look at their documentation for how all this works so first is get value this is going to be assigned to name this is the name of the object in our JSON so when we pull up search JSON this JSON name in each object that we signed to the movie name or the director name is what we want to display in the browser next up we have the URL option this is going to take a function it will give us our phrase that we typed in and we have to return a string for slash search let's do JSON so we can always have that you can make this your autocomplete URL if you wanted q equals and we add the phrase into that and that should return our URL that we want to hit every time the user types next up we have our categories this is going to be an array of categories so we're going to give it that each category is going to have a list location this is that key where they start so we have movies and we also have lists location of directors and then you can also add in your header option into this so that you can give it a title so you have header directors and you can give it a little bit of HTML in here like strong tags and that's going to give us bold headers for those and we'll have movies here as well last but not least we want to be able to handle the clicks on those events and the way that we can do this is by passing in a list option and on choose event is going to be a function and this is where we will handle when the user clicks on one of those items now a few things that we should probably change here and first off is that we could change this to you jQuery selector so that we have access to easy autocomplete since this will now be a JSON or a jQuery object is since this is a jQuery plug-in we have to do that and but that's also going to give us the ability to grab the get selected item data on the item and we can set VAR URL equal to that and let's just console dot log the URL out for the item so this is going to give us the ability to grab the selected item that the user just clicked on and in our browser if everything goes well we can type SP and click this and we'll see that that gives us the URL of movies flash to and split shows up here and it the field because we clicked on it by default that's going to insert that and so what we can do then is we can use turbolinks dot visit that URL and we can also say input set the value empty to also clear that out so that it feels more like you clicked on a result so now if we type split and we click this we will be navigated to the movie split in our database and so we can do this from anywhere we can have a cure for wellness that will take us there we can also do something like go to a director Gore Verbinski and that will take us to director slash one and now we have this awesome autocomplete that's actually navigating us directly to pages on our site and we don't have to search in our app last but not least is that if you type in a word and you don't click one of the results and you actually submit the search form you'll be taken to that same search URL that will have the query in it just like the search' autocomplete URL the JSON version this will be able to generate your HTML results to give to the user for their search so that is how you implement autocomplete and to search for them and so this gives you the functionality of both of those and if you are interested you can always split those two out to their own autocomplete actions and a search action and handle those a little bit differently in each case so I hope this was useful and I will talk to you in the next episode [Music]
Info
Channel: GoRails
Views: 16,367
Rating: undefined out of 5
Keywords: Ruby, Ruby on Rails, Rails, Javascript, HTML, CSS, Servers, Databases
Id: ibxlNN73UTY
Channel Id: undefined
Length: 24min 1sec (1441 seconds)
Published: Tue Jun 06 2017
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.