Filtering "tags" via checkboxes - HABTM


#1

First post/newbie post… bear with me.

What I’m trying to achive (music site):
A system containing tracks and moods with a HABTM relationship. I’ve
got all that set up and functioning in the admin environment - i.e.
admins can apply a variety of moods to a particular track via a
series of checkboxes. Join table works just fine.

I’m currently stuck on allowing site users to filter a list of moods
via checkboxes to see only those tracks that are “tagged” with the
selected mood or moods. In my hacking I’ve got it working for a
single mood, but multiple moods… nada.

My def results needs some help. I’m lost in the woods. Any insight
would be very appreciated. Code below:

Don

Here’s an excerpt of the error that might helpful.

Parameters: {“commit”=>“Show Tracks”, “moods”=>[“1”, “2”]}

MOODS_CONTROLLER.RB
def results
params[:moods].each do
#@my_id=mood
end
mood = Mood.find(4) # hard coded for a single query.
@tracks_by_mood = mood.tracks
end

LIST.RHTML

Moods

Select a mood or moods below to see a list of track with those moods

    <%= start_form_tag :action => 'results', :id => @mood %> <% Mood.find(:all).each do |mood| %>
  • <%= check_box_tag("moods[]",mood.id) %><%= mood.name %> - <%= mood.description%>
  • <% end %> <%= submit_tag 'Show Tracks' %> <%= end_form_tag %>

RESULTS.RHTML

Results

<% for track_by_mood in @tracks_by_mood %> <%end%>
<%= track_by_mood.title %> <% for mood in track_by_mood.moods %> <%= mood.name %>, <%end%>

#2

This is a great question. I’m trying to do something similar in a
demo application I’m putting together that searches through apartment
listings. I’m trying to accomplish the same as Don but in my case I’m
looking to filter searches with multiple bedroom sizes … IE: search
for apartments that are studios, 1br, or 2br …

for the life of me I can’t figure out how to create the call to
find_all with all of the selected checkboxes though.

  • J

#3

I guess it’s a good thing that this always happens, but, of course as
soon as I sent this email I had a “lightbulb” moment and figured it
out.

Don - This might work, try this:

def results
moodsearch = “”
params[:moods].each { |eachmood| moodsearch=moodsearch+" OR
mood=’"+eachmood+"’"}
moodsearch = moodsearch.slice!(3, moodsearch.length)
mood = Mood.find(:all, :conditions => moodsearch)
@tracks_by_mood = mood.tracks
end

basically I figured we should build the search condition dynamically
by looping through the checked values in the moods array. throw the
string that’s built in there as the conditions, and search away. (The
slice method is just there to get rid of the head "OR ".)

I tried this in my own applicaction and it worked out perfectly.

  • Joel

#4

Yup - that works just as well and looks much more elegant than my
solution. Thank you Pat!

  • Joel

#5

How about:

moods = params[:moods].join(", ")
Mood.find(:all, :conditions => “mood in (#{mood})”)

Totally untested, but I think it’ll work, and you should be able to
adapt it. WAY prettier than looping/slicing :slight_smile:

Pat


#6

Guys-

Be careful with this. As it stands you are not escaping the params

you are putting in the :conditions search. So you are leaving
yourself open to sql injection attacks.

If you use my ez_where plugin you can do this same search like this:

@moods = Mood.ez_find(:all) { mood === params[:moods] }

The === operator and this ez_find method will create this where clause:

:conditions => [“mood IN (?)”, params[:moods] ]

where params[:moods] is an array of the check boxes.

You can read more and get the download link to this plugin here:
There is a ton of other cool features that make multi param searches

a lot cleaner in the plugin

Cheers-
-Ezra