Controller method to do fuzzy search for companies I would like some help to clean up this action, especially from @companies and downward. The comments should be enough to explain :)

def search
  @query = params[:query]
  unless @query.blank?
    @query.strip!
    #Get tags with fuzzy match
    tags = Tag.where("name LIKE ?", "%#{@query}%").pluck(:name)

    #Get vouchers with these tags
    @vouchers = Voucher.tagged_with(tags, :any =&gt; true)

    #Get companies with these tags, and add their vouchers to the list
    @companies = Company.tagged_with(tags, :any =&gt; true)
    @companies.each do |company|
      #Because can't merge with nil. Can this be re-written?
      if @vouchers.empty?
        @vouchers = company.vouchers
      else
        @vouchers.merge(company.vouchers)
      end
    end

    #Get every voucher's category. Can this be re-written?
    @categories = []
    @vouchers.each do |voucher|
      @categories &lt;&lt; voucher.categories
    end
    #Because can't call .flatten on nil
    if @categories.any?
      #Need to flatten because the array will contain an arrays of categories [[],[],[]]
      @categories.flatten!.uniq # I don't really want .flatten.uniq in the view, or?
    end
  end
end
Unless I've misjudged what you're going for, this should work (it's not pretty though, I'm sure there's an even better way)

def search
  @query = params[:query].try(:strip) # strip here instead

  unless @query.blank?
    tags = Tag.where("name LIKE ?", "%#{@query}%").pluck(:name)
    @companies  = Company.tagged_with(tags, :any =&gt; true).includes(:vouchers) # eager load vouchers
    @vouchers   = [
      Voucher.tagged_with(tags, :any =&gt; true),
      companies.map(&amp;:vouchers)
    ].flatten.uniq
    @categories = @vouchers.map(&amp;:categories).uniq
  else
    # you need something here, by the way...
  end
end


If you don't need each of the collections in the search results, but only need the categories, you should probably add this to the Company model

has_many :categories, :through =&gt; :vouchers


then you can do

def search
  @query = params[:query].strip # strip here instead

  unless @query.blank?
    tags = Tag.where("name LIKE ?", "%#{@query}%").pluck(:name)
    vouchers  = Voucher.tagged_with(tags, :any =&gt; true).includes(:categories)
    companies = Company.tagged_with(tags, :any =&gt; true).includes(:categories)

    @categories = [vouchers, companies].flatten.map(&amp;:categories).flatten.uniq
  end
end


However, I'd think about restructuring the database if possible, to avoid the mix of 1st and 2nd order associations.