简体   繁体   中英

Filterrific Search & Sort Filters No Longer Working After Adding Checkbox Filters

I have a list of books. There are filters on top of the list for search and your standard sort dropdown. Then on the side are checkbox filters (see image below).

在此处输入图片说明



I setup the Filterrific gem according to the documentation, only for the top search and sort filters at first. They worked great on the "All Books" list page, "Series" book list page and the "Collections" book list page. These are all managed by their own controllers but all use the "title" model. A few days after getting the top filters to work, I got the side filters to work using Filterrific. I only did the side filters on the "All Books" list page for now. I wanted to get everything working on that one first before moving it to the other pages.

Only the first set of side filters work (type) but now the search and sort filters no longer work as expected. If I change the sort order nothing happens. Let's say I change it to list the titles from Z to A. The list doesn't change. If I tick one of the side filters then the list changes according to the side filter. BUT if I untick the side filter then the list changes according to the sort dropdown option I'd chosen prior to ticking the side filter. Changing the sort filter again does nothing. It's only working after I tick and untick a side filter. The search filter doesn't work at all anymore.


My "Title" model:

  class Title < ActiveRecord::Base

  # Tenant Of
  belongs_to :account, :inverse_of => :titles
  accepts_nested_attributes_for :account

  default_scope { where(account_id: Account.current_id) }

  belongs_to :writer, :inverse_of => :titles
  accepts_nested_attributes_for :writer

  mount_uploader :cover, CoverUploader
  mount_uploader :cover2, Cover2Uploader
  mount_uploader :cover3, Cover3Uploader

 def to_param
   "#{id}-#{title.parameterize}"
  end


  filterrific(
  default_filter_params: { sorted_by: 'published_desc' },
  available_filters: [
    :sorted_by,
    :search_query,
    :with_btype,
    :with_bformat,
    :with_age,
    :with_series,
    :with_collection,
    :with_guide
  ]
)

# default for will_paginate
  self.per_page = 10

# Search by Author or Title
  scope :search_query, lambda { |query|
  return nil  if query.blank?
  terms = query.downcase.split(/\s+/)
  terms = terms.map { |e|
    (e.gsub('*', '%') + '%').gsub(/%+/, '%')
  }
  num_or_conds = 2
  where(
    terms.map { |term|
      "(LOWER(titles.title) LIKE ? OR LOWER(titles.name) LIKE ?)"
    }.join(' AND '),
    *terms.map { |e| [e] * num_or_conds }.flatten
  )
}

# Sort By All These Options
  scope :sorted_by, lambda { |sort_option|
  # extract the sort direction from the param value.
  direction = (sort_option =~ /desc$/) ? 'desc' : 'asc'
  case sort_option.to_s
  when /^title_/
    order("LOWER(titles.title) #{ direction }")
  when /^price_/
    order("titles.price #{ direction }")
  when /^author_/
    order("LOWER(titles.name) #{ direction }")
  when /^published_/
    order("titles.published #{ direction }")
  else
    raise(ArgumentError, "Invalid sort option: #{ sort_option.inspect }")
  end
}


 def self.options_for_sorted_by
    [
      ['Title - A to Z', 'title_asc'],
      ['Title - Z to A', 'title_desc'],
      ['Price - Low to High', 'price_asc'],
      ['Price - High to Low', 'price_desc'],
      ['Author - A to Z', 'name_asc'],
      ['Author - Z to A', 'name_desc'],
      ['Newest to Oldest', 'published_desc'],
      ['Oldest to Newest', 'published_asc']
    ]
  end

#checkbox Side Filters

# Book Types
scope :with_btype, lambda { |flag|
  where(btype:[flag])
}

# Book Formats
scope :with_bformat, lambda { |flag|
  where(bformat:[flag])
}

# Age Groups
scope :with_age, lambda { |flag|
  where(age:[flag])
}

# Book Series
scope :with_series, lambda { |flag|
  where(sname:[flag])
}

# Book Collections
scope :with_collection, lambda { |flag|
  where(cname:[flag])
}

# Guides
scope :with_guide, lambda { |flag|
  where(gname:[flag])
}


end




My "Books" Controller:

