1
\$\begingroup\$

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 => true)

    #Get companies with these tags, and add their vouchers to the list
    @companies = Company.tagged_with(tags, :any => 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 << 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
\$\endgroup\$

1 Answer 1

1
\$\begingroup\$

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 => true).includes(:vouchers) # eager load vouchers
    @vouchers   = [
      Voucher.tagged_with(tags, :any => true),
      companies.map(&:vouchers)
    ].flatten.uniq
    @categories = @vouchers.map(&: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 => :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 => true).includes(:categories)
    companies = Company.tagged_with(tags, :any => true).includes(:categories)

    @categories = [vouchers, companies].flatten.map(&: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.

\$\endgroup\$
3
  • \$\begingroup\$ I'm using your first example. Exactly the type of refactoring I was looking for. But watch out, you can't call .strip on params that are nil \$\endgroup\$
    – Frexuz
    Commented Jul 7, 2013 at 18:23
  • \$\begingroup\$ @Frexuz Ah, of course you're right about that. Wasn't thinking. But it's an excellent chance to use ActiveSupport's try method. I've updated my code \$\endgroup\$
    – Flambino
    Commented Jul 8, 2013 at 10:36
  • \$\begingroup\$ Yes, I went with try instead. Just love that method :) \$\endgroup\$
    – Frexuz
    Commented Jul 8, 2013 at 11:42

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.