Don’t you love pages that are reactive and lively? They’re a delight to use. But it’s a nightmare for the developer to program. However, with just a little mix and match of the right frameworks, you can build delightful pages that don’t take a toll on you.

In this tutorial we’ll build a live search page with ReactJS, Rails and Elasticsearch. A live search page is a just a search page that responds to the query, as it’s being typed.

Something like this,

Liveserach

Here’s how it is going to work.

The communication between Elasticsearch, Rails and ReactJS

Let’s start out by creating a simple Rails scaffold called “songs” which has “name” and “artist” as the attributes. Simple.

rails g scaffold songs name:string artist:string

Now lets add a search action in the SongsController that will accept a search query and render a JSON with the search results. If the request is XHR, we’ll render a JSON. If it’s not, we’ll render the Index page.

To integrate Elasticsearch, we’ll use Searchkick. This will allow us to search on our Songs model with Elasticsearch. Just add this to your Song model.

searchkick text_start: [‘artist’], text_start: [‘name’]

Now for the fun part, ReactJS. We’ll be using the React gem to do this. Just add it to your Gemfile!

Now we have access to a new helper, react_component. This helper is very similar to render :partial, but instead of rendering an ERB, it’s going to render the React component. And just like passing locals to your partial, we’ll be passing props here. Add this to your index.html.erb.

<%= react_component “SongsContainer”, { songsPath: songs_path(:json), searchPath: search_path } %>

The two props we’ll be passing here is the path to index in JSON format and the search path. This is how index.html.erb should look now,

Now lets create a SongsContainer in

app/assets/javascripts/components/_songs_container.js.jsx

Remember how I said props are like locals? Well what if your locals could change based on some conditions, and the UI automatically refreshed to show the new data?

Let’s take an example of a live stream. As new data comes up, the UI pushes down the old content and automatically updates to show the new content. And all this happens without you having to reload the page! This is essentialy what state is. It’s the data in React that when changes, causes the UI to reflect the same.

So simple, you have props which are like locals and don’t change, and state which is dynamic and causes the UI to refresh.

Let’s see how SongsContainer looks,

Scary right? But it’s pretty simple. The barebones of a React Class are it’s componentWillMount(), getInitialState() and render(). Let’s look at each of them,

componentWillMount()

This is the function that gets automatically triggered when the this React component loads into the DOM. So once it’s loaded we are telling it to access the index path in the form of JSON, and render out the content. Now, once you hit the main page, all the songs are rendered.

getInitialState()

This is pretty self explanatory. It is used to set the initial state of the… state. It sounded better in my head.

render()

This is the special function. It renders out the HTML content to the page. Kind of like in ERB, but not as powerful. The one major thing to remember here is that all content rendered here must be enclosed in ONE HTML element. It can be a <div> or a <ul> or anything else. This is due to the way JSX parses out the HTML content. Also remember to close orphan tags with a /, like in the case of <img /> or <br />.

Let’s see what exactly is is that render is doing here. In the first look, it seems like there is some custom tags that are being rendered. In a way that is true. This is how we call other React components, just like how we call a partial within a partial!

The first part is similar to something like <%= render @songs %>. It will loop over the array of songs and render out each one of them.

The second part is what renders the search form. And just like how we passed props from the ERB file, we can pass props from one component to the other.

This is how the Songs component looks like,

Pretty simple. It’s looping over the songs array and calling yet another React component to display each song. The important part here is the “key” prop that’s being passed on. This acts like an unique identifier to React. So when new content is being added on, React will just diff out the elements and refresh only the new content. Pretty neat huh?

This is how the Song component looks like, (notice the singular form here).

Finally! We can see the damn song.

Let’s look at something really interesting, the actual search form. There’s three props that are being passed on, “searchPath”, “submitPath” and “cancelPath”.

searchPath: It is the path to the search action in SongsController.

submitPath: It is the function in SongsContainer which will make a request to the searchPath along with the query that is being typed into the form.

cancelPath: It is the function in SongsContainer which will render out the index action in SongsController. This gives the illusion to the user that he is back on the home page.

Let’s look at some code,

It’s so simple! When there is a change on the input field (the user is typing), it queries the search action in our SongsController, which in turn queries Elasticsearch, and then returns a JSON of the result. This is then stored to the SongsContainer “songs” state. And since the state has been updated, the UI automatically reflects! We have our live search up.

Now in case the user hits on the enter key, the query is submitted again to the search action, but this time the screen reloads. Since we are making a full HTTP GET request.

The code is hosted on Github. It requires a working installation of Rails 4.x.x and Elasticsearch. Happy coding everybody!