4

I am building an app where I'd like to use a simple search to search through the object's title, AND tags (using acts_as_taggable_on) in one search

I am able to construct either, but not both, and am at my wits end trying to figure it out.

To search using tags, I use:

@post = Post.tagged_with(params[:search])

To search the object, I use:

@post = Post.search(params[:search])

And I wrote a method called search in the Post model, as follows:

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

Any idea how to combine these two queries? Any attempts so far have been unsuccessful mainly because there isn't a "tag" column in my Post model, etc.

lucapette
  • 20,564
  • 6
  • 65
  • 59

3 Answers3

2

I figured it out and testing it in my solution, I wrote the joins myself so it isn't as clean as I would like so if anybody has a better solution, I'd still love to see it. Here's what I came up with:

q = "%#{search}%"
        Post.select('distinct posts.*').joins("LEFT JOIN taggings on posts.id = taggings.taggable_id")
        .joins("LEFT JOIN tags on tags.id = taggings.tag_id")
        .where('title LIKE ? OR tags.name LIKE ?', q, q )

This is working as expected in my tests. I am testing with three records. One has the search term in the title, another has just the tag and the third has both the title and the tag, so it shouldn't return duplicates.

Hope this helps.

Andrew Van Slaars
  • 1,816
  • 1
  • 14
  • 20
  • I've updated the code to include the select method in order to add distinct to the query. My initial test wasn't comprehensive enough and I just discovered that duplicate results were being returned in some cases. At this point, it's almost like writing raw SQL code, but it's the best I could come up with at this point. – Andrew Van Slaars Feb 29 '12 at 13:32
1

I found this: Search form with acts_as_taggable_on (Rails 3)

this might work, but I am also paging my results with the kaminari gem so when I use this approach, I get the following error:

undefined method `page' for []:Array

So this won't work in my situation. I would love to find a solution with a single query to handle the whole thing.

Community
  • 1
  • 1
Andrew Van Slaars
  • 1,816
  • 1
  • 14
  • 20
  • You might be able to do it in two steps like shown [here](https://github.com/davidcelis/goodbre.ws/blob/master/app/controllers/dashboard_controller.rb). I haven't tested it though, but hopefully this gets you on the right track: beers = Beer.includes(:brewery, :style).top(100) beers = Kaminari.paginate_array(beers).page(params[:page]).per(25) – Matt Nov 14 '12 at 16:46
0

As a followup to Andrew's code, I used this search method in my model -- just adding case-insensitivity and making the post "title" query a bit more explicit since my model actually contained a "name" attribute which was ambiguous.

def self.search(search)
  if search.present?
    q = "%#{search}%"
    Post.select('distinct posts.*').joins("LEFT JOIN taggings on posts.id = taggings.taggable_id")
      .joins("LEFT JOIN tags on tags.id = taggings.tag_id")
      .where('lower(posts.title) LIKE lower(?) OR lower(tags.name) LIKE lower(?)', q, q )
  else
    all
  end
end
willbradley
  • 694
  • 7
  • 11