Integrating Atlas Search in a Ruby on Rails Application
Rate this tutorial
In the article "Getting Started with MongoDB Atlas and Ruby on Rails," Luce Carter showed us how to integrate MongoDB Atlas in a Ruby on Rails application named Inspiration. Users could capture and organize their creative ideas, thanks to the integration of MongoDB Atlas. In this article, we'll build upon the foundation laid out in Luce’s article and take a deeper dive as we integrate text search directly within our Rails application. By the end of this article, you will have a fully functional search feature embedded in your Rails app, allowing users to efficiently find the ideas they need.
Before getting started, you will need to complete the following:
- Create a MongoDB Atlas cluster.
- Update the development config section inside
config/mongoid.yml
and add your own connection string. - Ensure that you have data stored in your MongoDB Atlas cluster that you can query against Atlas Search. This should include the ideas you have added to your Inspiration application.
- Using the Atlas UI create an Atlas Search index called inspiration. A step by step guide on how to create an Atlas Search index can be found in the Atlas documentation.
Now that we have our environment properly configured, and our inspiration index created, we can update our model to handle queries to our database. We do this by defining a search method in our Idea model. The method
self.search(query):
defines a class method named search that takes a single argument query and returns the results.- Open your
idea.rb
file - Replace its contents with the content below:
1 class Idea 2 include Mongoid::Document 3 include Mongoid::Timestamps 4 field :name, type: String 5 field :description, type: String 6 field :picture, type: String 7 8 def self.search(query) 9 aggregation_pipeline = [ 10 { 11 "$search": { 12 "index": "inspiration", 13 "text": { 14 "query": query, 15 "path": ['name', 'description'] 16 }, 17 "sort": { 18 "score": {"$meta": "searchScore"} 19 } 20 } 21 }, 22 { 23 "$limit": 20 24 } 25 ] 26 results = collection.aggregate(aggregation_pipeline) 27 28 search_results = results.to_a 29 search_results.map do |result| 30 Idea.new( 31 id: result["_id"], 32 name: result["name"], 33 description: result["description"], 34 picture: result["picture"] 35 ) 36 end 37 end 38 end
When you call
idea.search("example query")
, Mongoid constructs and executes a MongoDB query that:- Performs a full text search using Atlas Search on the inspiration index.
- Runs a query across the name and description fields.
- Sorts the results by their relevance score.
- Limits the results to 20. Using a limit is good practice to avoid performance issues if your collection contains millions of documents.
The search_results variable then converts the raw results from MongoDB into an array of hashes that can then be mapped to new Idea instances and rendered in our view files.
1 search_results.map do |result| 2 Idea.new( 3 id: result["_id"], 4 name: result["name"], 5 description: result["description"], 6 picture: result["picture"] 7 ) 8 end
Now that we have defined our search query in our Idea model, we need a way to initiate that search. We do this by adding a search action in our IdeasController.
Add the following code to your IdeasController:
1 def search 2 @query = params[:query] 3 @ideas = @query.present? ? Idea.search(@query) : Idea.all 4 render :display_results 5 end
With this setup, when you submit a search query it will call the search method in the Idea model to perform the search. The results will then be rendered in our view files.
We will be creating a separate SearchesController to handle search requests and to display the search results.
Run the following command to generate the SearchesController and the display_results view file.
1 rails generate controller Searches display_results
Open your
searches controller.rb
file and add the following code.1 class SearchesController < ApplicationController 2 def display_results 3 query = params[:query] 4 @results = Idea.search(query) 5 end 6 end
Open the file
display_results.html.erb
and add the below, which will return our search results.1 <div class="search-results"> 2 <h1>Search Results for "<%= params[:query] %>"</h1> 3 4 <% if @results.empty? %> 5 <p>No ideas found.</p> 6 <% else %> 7 <div class="idea-container"> 8 <% @results.each do |result| %> 9 <div class="idea"> 10 <h2><%= result.name %></h2> 11 <p><%= truncate(result.description, length: 150) %></p> 12 <img src="<%= result.picture %>" alt="<%= result.name %>" /> 13 14 <p><%= link_to "View", idea_path(result.id) %></p> 15 </div> 16 <% end %> 17 </div> 18 <% end %> 19 </div> 20 21 <%= link_to "Back", ideas_path %>
In your
application.css
file, add the below to create some basic styling for your search results:1 .search-results { 2 /* Add styles for the search results container */ 3 width: 80%; 4 margin: 0 auto; 5 } 6 .idea-container { 7 display: flex; 8 flex-direction: column; 9 } 10 .idea { 11 padding: 20px; 12 border-bottom: 2px solid #ccc; 13 border-radius: 10px 10px 0 0; 14 margin-bottom: 10px; 15 } 16 .idea h2 { 17 margin: 0; 18 } 19 .idea p { 20 margin: 0; 21 } 22 .idea img { 23 width: 100px; /* Adjust the width of the image */ 24 height: auto; /* Maintain aspect ratio */ 25 display: block; /* Ensure the image takes up full width */ 26 } 27 /* Remove bullet points */ 28 ul { 29 list-style-type: none; 30 padding: 0; 31 }
With this setup, when you submit a search query, it will be routed to the
SearchesController
, which will call the search method in the Idea
model to perform the search. The results will then be displayed in the display_results
view.Now, we just need to create a simple UI so that users can submit queries directly in our Rails application.
- Open your
index.html.erb
. - Copy and paste the code below to add a search form and a placeholder for search results.
1 <%= form_tag(search_results_path, method: :get, class: "form-inline") do %> 2 <div class="input-group mb-3"> 3 <%= text_field_tag :query, params[:query], placeholder: "Search Ideas...", class: "form-control" %> 4 <div class="input-group-append"> 5 <%= submit_tag "Search", class: "btn btn-primary text-white" %> 6 </div> 7 </div> 8 <% end %>
- Add the following styling for the search bar in your
application.css
file:
1 .input-group { 2 width: 100%; 3 } 4 5 .btn-primary { 6 background-color: #007bff; 7 border-color: #007bff; 8 color: white; 9 } 10 11 .btn-primary:hover { 12 background-color: #0056b3; 13 border-color: #004085; 14 }
To redirect users to the display_results view file, we need to update our routes.rb.
Add the following get request to your routes file:
1 Rails.application.routes.draw do 2 root to: "ideas#index" 3 4 resources :ideas 5 get '/search_results', to: 'searches#display_results', as: "search_results" 6 end
It’s time to test out our application. Begin by running the following command in your project directory:
1 rails server
To submit a search, add your query term in the search bar and click on “Search.”
Here are the results of a search in my MongoDB database for the word “pet”:
Please note that search results are dependent on the contents of your own database. So make sure your database has the data you are requesting. However, as the complexity of your data increases, the need for more advanced search queries may be necessary. Refer to the MongoDB documentation for information regarding these queries.
And with that, we now have a fully functional search feature integrated into our Rails application. This integration not only enhances the usability and functionality of our application but can also help improve user engagement. Our Rails app now offers a powerful tool for users to find and manage their creative ideas effectively. Be sure to explore more about MongoDB Atlas and Rails in the community forums, share your experiences, or ask any questions you may have!