class BooksController < ApplicationController
  skip_before_filter :require_login
  skip_before_filter :not_authenticated
  before_action :set_title, only: [:show]
  layout "unify"

  def index
    @filterrific = initialize_filterrific(
      Title,
      params[:filterrific],
      select_options: {
        sorted_by: Title.options_for_sorted_by
      },
      :persistence_id => false,
    ) or return

    @titles = @filterrific.find.unscope(where: :account_id).paginate(:page => params[:page])

    respond_to do |format|
      format.html
      format.js

    end

  rescue ActiveRecord::RecordNotFound => e
    puts "Had to reset filterrific params: #{ e.message }"
    redirect_to(reset_filterrific_url(format: :html)) and return
  end

  def show
  end

  private

  def set_title
      @title = Title.unscope(where: :account_id).find(params[:id])
  end

  def title_params
      params.require(:title).permit(:cover, :cover2, :cover3, :title, :name, :btype, :genre, :price, :bformat, :pages, :edition, :age, :series, :sname, :collection, :cname, :guide, :gname, :movie, :mname, :isbn, :isbn13, :published, :description, :audio, :audio_html, :video, :video_html, :quote, :barns_noble, :amazon_us, :alibris, :abebooks, :books_million, :amazon_uk, :writer_id, :account_id, :active)
  end
end




My "Books Index" view:

<!--=== Breadcrumbs v4 ===-->
<div class="breadcrumbs-v4">
    <div class="container">
        <ul class="breadcrumb-v4-in">
            <li><a href="/">Home</a></li>
            <li class="active">All Books</li>
        </ul>
    </div><!--/end container-->
</div>
<!--=== End Breadcrumbs v4 ===-->

