【问题标题】:Rails searching with multiple conditions (if values are not empty)Rails 搜索多个条件(如果值不为空)
【发布时间】:2012-03-07 16:56:30
【问题描述】:

假设我有一个模型Book,其字段为word_count,可能还有许多其他类似的字段。

对我来说,在数据库的“高级搜索”中将条件串在一起的好方法是什么?在上面的示例中,我有一个带有“word count between ___ and ___”框的搜索表单。如果用户填写第一个框,那么我想返回所有字数大于该值的书籍;同样,如果用户填写第二个框,那么我想返回所有字数少于该值的书籍。如果两个值都填写,那么我想返回该范围内的字数。

如果我这样做,显然

Book.where(:word_count => <first value>..<second value>)

如果只填写一个字段,这将中断。有什么方法可以优雅地处理这个问题?请记住,可能有许多相似的搜索条件,所以我不想为每个可能的组合构建单独的查询。

抱歉,如果之前有人问过这个问题,但搜索该网站尚未产生任何有用的结果。

【问题讨论】:

    标签: ruby-on-rails activerecord


    【解决方案1】:

    怎么样:

    @books = Book
    @books = @books.where("word_count >= ?", values[0]) if values[0].present?
    @books = @books.where("word_count <= ?", values[1]) if values[1].present?
    

    ActiveRecord 将链接 where 子句

    唯一的问题是,如果 values[0] && values[1] 如果 values[0] 大于 values[1],查询将不会返回任何内容。

    【讨论】:

      【解决方案2】:

      对于我们的高级搜索,我们创建了一个过滤器对象,它将活动记录查询封装成简单的方法。原来是基于这个Thoughtbot post

      图书过滤器可能如下所示:

      class BookFilter
        def initialize
          @relation = Book.scoped
        end
      
        def restrict(r)
          minimum_word_count!(r[:first]) if r[:first].present?
          maximum_word_count!(r[:second]) if r[:second].present?
          recent! if r.try(:[], :recent) == '1'
          @relation
        end
      
        protected
      
        def recent!
          where('created_at > ? ', 1.week.ago)
        end
      
        def minimum_word_count!(count)
          where('word_count >= ? ', count)
        end
      
        def maximum_word_count!(count)
          where('word_count <= ?', count)
        end
      
        def where(*a)
          @relation = @relation.where(*a)
        end
      end
      
      #to use
      books = BookFilter.new.restrict(params)
      

      【讨论】:

      • 我有点喜欢这里的发展方向。不过,我该把这门课放在哪里呢?
      • 我们将它们放入app/models。您可以将它们命名为 Filters 并将它们放在 lib/filters 文件夹中
      【解决方案3】:

      看看ransack gem,它是meta_search gem 的继承者,似乎仍然有更好的文档。

      如果您确实想自己动手,没有什么能阻止您使用相同的属性链接子句:

      scope = Book
      scope = scope.where("word_count >= ?", params[:first]) if params[:first]
      scope = scope.where("word_count <= ?", params[:last])  if params[:last]
      

      但实际上没有必要自己进行搜索,上面有很多现成的解决方案。

      【讨论】:

        猜你喜欢
        • 2021-12-29
        • 2016-12-02
        • 1970-01-01
        • 1970-01-01
        • 2021-11-04
        • 2017-04-23
        • 1970-01-01
        • 2014-05-15
        • 1970-01-01
        相关资源
        最近更新 更多