In my Rails app, I'm using Sunspot, so that users can search "pins" (like a post). All works fine and I'm returning the data as JSON.
However, I'd also like to include in the JSON response, the "user" data associated with each "pin".
I'm not needing "user" to be included in the search, but only as data with each "pin" after the search has been done.
My search works fine, but I can't work out how to add the user data.
module Api
module V1
class PinsController < ApplicationController
respond_to :json
def index
_search = Sunspot.search(Pin) do
fulltext params[:q] do
highlight :title
phrase_fields :title => 2.0
phrase_slop 1
minimum_match 1
end
facet(:position_id, :type_id, :instrument_id, :genre_ids, :skill_id)
with(:position_id, params[:position]) if params[:position].present?
with(:type_id, params[:type]) if params[:type].present?
with(:instrument_id, params[:instrument]) if params[:instrument].present?
with(:genre_ids).all_of(params[:genre]) if params[:genre].present?
with(:skill_id, params[:skill]) if params[:skill].present?
paginate(:page => params[:page], :per_page => 25)
end
_pins = _search.results
_pins_positions = []
_pins_types = []
_pins_instruments = []
_pins_genres = []
_pins_skills = []
_search.facet(:position_id).rows.each do |row|
_facet = Position.find_by_id(row.value)
_object = _facet.attributes
_object["count"] = row.count
_pins_positions << _object
end
_search.facet(:type_id).rows.each do |row|
_facet = Type.find_by_id(row.value)
_object = _facet.attributes
_object["count"] = row.count
_pins_types << _object
end
_search.facet(:instrument_id).rows.each do |row|
_facet = Instrument.find_by_id(row.value)
_object = _facet.attributes
_object["count"] = row.count
_pins_instruments << _object
end
_search.facet(:genre_ids).rows.each do |row|
_facet = Genre.find_by_id(row.value)
_object = _facet.attributes
_object["count"] = row.count
_pins_genres << _object
end
_search.facet(:skill_id).rows.each do |row|
_facet = Skill.find_by_id(row.value)
_object = _facet.attributes
_object["count"] = row.count
_pins_skills << _object
end
_pins_positions = _pins_positions.sort_by { |e| e["title"] }
_pins_types = _pins_types.sort_by { |e| e["title"] }
_pins_instruments = _pins_instruments.sort_by { |e| e["title"] }
_pins_genres = _pins_genres.sort_by { |e| e["title"] }
_pins_skills = _pins_skills.sort_by { |e| e["title"] }
_response = {
:pins => _pins,
:facets => {
:positions => _pins_positions,
:types => _pins_types,
:instruments => _pins_instruments,
:genres => _pins_genres,
:skills => _pins_skills
}
}
respond_with _response
end
end
end
end
A typical response looks like:
{"pins":[{
"id":95,
"user_id":22,
"title":"Ratione sint odio vitae in quis aspernatur.",
"description":"Sunt ut pariatur aut ipsum sit unde alias.",
"latitude":null,
"longitude":null,
"position_id":1,
"type_id":1,
"instrument_id":4,
"skill_id":1,
"soundcloud_url":null,
"created_at":"2012-09-04T06:54:17.000Z",
"updated_at":"2013-10-14T21:58:17.000Z",
"deleted_at":null
}],
"facets":{
"positions":[{
"id":1,
"title":"Non-Professional",
"token":"non-professional","count":2
}],
"types":[{
"id":1,
"title":"Wanted",
"token":"wanted",
"count":2
}],
"instruments":[{
"id":4,
"title":"Synth",
"token":"synth",
"count":2
}],
"genres":[{
"id":12,
"title":"Folk",
"token":"folk",
"count":2
},
{
"id":16,"title":"Hip Hop","token":"hiphop","count":2}
],
"skills":[{
"id":3,
"title":"Advanced",
"token":"advanced",
"count":1},
{
"id":1,
"title":"Novice",
"token":"novice",
"count":1
}]
}}
But, ideally, I'd like to include the associated "user" data for each "pin" in the JSON. As you can see, all I have here is "user_id"...but I want this JSON API to be rather 'flat' and include another hash key called "user" that has things like, "first_name", "age", "gender" etc.
If I was doing a traditional View template, I could just expose "pin" as an instance variable and do something like: @pin.user.profile.first_name
- how can I do this when building my data within Sunspot?
Hope I've made this clear. Many thanks!
I figured out a solution by creating an empty array, looping the results from Sunspot, finding the respective user and pushing to the array.
_results = _search.results
_pins = []
_results.each do |pin|
_object = pin.attributes
_object["user"] = { :profile => pin.user.profile }
_pins << _object
end
I now get a structure, where the profile data is nested in a user key within the pin hash, like so: