We’re finally able to answer the age old quandary: “When I jump I …”
Skip Intro 👈 🤠
Software today is truly a thing of wonder. The devices in our pockets and their features would have had us burned at the stake or heralded as demigods in a past life. Unless, you are one of a few select operators who still use AN ORIGINAL Motorola Razr, in which case, you are still a demigod in my book.
Sadly though, because of how common place these devices and software features are; the magic is often lost on us. We assume, because we see them everywhere and how well designed they are, they must be simple to code or implement. (A principle known as magic 🧙♂️ in computer programming)
Any sufficiently advanced technology is indistinguishable from magic.
-Arthur C. Clarke
Today, I want to explore one of these features we see commonly; one that I very much took for granted (like the nimrod I am). I want to explore Autocomplete Prediction. For those unfamiliar, it’s what most of us use everyday when we type something into google.
In my mind, this always seemed like such a trivial thing. So trivial, that when I was first asked how to implement it in a rails app, I responded with a scoff and said it’d take me no time at all (how very wrong I was… 🤦🏽♂️).
And like any good ruby developer I went off to find that one gem or package that would have me hailed as the next Dijkstra by my friends and peers when I unveiled my autocomplete feature. Now if you’re reading this article, you can probably guess, I found no such gem. 😭
So, with my tail between my legs, I set off to try and figure out how one does autocomplete predictions in a rails application. Through my initial research, it became readily apparent the tool of choice would be Algolia, a SaaS company that is the gold standard for providing search services; some would describe them as the bee’s knees. 🐝
Before we get too deep into what Algolia is; let’s go ahead and set up an application for us to use with Algolia.
Our app will be simple enough, we simply need a model with a few attributes to search along. These attributes are what we’ll display in our predictions as our user searches.
For the app generation, I’ll be using BambooSticks 🎍, a decision-tree template for rails apps that we use at MangoTree anytime we’re kicking off a project. I’m using it here because it configures bootstrap, sets up Stimulus, and arranges our preferred js & css folder structure.
Great, we’re on our way. After dropping in the faker gem, and generating our Poke’mon model (with name, location, and move attributes), I went ahead and created 500 instances of Poke’mon to populate my database.
From there, I created a simple home page that would act as my root_path and the screen that would house my search bar.
Ok, we’re off to a good start.
Now, let’s talk about Algolia. There is an assumption here, that if you’re looking at an article about setting up Algolia with a Rails app, you probably know what it is.
But just in case you don’t, Algolia is a powerful SaaS that helps you implement search and then improve upon it thru analytics. Just as you would utilize tools like pg_search or Elasticsearch to implement search in your application, Algolia is the gold standard for search implementation, and has built some incredible out of the box developer tools for you to build an incredible search experience. (As a side note I am not sponsored by Algolia in any way, I just really like their product 💸 However, if anyone at Algolia is feeling a little generous, hit your boy up, 37 to 43 tacos per meal ain’t cheap 🌮)
So with that little “I ❤️ Algolia” diary session behind us, let’s go ahead and set everything up.
We’ll follow a three step process to get everything working together.
- Set up an account on Algolia and index your data
- Connect with algoliasearch to communicate with the Algolia API
- Implement autocomplete.js for the dropdown prediections
Setting up Algolia & Indexing Your Data
Fortunately, getting started is as simple as signing up (no credit card necessary), and if you decide to move forward they operate on a pay-as-you-go model. The more search requests or records you index (more on this later), the more you pay.
Once, you’ve set yourself up with an account let’s go ahead and grab three important pieces of information we’ll need from your dashboard. Your application id, your search-only API key, and your admin API key (These are located under the ‘API Keys’ tab on the left hand column). To make sure we keep our keys secret I’ll be using dotenv-rails to manage my API keys. I’ve tossed them into my .env file with the following naming convention.
Mind you, I’m calling my admin key the ALGOLIA_INDEX_KEY.
To set up the API client that will allow us to interact with Algolia’s client-side Search API, we need to follow the setup on algoliasearch-rails (a gem provided by the Algolia team). I’ve provided step by step directions, but please refer to their documentation as well for more information.
- Add the algoliasearch-rails gem to your gemfile and bundle install
- Set up your algoliasearch.rb configuration file
- Set up the model(s) you want to search
Now it’s time to index our data, a phrase we’ve brought up over and over again but have yet to clarify.
When we speak about indexing our data, we create a secondary data structure that allows us to quickly retrieve records. This secondary data structure consists of keys (aka values we want to look up) that we build through providing information from our records.
For our purpose, we are choosing to index along all fields of our Poke’mon model, but this does not have to be the case, and in fact, should be avoided if possible. We only want to index on data that is relevant to our user’s search experience, no more. (You can choose what to index on by modifying the algoliasearch block in your model’s code)
Pretty decent explanation here 👉 On Database Indexes
A good metaphor to think thru is how you quickly navigate a book through the use of an index. Does the index need to be there for you to locate chapters?
But does it make it easier at the cost of an extra page or two?
And what do we ‘expose’ in our index?
Just the chapter title and number.
So for us, when we start off with Algolia, we need to create an index for our data to actually give us something to search against through Algolia’s Search API. Otherwise, there’s nothing to search against in their servers. Fortunately, we only need to do this one time. From there, the gem uses Rails’ callbacks to trigger indexing on our model anytime changes are made.
So drum roll 🥁 please as we index our data for the first and only time!
Wow, that was easy 👏.
And to make sure the records were passed through, check your dashboard and verify you see the number of records you just indexed; in my case I see 500.
Next we need to tell Algolia specifically what to allow users to search against through their API. In our case, I am allowing users to search against my model’s name, location, and move. These are added for specific indices under the configuration tab.
Great, we’re done with setting up our data in Algolia. On to step 2, connecting to the algoliasearch API from our client-side browser.
Connect with algoliasearch
To do this, the first thing we’ll need to do is add the package to our project. As I’m using yarn, I’ve used the following command:
yarn add algoliasearch
Now let’s see if we can get a request to the API from our browser. To do this, we’ll use a little bit of Stimulus magic ✨ . (Note that Stimulus was setup for us through BambooSticks, install it manually as needed)
Below you can see the code for our Stimulus controller and how we’ve modified our markup to work with Stimulus.
The two important things to notice are, we’ve embedded our search key and Algolia id in our input bar through data attributes. We do this so our Stimulus controller has access to our keys when it makes an API request. The second thing to note is how we access those data attributes in our controller by making our input element a Stimulus target.
At this point, you should see something getting printed in your console. If not, chances are you didn’t restart your server after you installed the algoliasearch package.
This means, whenever Stimulus finds the search controller and connects, it immediately makes a request to the Algolia API looking for charmander in the Poke’mon index we’ve created. Whew, almost done now!
The final step involves adding Algolia’s autocomplete package. Same as before we’ll use yarn to perform the deed and then import into our Stimulus controller.
yarn add autocomplete.js
To then actually call the autocomplete function we’ll need to do two things.
The first is to write a compatibility function between algoliasearch v4 and autocomplete. As of writing this, out of the box, algoliasearch v4 is not compatible with autocomplete, but I’m sure that’ll change soon.
In the autocomplete documentation you can see an example of this compatibility function or use the one I have below:
With our compatibility function in hand we can go ahead and call the autocomplete function on our search-input like so:
Feel free to tweak as needed but the main places to watch are commented in the code below. If you have any further questions make sure to leave a comment.
With this all together, and a server restart (remember those new packages we added!) we should start seeing results dropping down as we type in our autocomplete!
WWWHHHHEEEEEE!!!! We did it, it only took a few handfuls of hair and a minor mental breakdown, but we did it!
Alas, this doesn’t look the prettiest so I went ahead and added a little css styling 💄 which can be found in _searchbar.scss to really bring this together.
And just like that we’re done! 🎉
To recap, we’ve set up algolia autocomplete predictions for our rails applications using a little bit of help from Stimulus. If you have any questions or get stuck, please don’t hesitate to reach out or comment below.
To see the full code base please find it below:
— — — — —
These are hilarious to me, watching someone write about themselves in the third person.
Sy Rashid is a former child who used to hop on the occasional flight and works as a designer and developer at his web development agency MANGOTREE. When he’s not busy coding he teaches as a Lead Instructor for Le Wagon — the #1 coding school globally — where he has trained 100+ students across 3 campuses to bring over 25+ product visions to life thru teaching, guidance, and product management.