Using checkboxes to filter records

2020-07-14 08:55发布

问题:

I am trying to learn rails from zero programming experience and have an app im trying to make. With much help from people on here, I have an index page of venues which are filterable by which area they belong to via a dropdown menu. I would like to be able to have the same affect but using checkboxes and also being able to select multiple areas to add to the filter. This is what I have so far:

Model :

class Venue < ActiveRecord::Base
  belongs_to :user
  has_many :reviews
  belongs_to :area

  scope :north, where(:area_id => "2")
  scope :west, where(:area_id => "3")
  scope :south, where(:area_id => "4")
end

Controller:

def index
  if (params[:area] && Area.all.collect(&:name).include?(params[:area][:name]))
    @venues = Venue.send(params[:area][:name].downcase)
  else
    @venues = Venue.all
  end
end

Venues index.html.erb:

<div class="filter_options_container">

  <form class="filter_form", method="get">
    <%= select("area", "name", Area.all.collect(&:name), {:prompt => 'All Areas'}) %><br>
    <input type="submit" value="Filter" />
  </form>

  <br><br>

  <form class="filter_form", method="get">
    <% Area.find(:all).each do |a| %>
      <%= check_box_tag("area", "name") %>
      <%= a.name %>
    <% end %>
    <input type="submit" value="Filter" />
  </form>
</div>

<div class="venue_partials_container">
  <%= render :partial => 'venue', :collection => @venues %>
  <div class="clearall"></div>
  <%= link_to 'add a new venue', new_venue_path, :class => "add_new_venue_button" %>
</div>

The first form (the dropdowns) in the filter_options_container works fine but the checkboxes (the second form) is returning "can't convert Symbol into Integer" what am I missing/doing wrong?

Thankyou for any help.

回答1:

I don't know exactly what's causing your error, but I can tell you that the check_box_tag helper isn't working the way you expect it to. From the documentation, it's defined like this:

check_box_tag(name, value = "1", checked = false, options = {})

So calling check_box_tag("area", "name") repeatedly will just give you <input id="area" name="area" type="checkbox" value="name" /> multiple times. Note that the "value" attribute (which is the value that gets sent to your server when that form is submitted) is always "name" - not what you want!

Instead, try the following:

<% Area.all.each do |a| %>
    <%= check_box_tag("areas[]", a.id) %>
    <%=h a.name %>
<% end %>

The things I've changed:

  1. I used Area.all instead of Area.find(:all) - I did it for cosmetic reasons, but DanneManne's answer claims it's obsolete in Rails 3 (I wouldn't know - I'm still on 2.3.8).
  2. I used the area's ID instead of its name in the value field; it's always good to look things up by ID if you can - IDs are integers, and compare faster than strings, and there'll always be an index on the id column in your database for extra-fast lookups.
  3. And last, but way most importantly I threw in [] after the input name. This lets Rails collect all the values submitted with this name into an array, rather than just taking the last one. See below:

Throwing the URL...

/whatever?a=3&a=17&a=12

...at a Rails app gives you the params hash...

{:a => 12}

...but the URL...

/whatever?a[]=3&a[]=17&a[]=12

...gives you what you want:

{:a => [3, 17, 12]}

And if you have an array of all the area_ids you're interested in, you can get all the venues that are in any of those areas in a one-liner (isn't Rails great?):

filtered_venues = Venue.all(:conditions => {:area_id => params[:areas]})

Just make sure you have a valid array of area ids before calling that finder - if you don't, your conditions hash will evaluate to {:area_id => nil}, and Rails'll find you all the venues that don't have an area_id - probably none, and definitely not what you want.

Hope this helps!



回答2:

In your call to Area.find you supply the argument :all. This syntax is deprecated in Rails 3 which I assume you are using. All the previous usages of find(:all, ...) or find(:first, ...) etc can no longer be used. Instead you should be using it like you in the first form: Area.all(...)

As a side note, it also looks like the check_box_tag arguments might be wrong. I guess you should send a.name instead of "name".

Here is a modified form that I think works:

<form class="filter_form", method="get">
  <% Area.all.each do |a| %>
    <%= check_box_tag("area", a.name) %>
    <%= a.name %>
  <% end %>
  <input type="submit" value="Filter" />
</form>