<!--=== Content Part ===-->
<div class="content container">
    <div class="row">
        <div class="col-md-3 filter-by-block md-margin-bottom-60">
            <h1>Filter By</h1>
            <div class="panel-group" id="accordion">
                <div class="panel panel-default">
                    <div class="panel-heading">
                        <h2 class="panel-title">
                            <a data-toggle="collapse" data-parent="#accordion" href="#collapseOne">
                                Type
                                <i class="fa fa-angle-down"></i>
                            </a>
                        </h2>
                    </div>
                    <%= form_for_filterrific @filterrific do |f| %>
                    <div id="collapseOne" class="panel-collapse collapse in">
                        <div class="panel-body">
                            <ul class="list-unstyled checkbox-list">
                                <li>
                                    <label class="checkbox">
                                        <%= f.check_box(:with_btype, {multiple: true}, 'Childrens', nil) %>
                                        <i></i>
                                        Children's

                                    </label>
                                </li>
                                <li>
                                    <label class="checkbox">
                                        <%= f.check_box(:with_btype, {multiple: true}, 'Young Adult', nil) %>
                                        <i></i>
                                        Young Adult

                                    </label>
                                </li>
                                <li>
                                    <label class="checkbox">
                                        <%= f.check_box(:with_btype, {multiple: true}, 'Fiction', nil) %>
                                        <i></i>
                                        Fiction

                                    </label>
                                </li>
                                <li>
                                    <label class="checkbox">
                                        <%= f.check_box(:with_btype, {multiple: true}, 'Non-Fiction', nil) %>
                                        <i></i>
                                        Non-Fiction

                                    </label>
                                </li>
                            </ul>
                        </div>
                    </div>
                </div>
            </div><!--/end panel group-->

            <div class="panel-group" id="accordion-v3">
                <div class="panel panel-default">
                    <div class="panel-heading">
                        <h2 class="panel-title">
                            <a data-toggle="collapse" data-parent="#accordion-v3" href="#collapseThree">
                                Format
                                <i class="fa fa-angle-down"></i>
                            </a>
                        </h2>
                    </div>
                    <div id="collapseThree" class="panel-collapse collapse in">
                        <div class="panel-body">
                            <ul class="list-unstyled checkbox-list">
                                <li>
                                    <label class="checkbox">
                                        <%= f.check_box(:with_bformat, {multiple: true}, 'Hardcover', nil) %>
                                        <i></i>
                                        Hardcover

                                    </label>
                                </li>
                                <li>
                                    <label class="checkbox">
                                        <%= f.check_box(:with_bformat, {multiple: true}, 'Paperback', nil) %>
                                        <i></i>
                                        Paperback

                                    </label>
                                </li>
                                <li>
                                    <label class="checkbox">
                                        <%= f.check_box(:with_bformat, {multiple: true}, 'Audiobook CD', nil) %>
                                        <i></i>
                                        Audiobook CD

                                    </label>
                                </li>
                                <li>
                                    <label class="checkbox">
                                        <%= f.check_box(:with_bformat, {multiple: true}, 'E-book', nil) %>
                                        <i></i>
                                        E-book

                                    </label>
                                </li>
                            </ul>
                        </div>
                    </div>
                </div>
            </div><!--/end panel group-->

           <div class="panel-group" id="accordion-v3">
                <div class="panel panel-default">
                    <div class="panel-heading">
                        <h2 class="panel-title">
                            <a data-toggle="collapse" data-parent="#accordion-v3" href="#collapseThree">
                                Age
                                <i class="fa fa-angle-down"></i>
                            </a>
                        </h2>
                    </div>
                    <div id="collapseThree" class="panel-collapse collapse in">
                        <div class="panel-body">
                            <ul class="list-unstyled checkbox-list">
                                <li>
                                    <label class="checkbox">
                                        <%= f.check_box(:with_age, {multiple: true}, '0 - 3', nil) %>
                                        <i></i>
                                        0 - 3

                                    </label>
                                </li>
                                <li>
                                    <label class="checkbox">
                                        <%= f.check_box(:with_age, {multiple: true}, '4 - 6', nil) %>
                                        <i></i>
                                        4 - 6

                                    </label>
                                </li>
                                <li>
                                    <label class="checkbox">
                                        <%= f.check_box(:with_age, {multiple: true}, '7 - 9', nil) %>
                                        <i></i>
                                        7 - 9

                                    </label>
                                </li>
                                <li>
                                    <label class="checkbox">
                                        <%= f.check_box(:with_age, {multiple: true}, '10 - 12', nil) %>
                                        <i></i>
                                        10 - 12

                                    </label>
                                </li>
                                <li>
                                    <label class="checkbox">
                                        <%= f.check_box(:with_age, {multiple: true}, '13 And Up', nil) %>
                                        <i></i>
                                        13 And Up

                                    </label>
                                </li>
                            </ul>
                        </div>
                    </div>
                </div>
            </div><!--/end panel group-->

            <div class="panel-group" id="accordion-v3">
                <div class="panel panel-default">
                    <div class="panel-heading">
                        <h2 class="panel-title">
                            <a data-toggle="collapse" data-parent="#accordion-v3" href="#collapseThree">
                                Series
                                <i class="fa fa-angle-down"></i>
                            </a>
                        </h2>
                    </div>
                    <div id="collapseThree" class="panel-collapse collapse in">
                        <div class="panel-body">
                            <ul class="list-unstyled checkbox-list">
                                <li>
                                    <label class="checkbox">
                                        <%= f.check_box(:with_series, {multiple: true}, 'The Mysterious Mrs. Bean', nil) %>
                                        <i></i>
                                        The Mysterious Mrs. Bean

                                    </label>
                                </li>
                            </ul>
                        </div>
                    </div>
                </div>
            </div><!--/end panel group-->

            <div class="panel-group" id="accordion-v3">
                <div class="panel panel-default">
                    <div class="panel-heading">
                        <h2 class="panel-title">
                            <a data-toggle="collapse" data-parent="#accordion-v3" href="#collapseThree">
                                Collections
                                <i class="fa fa-angle-down"></i>
                            </a>
                        </h2>
                    </div>
                    <div id="collapseThree" class="panel-collapse collapse in">
                        <div class="panel-body">
                            <ul class="list-unstyled checkbox-list">
                                <li>
                                    <label class="checkbox">
                                        <%= f.check_box(:with_collection, {multiple: true}, 'Classic Noir', nil) %>
                                        <i></i>
                                        Classic Noir

                                    </label>
                                </li>
                                <li>
                                    <label class="checkbox">
                                        <%= f.check_box(:with_collection, {multiple: true}, 'True Crime', nil) %>
                                        <i></i>
                                        True Crime

                                    </label>
                                </li>
                                <li>
                                    <label class="checkbox">
                                        <%= f.check_box(:with_collection, {multiple: true}, 'Lesbian', nil) %>
                                        <i></i>
                                        Lesbian

                                    </label>
                                </li>
                            </ul>
                        </div>
                    </div>
                </div>
            </div><!--/end panel group-->

            <div class="panel-group" id="accordion-v3">
                <div class="panel panel-default">
                    <div class="panel-heading">
                        <h2 class="panel-title">
                            <a data-toggle="collapse" data-parent="#accordion-v3" href="#collapseThree">
                                Guides
                                <i class="fa fa-angle-down"></i>
                            </a>
                        </h2>
                    </div>
                    <div id="collapseThree" class="panel-collapse collapse in">
                        <div class="panel-body">
                            <ul class="list-unstyled checkbox-list">
                                <li>
                                    <label class="checkbox">
                                        <%= f.check_box(:with_guide, {multiple: true}, 'Survival', nil) %>
                                        <i></i>
                                        Survival

                                    </label>
                                </li>
                                <li>
                                    <label class="checkbox">
                                        <%= f.check_box(:with_guide, {multiple: true}, 'Travel', nil) %>
                                        <i></i>
                                        Travel

                                    </label>
                                </li>
                                <li>
                                    <label class="checkbox">
                                        <%= f.check_box(:with_guide, {multiple: true}, 'Sexual', nil) %>
                                        <i></i>
                                        Sexual

                                    </label>
                                </li>

                            </ul>
                        </div>
                    </div>
                </div>
            </div><!--/end panel group-->

            <%= link_to('RESET FILTERS', reset_filterrific_url, :class => 'btn-u btn-brd btn-brd-hover btn-u-lg btn-u-sea-shop btn-block') %>
        </div>

        <div class="col-md-9">
            <div class="row margin-bottom-5">
                <div class="col-sm-2 result-category">
                    <h3>BOOKS</h3>
                </div>
                <div class="col-sm-10">

                    <ul class="list-inline clear-both">
                        <li class="grid-list-icons">
                            <%= link_to('Reset Filters', reset_filterrific_url, :class => 'btn-u btn-u-sea-shop') %>
                        </li>


                        <li class="sort-list-btn">
                            <h3>Sort :</h3>
                            <div class="btn-group">
                                <%= f.select(:sorted_by, @filterrific.select_options[:sorted_by], class: 'btn btn-default dropdown-toggle') %>
                            </div>
                        </li>

                        <li class="sort-list-btn">
                            <h3>Search :</h3>
                            <div class="btn-group">
                                <%= f.text_field(:search_query, class: 'filterrific-periodically-observed') %>
                            </div>
                        </li>

                    </ul>
                      <%= render_filterrific_spinner %>
                      <% end %>
                </div>
            </div><!--/end result category-->

        <div id="filterrific_results" class="filter-results">
        <%= render( partial: 'books/list', locals: { titles: @titles } ) %>
        </div><!--/end filter resilts-->

        </div>
    </div><!--/end row-->
