Question

I'm implementing a searchable database whereby I have a Tool model that is taggable via the acts as taggable gem. It also has a class method that allows me to search on the name property of the tool:

class Tool < ActiveRecord::Base

  acts_as_ordered_taggable

  def self.search(search)
    if search
      where('lower(name) LIKE lower(?)', "%#{search}%")
    else
      scoped
    end
  end
end

Now in one of my pages, I'm trying to implement a search function that returns results if a tool's name includes the substring of the search OR a tool is tagged with a tag that includes the substring of the search. I have the following code for my controller:

class ToolsController < ApplicationController

  def index
    @tools = Tool.all
    if params[:search]
      @tools = @tools.search(params[:search])
    end
  end
end

Now I know I can also search for tags and have it return tools using the helper provided with the acts-as-taggable-gem:

@tools = @tools.tagged_with(params[:search], any: true, wild: true)

This will give me tools that are tagged with the search string, matching any single tag using wildcard search. Now what I want to be able to do, is merge this into one ActiveRecord::Relation. I know I can call it twice and do a union with eager loading into arrays, however, I need it as an ActiveRecord::Relation as I use the tag_cloud helper which takes a relation as an input. Is there an efficient way I can do this? Maybe in SQL? I've tried lots of ways and can't seem to figure out how to connect them and all the searching I've done on StackOverflow talks about merging two ActiveRecord::Relations by chaining them (intersection), when what I want is a union of the two datasets.

Thanks.

Was it helpful?

Solution

I think you can try following code (NOT tested). Based on this answer

def index
  @tools = Tool.all # I hope you use Rails 4
  if params[:search]
    tag_tool_ids = @tools.tagged_with(params[:search], any: true, wild: true).pluck(:id) # or pluck('tools.id')
    search_tool_ids = @tools.search(params[:search]).pluck(:id) # or pluck('tools.id')
    @tools = @tools.where('id IN (?) OR id IN (?)', tag_tool_ids, search_tool_ids
  end
end

I hope that this will call one query (but rather complicated and maybe not optimized)

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top