Skip to content

Understanding Rails and Blacklight

Chris Beer edited this page Apr 23, 2021 · 7 revisions

Understanding how Blacklight fits within a Ruby on Rails application

In order to understand how Blacklight works, you should have some basic knowledge about how Ruby and Ruby on Rails works. In this section, we'll highlight the most important concepts for working with Blacklight.

Architecture

Blacklight is packaged as a Rails Engine, which means it is distributed as a Ruby gem that provides functionality to the host application; in Blacklight's case, this includes the controllers, helpers, views, and assets to provide a basic search experience.

This means Blacklight can provide its core functionality, but the application is ultimately responsible for all the user interactions presented and will always take precedence over behavior provided by engines. This allows the application to override or change that behavior as appropriate to the application.

Controllers

As part of the install generator, Blacklight adds a CatalogController into your application and looks something like this:

class CatalogController < ApplicationController

  include Blacklight::Catalog

  configure_blacklight do |config|
    ...
  end
end

Blacklight::Catalog is a controller "concern" that provides some endpoints and useful out-of-the-box behavior for search and discovery, as well as viewing a single item.

Blacklight::Catalog provides the configure_blacklight method which allows you to specify and customize many aspects of how the catalog behaviors work using some configuration. You can use this configuration to manage:

  • what search views are available
  • which fields to show
  • how to connect to the Solr index

Note: Information about the Blacklight configuration is provided elsewhere in this wiki.

This Blacklight configuration is done at the class-level, but a separate copy of the configuration is also made available within the controller instance (as CatalogController#blacklight_config) at request time. This allows you to also modify the Blacklight behaviors (e.g. using Rails' .before_action hook) based on parameters from the request (say, from parameters or using information about the user)

The Blacklight configuration allows you to make significant changes to what Blacklight displays on the page and how it interacts with parameters sent to and received from your search index. However, your application's controller can further customize behavior by overriding specific parts of what Blacklight provides, including replacing controller actions, helper methods, view partials, etc.

Finally, note that, although Blacklight provides this CatalogController from its install generator (and seems to be appropriate for many use cases), you are free to rename it, have multiple such controllers, subclass the controller for special use cases, etc.

Models

As with the CatalogController above, Blacklight generates a SolrDocument model into your application. The SolrDocument provides a way to access data as a hash, and it is often useful to add model methods, accessors, and behaviors within the SolrDocument method to make working with the data easy and pleasant.

This model is also key for translating a document from Solr's representation into something that approximates a Rails model in order to provide some of the same conventional behavior one might expect from any other Rails model.

In order to provide some of this magic, Blacklight expects that the Solr document has a unique id (by default, in the id field), but this can be changed by setting the unique_key class attribute:

class SolrDocument
  self.unique_key = 'url'
  ...

Blacklight uses the value of the unique key field to provide appropriate Rails routing behavior, as well as using it to look up additional information from the solr response not contained by the document hash (e.g. Solr highlighting).

Blacklight provides a default implementation of some ActiveModel behavior to make it easy to work with these models within Rails. This includes features like:

Views, helpers, and components

Your application can override any view provided by Blacklight by creating a new view within your application with the same name as the Blacklight view you want to override. E.g., if you wanted to override the view provided by the Blacklight app/views/catalog/_per_page_widget.html.erb partial, you could create the file app/views/catalog/_per_page_widget.html.erb in your own application. When Rails looks for a view to render, it will first look in the app/views directory of the application. If it cannot find the view there, then it will check in the app/views directories of all engines which have this directory.

Note: View overriding in Rails also respects the controller inheritance; if you added another controller (say, AnotherController) that inherited from your CatalogController, you could override partials just for the other controller using the path app/views/another/_per_page_widget.html.erb.

Overriding views is a very powerful way to completely change the look and feel of what Blacklight provides. That said, because views lack a strong contract between the the rendering context and your partial, overriding views in this way can be very brittle and liable to change unexpectedly. Although Blacklight maintainers try to limit breaking changes to major releases, you are strongly advised to write good integration tests to ensure your changes continue to function across releases.

Layout

Blacklight provides a generic layout to the application. This layout is often overridden by applications to provide institutional branding and styles.

If you're integrating Blacklight into an existing Rails application, note that Blacklight expects the layout to provide a some key content areas:

  • flash messages
  • modal
  • content_for(:head)
  • content_for(:container_header)
  • yield(:content)

Routes

Blacklight provides a small number of application-wide routes that are mounted into the application by the install generator:

mount Blacklight::Engine => '/'

produces:

Routes for Blacklight::Engine:
      search_history GET    /search_history(.:format)       search_history#index
clear_search_history DELETE /search_history/clear(.:format) search_history#clear

The install generator also hooks up Rails routing for the CatalogController:

  # as on Blacklight 7:
  # Search behaviors
  resource :catalog, only: [:index], as: 'catalog', path: '/catalog', controller: 'catalog' do
    concerns :searchable
  end

  # Single item behavior
  resources :solr_documents, only: [:show], path: '/catalog', controller: 'catalog' do
    concerns :exportable
  end

The searchable concern adds some routes that the default Blacklight views will use for searching:

search_catalog GET|POST /catalog(.:format)                                                                                catalog#index
advanced_search_catalog GET      /catalog/advanced(.:format)                                                                       catalog#advanced_search
 track_catalog POST     /catalog/:id/track(.:format)                                                                      catalog#track
   raw_catalog GET      /catalog/:id/raw(.:format)                                                                        catalog#raw {:format=>"json"}
opensearch_catalog GET      /catalog/opensearch(.:format)                                                                     catalog#opensearch
suggest_index_catalog GET      /catalog/suggest(.:format)                                                                        catalog#suggest {:format=>"json"}
 facet_catalog GET      /catalog/facet/:id(.:format)                                                                      catalog#facet

while the exportable concern adds some actions for working with individual documents:

email_solr_document GET|POST /catalog/:id/email(.:format)                                                                      catalog#email
  sms_solr_document GET|POST /catalog/:id/sms(.:format)                                                                        catalog#sms
citation_solr_document GET      /catalog/:id/citation(.:format)                                                                   catalog#citation
email_solr_documents GET|POST /catalog/email(.:format)                                                                          catalog#email
 sms_solr_documents GET|POST /catalog/sms(.:format)                                                                            catalog#sms
citation_solr_documents GET      /catalog/citation(.:format)                                                                       catalog#citation

Note: Blacklight uses Rails' polymorphic URL helpers extensively to map a Blacklight document instance (by default, called SolrDocument) to the appropriate route (hence the solr_document routes). Given the proper configuration, this makes it possible to express many different search behaviors within an application (multiple search controllers providing access to documents at a consistent URL, multiple search controllers with their own document endpoints, or a single search controller that links to documents at different endpoints depending on the type of document)

More information about Blacklight routing and some common application-specific routing needs is available in the Configuring rails routes section of the wiki.

Assets

Blacklight adds javascript and stylesheet assets to your application.

Stylesheets are provided using SCSS, and can be modified by overriding Bootstrap's SCSS variables.

Javascript is implemented using a pluggable approach, which we hope provides an easy way to customize behavior.

Locales and internationalization

Blacklight uses i18n (internationalization) extensively to both:

  • translate the Blacklight-provided strings into other languages (with 10+ out-of-the-box translations), and
  • allow applications to customize and override those strings with language more appropriate to the application's audience.
Clone this wiki locally