Ruby on Rails-根据用户选择的选项过滤记录

时间:2019-01-07 16:02:23

标签: ruby-on-rails filter rails-activerecord

在我的应用程序中,我有一个Book模型。我的数据库中大约有10000k图书记录。基本上,该应用程序的工作方式是用户可以选择选项并获取与它们插入的证书匹配匹配的图书列表。

这些books中的每个都有typelanguagegenres

每本书可以有多个typelanguagegenres (就像一个数组)

title: 'Have fun book' 
type: ['pdf', 'paper', 'website']
language: ['Egnlish', 'French', 'German', 'Spanish']
genres: ['comedy']

我的BooksController

def book_params
  params.require(:book).permit(type:[], language:[], genres:[])
end

用户可以在其中插入其凭据并过滤书籍的表格如下图所示:

Book filter form

目前,这是我在BooksController中要执行的操作,以过滤这些书:

@book_filter = Book
                .where(type: @book.type)
                .where(language: @book.language)
                .where(genres: @book.genres)

这很好,但是我有一些问题。例如,如果用户未选择任何图书类型/ type 或其他任何选项,则不会得到all,而是得到nil原因,不会向用户显示任何图书。

我要记住的是,如果未选择该选项,则该选项的where不会受到影响或会通过all

>

我没有运气尝试过这个

@book_filter = Book
                .where(type: @book.type || '')
                .where(language: @book.language || '')
                .where(genres: @book.genres || '')

我的第二个问题是,我认为过滤器可以写得更聪明,并且采用 Rails方式

提前感谢,感谢您的帮助!

Rails 5.1

2 个答案:

答案 0 :(得分:1)

在您的models/concerns中创建一个module

module Filterable
  extend ActiveSupport::Concern

  module ClassMethods
    def filter(filtering_params)
      results = self.where(nil)
      filtering_params.each do |key, value|
        results = results.public_send(key, value) if value.present?
      end
      results
    end
  end
end

module放入您的model中,如下所示:

class Product
  include Filterable
  ...
end

然后在您的控制器中执行以下操作:

@products = Product.filter(params.slice(:status, :location, :starts_with))

私人

# A list of the param names that can be used for filtering the Product list
def filtering_params(params)
  params.slice(:status, :location, :starts_with)
end

module背后的原因是因为此代码可重复使用,并且可以在应用程序的任何部分使用。

PS:请记住,变量或模型与问题不相同,但解决方案是可以对任何应用程序实施的通用解决方案。

答案 1 :(得分:0)

基于https://stackoverflow.com/a/54401841/3058437,但将public_send替换为where对我来说很有效。 Rails 5

module Filterable
  extend ActiveSupport::Concern

  module ClassMethods
    def filter(filtering_params)
      results = self.where(nil)
      filtering_params.each do |key, value|
        results = results.where("#{key} = ?", value) if value.present?
      end
      results
    end
  end
end