Sunspot
Note on Sunspot Solr Binary
There is an optional gem, `sunspot_solr`, which offers a pre-packaged Solr distribution for local development. Some online guides recommend installing this and give examples of using it. This information can be very confusing to new users, and we do not recommend it. There are no command line tools or Rake tasks for starting, stopping or restarting a Websolr index. Additionally, the pre-packaged Solr distribution may be a very different version from your Websolr index, which means it will behave differently in a local environment.
Step 1: Set up a Websolr Index
- If you’ve signed up with us at https://websolr.com, you will want to follow the directions here. When it comes to choosing a Solr configuration, make sure to pick the Sunspot option.
- Heroku users should follow these directions. Websolr will default to creating the new index using Sunspot’s configuration. You can also specify it via the command line, like so:
heroku addons:create websolr[:PLAN] [-a APP_NAME] --config=sunspot
Step 2: The Solr Index URL
When you have successfully created your index, it will be given a semi-random URL. You can find this in the Websolr.com Dashboard, in the Overview tab. From this view, you can also verify that the Configuration in use is Sunspot’s:
WEBSOLR_URL
created when Websolr is added to the application. This variable will contain the fully-qualified URL to the cluster.
/select
or
/admin/ping
to your URL and requesting the resource:
Using curl:
curl https://us-east-1.websolr.com/solr/a1b2c3d4e5/select {"responseHeader":{"status":0,"QTime":59},"response":{"numFound":0,"start":0,"docs":[]}}
Using a browser:
Note on Solr endpoints
/select
,
/update
,
/admin/ping
,
/admin/luke
, etc, will result in an HTTP 503 error. This does not mean that the index is offline, just that the user has made an incomplete request. If you absolutely want to verify whether your index is up and running, append
/admin/ping
to your URL and see what happens.
Step 3: Install the Gem
To install Sunspot, you will need the sunspot_rails gem. Add the following to your Gemfile outside of any blocks:
gem 'sunspot_rails'
Make sure to bundle install
. This will install the libraries necessary to use Sunspot.
Step 4: Tell Sunspot where your Solr Index is located
You can optionally also create a sunspot.yml
file with this Rake task:
rails generate sunspot_rails:install
The sunspot.yml
file looks something like this:
production: solr: hostname: localhost port: 8983 log_level: WARNING path: /solr/production development: solr: hostname: localhost port: 8982 log_level: INFO path: /solr/development test: solr: hostname: localhost port: 8981 log_level: WARNING path: /solr/test
sunspot.yml
file will supersede your
WEBSOLR_URL
variable in the environment running the Rails app! This means that Heroku users who have added Websolr to their app should not create the
sunspot.yml
file unless they have a good reason. And if you do create it, you’ll need to edit it to point to the right location(s).
sunspot.yml
file that points to different indices, you can do something like this:
production: solr: hostname: us-east-1.websolr.com port: 443 scheme: https path: /solr/0a1b2c3d4e5f development: solr: hostname: us-east-1.websolr.com port: 443 scheme: https path: /solr/blahblahblah test: solr: hostname: us-east-1.websolr.com port: 443 scheme: https path: /solr/s0m3t35tth1ng
It is also possible to add some additional parameters to the sunspot.yml
file, which override the default behaviors. You can find documentation on these different parameters here.
Step 5: Add Sunspot to your Models
Any model that you will want to be searchable with Sunspot will need to be configured to do so by adding the searchable
block with its attributes. Our demo app has a User model that looks something like this:
class User < ActiveRecord::Base searchable do text :first_name text :last_name text :email text :address text :city integer :zip_code text :company text :company_description end end
This makes the model searchable with Sunspot.
Step 6: Create a Search Route
You will need to set up a route to handle searching. The easiest way to do this is to have a search route per model. This involves updating your models’ corresponding controller, and defining a route in config/routes.rb
. You’ll also need to have some views that handle rendering the results, and a form that posts data to the controller(s). Take a look at how we implemented this in our demo app for some examples of how this is done.
Our Example
In our example Rails app, we have one model, User
, with a handful of attributes. It looks something like this:
class User < ActiveRecord::Base searchable do text :first_name text :last_name text :email text :address text :city integer :zip_code text :company text :company_description end end
To implement search, we used the file called app/controllers/users_controller.rb and added this code:
def search @results = User.search { fulltext "#{params[:q]}"}.results end
Note on Hits vs. Results
User#search
method above returns a Sunspot data structure of the matching object IDs. Calling
.hits
on this data structure will return the IDs, while calling
.results
will return the actual ActiveRecord objects. See the
Readme file for more information.
We then created a route in the config/routes.rb
file:
resources :users do collection do post :search # creates a route called users_search end end
Next, we need to have some views to render the data we get back from Solr. The search
controller action will be rendered by creating a file called app/views/users/search.html.erb
and adding:
<div class="container"> <h3>Search Results</h3> <% if @results.present? %> <%= render partial: 'search_result' %> <% else %> <h4>Nothing here, chief!</h4> <% end %> </div>
This way if there are no results to show, we simply put a banner indicating as such. If there are results to display, we will iterate over the collection(assigning each one to a local variable called result
), and passing it off to a partial. Create a file for a partial called app/views/users/_search_result.html.erb
and add:
<div class="row"> <div class="col"> <%= link_to "#{result.first_name} #{result.last_name} <#{result.email}>", user_path(result) %><br /> <strong><%= result.company %></strong><br /> <em><%= result.company_description %></em><br /> <br /> </div> </div>
User
model is configured for searching in Solr, and has routes for sending a query to Solr. The next step is to render a form so that a user can actually use this feature. This is possible with a basic
form_with
helper.
<%= form_with(url: search_users_path, method: "post", class: 'form-inline my-2 my-lg-0', local: true) do %> <%= text_field_tag(:q, nil, class: "form-control mr-sm-2", placeholder: "Search") %> <%= button_tag("Search", class: "btn btn-outline-info my-2 my-sm-0", name: nil) %> <% end %>
This code renders a form that looks like this:
Step 7: Push data into Solr
<Model>.reindex
. So if you want to reindex a model called
User
, you would run
User.reindex
.
User
model, you could run:
bundle exec rake sunspot:reindex
.
Step 8: Put it all together
At this point you should have all of the pieces you need to search your data using Sunspot. In our demo app, we have this simple list of users:
UsersController#search
action, via the route set up in
config/routes.rb
:
UsersController#search
action, where it will be passed to Sunspot, which queries Solr. Solr will search the users index, and return any results to a class variable called
@results
.
UsersController
will then ensure the appropriate views are rendered. Each result will be rendered by the partial
app/views/users/_search_result.html.erb
. It looks something like this:
Congratulations! You have implemented Sunspot in Rails!
Final Thoughts
You can find information on these additional subjects in the Cookbook section below. And if you have any ideas or requests for additional content, please don’t hesitate to let us know!