【问题标题】:Rails: filter index via dropdown and checkboxesRails:通过下拉列表和复选框过滤索引
【发布时间】:2011-11-24 07:13:51
【问题描述】:

我正在尝试通过下拉菜单(位置)和一组复选框(类别)过滤产品的索引页面,但效果并不好。我可以通过下拉列表过滤位置或类别。我也可以在一个表单中组合两个下拉菜单,但如果我无法为两个单独的表单找到可行的解决方案。

我想要实现的是提交 onchange 的位置下拉列表以及我想要作为带有过滤器按钮的复选框的类别。

我目前的代码提供了下拉菜单和复选框,但存在一些问题:

  • 复选框列出了所有类别,但是当我根据这些进行过滤时,参数作为数组传递,但视图中没有返回任何产品
  • 每当我按类别过滤时,我都会丢失之前的位置选择

以下是相关代码:

产品型号

....
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"

控制器

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

库 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>

我一直在绕圈子,所以非常感谢任何方向。

为了部分回答我自己的问题,我修改了库索引并在类别表单中使用了一个隐藏字段,该字段调用 location_id 参数(如果存在),这意味着我可以保留选择类别后所做的任何位置选择复选框。

进一步的更新是我添加了一个检查是否通过查询参数来检查类别复选框,更新了下面的库 index.html.erb。

最后一次编辑与@rdvdijk 输入合并(谢谢)

库 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 => :get ) 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 %>
.......

【问题讨论】:

    标签: ruby-on-rails checkbox filter params


    【解决方案1】:

    您有两种形式,我认为这是您的问题的一部分。每当您在第一种形式中更改位置时,只会将 location_id 发送到您的控制器 index 操作。每当您选择一个类别并提交第二个表单时,只会将category_ids 发送到您的控制器index 操作。

    使用一种形式,看看会发生什么。它至少应该使过滤对单个提交起作用。

    我看到的第二个问题是您没有选择所选位置,或检查所选类别。

    查看options_for_selectcheck_box_tag 的文档以解决此问题。

    【讨论】:

    • 当两个选择都在一种形式中时,我可以进行选择,但这不允许我进行独立的选择(位置或类别)。我现在在类别选择中使用一个隐藏字段,该字段调用位置参数(如果存在),这使我现在可以先设置位置,然后再过滤类别。我编辑了我的问题以显示该修改。我不确定我是否遵循您提出的第二个问题,但我会查看该文档。谢谢
    • 所以你的问题归结为:你有两个过滤器。当您更改第一个过滤器时,应该应用这两个过滤器,而在更改该过滤器时只应用第二个过滤器。我理解正确吗?
    • 根据您的建议,我意识到在做出选择之后我并没有选择任一表单的状态,因此我添加了一些查询,这些查询根据参数设置过滤器的状态。我对原始问题进行了一些更新。因此过滤器按应有的方式工作:单独使用任一选择仅提交该过滤器,除非在提交两者并保留状态的位置之后选择类别。所以我的最后一个问题是,虽然 category_ids 作为数组传递,但数据库查询没有返回任何产品。感谢您迄今为止的帮助。
    • 感觉你的表单模板逻辑有点多。您的checked 变量不需要所有ifelsifelse 逻辑。只需将params[:category_ids].include?(category.id.to_s) 直接放在check_box_tag 中即可。这将删除 8 行代码。少即是多。另外,不要使用for category in Category.all,而是使用Category.all.each { |category| .. },这是“更好”的 Ruby 习语。
    • 另外,这个问题和 cmets 有点失控了。 StackOverflow 上的问题应该是有限的。这个问题涉及几个不同的主题,您可能希望专注于更小的、更具体的问题。请参阅常见问题解答的这一部分:stackoverflow.com/faq#dontask
    【解决方案2】:

    在我的例子中,product belongs_to :category 和 category has_many :products,我将 categories.id 修改为 category_id,它可以工作!

    scope :category, lambda { |*category_id| {:include => :categories, :conditions => ["category_id = ?", category_id]} }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-12-15
      • 1970-01-01
      • 1970-01-01
      • 2015-11-02
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多