Usage Without ActiveRecord: ElasticSearch
Though we’ll be hitting elasticsearch in this example, remember that this is just an HTTP API underneath the hood. The same pattern applies to a variety of use cases.
First we need a Client for elasticsearch
. Though you can feel free
to use a variety of clients, this example will use trample.
Though we’ll show code snippets below, feel free to view the diff on github.
Also keep in mind, we’ll be showing a one-off customization here. You
probably want to extract this code into an Adapter
if this is going to
become a core component of your application.
Start by installing trample:
Tell searchkick that we want to
index Employee
s and Position
s:
Define our search classes. These tell trample the configuration of the search:
In our controller, we need to pass a base scope. Before, we were passing
an ActiveRecord::Relation
(Post.all
). Let’s pass an instance
of Trample::Search
instead. Since by default search results come back
as Hashie::Mash
es, we’ll also specify our serializer directly. You
could also use a generic SearchResult
serializer, it’s up to you.
Since we are now passing a non-default base scope, we need to tell our
Resource
how to query and resolve this new scope. Start by switching to
the pass-through adapter, and resolve using trample
’s query API:
You can now hit http://localhost:3000/api/v1/employees
- the exact
same payload is coming back, but is now sourced from elasticsearch
!
Let’s add a prefix filter:
Hit http://localhost:3000/api/v1/employees?filter[first_name]=hom
.
You’re now successfully querying the elasticsearch
index.
If we want sorting and pagination, we need to tell the Resource
how to deal with that, too:
View the Resource and Adapter documentation for additional overrides, like statistics.
The last step is adding the positions
association. If we want
has_many
-style macros we need to create an Adapter
, but for now
let’s simply use the lower-level allow_sideload
DSL. We need to define
two functions: how to build a scope for the association, and how to
associate the resulting objects:
Convert the PositionResource
to use elasticsearch
, just like we did
for Employee
:
Create the SerializablePositionSearchResult
class that we referenced
in app/serializers/serializable_employee.rb
:
We can now sideload positions
- check out the results at
http://localhost:3000/api/v1/employees?include=positions
. We’re
fetching employees and their corresponding positions
in a single
request, via elasticsearch
. Any filters/changes/default sort/etc that
apply to PositionResource
can be re-used at this endpoint.
If this was a one-off section of our application, we can call this good
enough and move on. But as we continue to use this pattern, it’s going
to get monotonous writing the same filter overrides, allow_sideload
wiring code, etc. To DRY up this code, we can package our changes into
an Adapter.