I'm using Sunspot to index and search several models in a Rails project and I need to limit results based on the models' HABTM associations with a Department
model. This is because users may not have permission to see records in all departments so results from those departments shouldn't be returned.
Here are the important parts of two of the models:
class Message < ActiveRecord::Base
has_many :comments, dependent: :destroy
has_and_belongs_to_many :departments
searchable do
text :title, :body
text :comments do
comments.map(&:body)
end
date :created_at
integer :department_ids, using: :department_ids, references: Department, multiple: true
end
end
class Document < ActiveRecord::Base
has_and_belongs_to_many :departments
searchable do
text :name
date :created_at
integer :department_ids, using: :department_ids, references: Department, multiple: true
end
end
And here's the search controller code:
class SearchController < ApplicationController
def index
# These arrays are created here for the sake of this example
document_permitted_departments = [1, 2, 3]
message_permitted_departments = [3, 4]
search = Sunspot.search Document, Message do
# This obviously doesn't work
with(:department_ids, document_permitted_departments)
with(:department_ids, message_permitted_departments)
fulltext params[:q]
paginate page: params[:page], per_page: SEARCH_RESULTS_PER_PAGE
order_by :created_at, :desc
end
@results = search.results
@number_of_results = search.total
respond_to do |format|
format.js
format.html
end
end
end
The problem is that a user may be able to read documents in Department A and Department B but they should only see messages in Department B.
Is there a way to apply the with
scope to a specific model in a multi-model search? Or is there another way of doing this that I'm missing?
After a lot more Googling and some trial and error I finally figured it out. Here's a heavily annotated version of the code I ended up with:
class SearchController < ApplicationController
before_filter :authenticate_user!
def index
# These arrays are created here for the sake of this example
# Push 0 on to the end because empty arrays break the `with :department_ids` scopes below
document_permitted_departments = [1, 2, 3].push(0)
message_permitted_departments = [3, 4].push(0)
search = Sunspot.search Document, Message do
any_of do # Return anything that matches any of the scopes in this block
all_of do # Return only those results that match these scopes
with :class, Document # This limits scopes in this block to Document results
with :department_ids, document_permitted_departments
end
all_of do # Return only those results that match these scopes
with :class, Message # This limits scopes in this block to Message results
with :department_ids, message_permitted_departments
end
end
fulltext params[:q]
paginate page: params[:page], per_page: SEARCH_RESULTS_PER_PAGE
order_by :created_at, :desc
end
@results = search.results
@number_of_results = search.total
respond_to do |format|
format.js # index.js.erb
format.html # index.html.erb
end
end
end
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With