Search code examples
ruby-on-railssolrsunspot

Sunspot Solr: Match multiple attributes together from a same has_many association?


Let's pretend we have two users,

User A, with:

  • skill of 'Ruby' and experience_years of '5'
  • skill of 'HTML' and experience_years of '7'

User B, with:

  • skill of 'Ruby' and experience_years of '2'
  • skill of 'HTML' and experience_years of '5'

I only want to match User A, that is, the user with 5 years of Ruby experience.

The controller and model code below matches both User A and B, because the skill and experience_years is evaluated separately and both users have 'Ruby' and '5', just not together.

How do I write the controller (or model) part to only match User A?

Models

class User < ApplicationRecord
  has_many :user_skills

  searchable do
    text :skill do
      user_skills.map { |r| r.skill.name }
    end
    text :experience_years do
      user_skills.pluck(:experience_years)
    end
  end
end

class UserSkill < ApplicationRecord
  belongs_to :user
  belongs_to :skill
end

class Skill < ApplicationRecord
end

Controller

class UsersController < ApplicationController
  def index
    sunspot = User.search do
      fulltext 'Ruby' do
        fields(:skill)
      end
      fulltext '31' do
        fields(:experienceYears)
      end
    end

    @users = sunspot.results
  end
end

Solution

  • The solution is to use a dynamic integer.

    Model (inside searchable block):

    # skill + experienceYears composite field:
    dynamic_integer :skill_composite do
      if skills
        skills.inject({}) do |hash, e|
          hash.merge(e.skill.skill_code => e.experience_years)
        end
      end
    end
    

    Controller:

    with(skill_code).equal_to experience_years
    

    Note the use of skill_code instead of name, this is because special characters like spaces in a string will cause troubles. skill_code is a sort of parameterized value of name in this case.