Rails: filter index via dropdown and checkboxes
I'm trying to filter an index page of products via a dropdown menu (locations) and a set of checkboxes (categories) and not being very successful with it. I can filter via a dropdown for either location or category. I can also combine the two dropdowns within the one form but if I can't get a working solution to two separate forms.
What i'd like to achieve is a dropdown for location that submits onchange and the categories I'd like to have as checkboxes with a filter button.
The code I have at the moment provides the dropdown and checkboxes but there are some problems:
- the checkboxes list all the categories but when I filter based on these the params are passed as an array but no products are returned in the view
- whenever I filter by category i lose the previous location selection
Here's the relevant code:
Product Model
....
has_many :categorizations
has_many :categories, :through => :categorizations
has_many :localizations
has_many :locations, :through => :localizations
class Product < ActiveRecord::Base
default_scope :order => 'end_date'
scope :not_expired, where('end_date > ?', Time.now)
scope :location, lambda { |*location_id| {:include => :locations, :conditions => ["locations.id = ?", location_id]} }
scope :category, lambda { |*category_id| {:include => :categories, :conditions => ["categories.id = ?", category_id]} }
scope :unique, :group => "title"
Controller
class LibraryController < ApplicationController
def index
if params[:location_id] && params[:category_ids]
@products = Product.not_expired.unique.location(params[:location_id]).category(params[:category_ids]).paginate(:page => params[:page], :per_page => 9)
elsif params[:category_ids]
@products = Product.not_expired.unique.category(params[:category_ids]).paginate(:page => params[:page], :per_page => 9)
elsif params[:location_id]
@products = Product.not_expired.unique.location(params[:location_id]).paginate(:page => params[:page], :per_page => 9)
else
@products = Product.not_expired.unique.paginate(:page => params[:page], :per_page => 9)
end
end
end
Library index.html.erb
<% if notice %>
<p id="notice"><%= notice %></p>
<% end %>
<div class="filter_options">
<form class="filter_locations", method="get">
<% @options = Location.all.map { |a| [ a.name, a.id ] } %>
<%= select_tag "location_id", options_for_select(@options), :onchange => "this.form.submit();", :include_blank => true %>
</form>
<form class="filter_categories", method="get">
<% for category in Category.all %>
<%= check_box_tag("[category_ids][]", category.id) %>
<%= category.name %>
<% end %>
<input type="submit" value="Filter" />
</form>
</div>
I've been going around in circles with this so any direction is greatly appreciated.
to part answer my own question I've modified the library index and used a hidden field in the category form that calls for the location_id param, if it exists, which means I can retain any location selection that's been made after selecting category checkboxes.
Further update is I've added a check for whether the category checkbox is checked by querying the params, updated library index.html.erb below.
Last edit with @rdvdijk input incorporated (Thanks)
library index.html.erb
.......
<%= form_tag( '', :method => :get ) do %>
<% @options = Location.all.map { |a| [ a.name, a.id ] } %>
<%= select_tag "location_id", options_for_select((@options), params[:location_id]), :onchange => "this.form.submit();", :include_blank => true %>
<% end %>
<%= form_tag( '', :method => :ge开发者_如何转开发t ) do %>
<% if(params.has_key?(:location_id)) %>
<%= hidden_field_tag 'location_id', params[:location_id] %>
<% end %>
<% Category.all.each do |category| %>
<%= check_box_tag 'category_ids[]', category.id, params[:category_ids].to_s.include?(category.id_to_s) %>
<%= category.name %>
<% end %>
<%= submit_tag 'Filter' %>
<% end %>
.......
You have two forms, I think that is part of your problem. Whenever you change a location in the first form, only the location_id
will be sent to your controller index
action. Whenever your select a category and submit the second form, only the category_ids
will be sent to your controller index
action.
Use one form and see what happens. It should at least make the filtering work for a single submit.
The second problem I see is that you don't select the chosen location, or check the chosen categories.
Take a look at the documentation for options_for_select
and check_box_tag
to fix that.
In my case, product belongs_to :category and category has_many :products, I modified categories.id to category_id, it works!
scope :category, lambda { |*category_id| {:include => :categories, :conditions => ["category_id = ?", category_id]} }
精彩评论