</div><!--/end container-->
<!--=== End Content Part ===-->




My "index.js":

<% js = escape_javascript(
  render(partial: 'books/list', locals: { titles: @titles })
) %>
$("#filterrific_results").html("<%= js %>");




My "list" partial:

               <% @titles.each do |title| %>
                <div class="list-product-description product-description-brd margin-bottom-30">
                    <div class="row">
                        <div class="col-sm-4">
                            <a href="shop-ui-inner.html"><%= image_tag(title.cover_url(:listview), class: "img-responsive sm-margin-bottom-20") if title.cover? %></a>

                        </div>
                        <div class="col-sm-8 product-description">
                            <div class="overflow-h margin-bottom-5">
                                <ul class="list-inline overflow-h">
                                    <li><h4 class="title-price"><%= link_to book_url(title) do %><%= title.title %><% end %></h4></li>
                                    <li><span class="gender text-uppercase">By <%= title.name %></span></li>
                                </ul>
                                <div class="margin-bottom-10">
                                    <span class="title-price margin-right-10"><%= title.btype %> | <%= title.bformat %> | <%= title.age %></span>
                                </div>
                                <div class="margin-bottom-10">
                                    <span class="title-price margin-right-10"><%= title.sname %> | <%= title.cname %> | <%= title.gname %></span>
                                </div>
                                <div class="margin-bottom-10">
                                    <span class="title-price margin-right-10">$<%= title.price %></span>
                                </div>
                                <p class="margin-bottom-20"><%= (raw title.description.truncate(500)) %></p>
                                <ul class="list-inline add-to-wishlist margin-bottom-20">

                                </ul>
                                <%= link_to('Read More ...', book_url(title), :class => 'btn-u btn-u-sea-shop') %>
                            </div>
                        </div>
                    </div>
                </div>
                <% end %> 

            <div class="text-center">
                <%= will_paginate @titles, renderer: BootstrapPagination::Rails %>
            </div><!--/end pagination-->




I was under the impression all of these different filters should work under one filterrific form. I have tried separating them but that didn't work either because I wasn't really sure how to have two separately working filterrific forms. I've tried putting the filters in the same order in the model as they are in the view. I've moved the filterrific_results div in and out of the partial. Still I have this strange behavior. It seems like with the way this is setup, all of the filters should be working accurately. I'm not sure what else to try.

I'm using:
filterrific (2.0.5)
rails (4.2.3)
ruby-2.0.0-p643

我相信它在输出的SQL查询中使用AND而不是OR

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM