Activeadmin:如何过滤匹配两个或多个搜索词的字符串

Activeadmin: how to filter for strings that match two or more search terms

假设我的用户 class 有一个 :email 字段。假设我正在使用 activeadmin 来管理用户。

制作一个过滤器 returns 匹配一个字符串的电子邮件,例如"smith",很简单。在 admin/user.rb 中,我只包含行

filter :email 

这给了我一个过滤器小部件来完成这项工作。

但是,此过滤器不允许我搜索多个术语的交集。我可以搜索包含 "smith" 的电子邮件,但不能搜索同时包含 "smith" 和“.edu”的电子邮件。

Google 告诉我 activerecord 使用 Ransack under the hood, and the Ransack demo 有一个 'advanced' 模式允许多个词搜索。

将多词搜索小部件放入 activeadmin 的最简单方法是什么?

理想情况下,我想要一个允许我输入 smith .edusmith AND .edu 以过滤包含这两个术语的电子邮件的小部件。

只需向您的模型添加三个过滤器:

filter :email_cont
filter :email_start
filter :email_end

它为您提供了一种灵活的方式来管理您的搜索。

此过滤器执行下一个 sql 代码:

SELECT  "admin_users".* FROM "admin_users"
WHERE ("admin_users"."email" ILIKE '%smith%' AND 
       "admin_users"."email" ILIKE '%\.edu')
ORDER BY "admin_users"."id" desc LIMIT 30 OFFSET 0

我希望这正是您要找的。

我找到了一个解决方案,但它并不完美。

好消息是 Ransack 可以轻松进行多词搜索。这些搜索使用 'predicate' cont_all。以下行用于查找包含 'smith' 和 '.edu'.

的电子邮件
User.ransack(email_cont_all: ['smith','.edu'] ).result

由于这些搜索在 Ransack 中很容易,因此在 Activeadmin 中可能也很简单,对吧?错误的!为了让它们正常工作,我需要做三件事。

  1. 我把一个自定义的搜索方法(a.k.a。ransacker)放到了User.rb。我将劫掠者命名为 email_multiple_terms

    class User < ActiveRecord::Base
    
    # ...
    
    ransacker :email_multiple_terms do |parent|
      parent.table[:path]
    end
    
  2. 我在我的 activeadmin 仪表板中声明了一个过滤器,并将其与劫掠者相关联。请注意,搜索谓词 cont_all 附加到劫掠者名称。

admin/User.rb:

ActiveAdmin.register User do

# ...

filter :email_multiple_terms_cont_all, label: "Email", as: :string 

此行在 Activeadmin 中创建过滤器小部件。我们快到了。剩下的一个问题:Activeadmin 将搜索查询作为单个字符串(例如 "smith .edu")发送给搜查,而我们的搜查者希望将搜索词作为一个数组。在某处,我们需要将单个字符串转换为搜索词数组。

  1. 我修改了 activeadmin 以在特定条件下拆分搜索字符串。逻辑在我添加到 lib/active_admin/resource_controller/data_access.rb.

    的方法中
    def split_search_params(params)
      params.keys.each do |key|
        if key.ends_with? "_any" or key.ends_with? "_all"
          params[key] = params[key].split  # turn into array
        end
      end
      params
    end
    

然后我在apply_filtering里面调用了这个方法。

    def apply_filtering(chain)
      @search = chain.ransack split_search_params clean_search_params params[:q]
      @search.result
    end

此代码存在于我自己的 activeadmin 分支中,此处:https://github.com/d-H-/activeadmin

因此,要进行多词搜索,请按照上面的步骤 1 和 2 进行操作,并包括我的 A.A 分支。在你的 Gemfile 中:

  gem 'activeadmin', :git => 'git://github.com/d-H-/activeadmin.git'

HTH.

如果谁有更简单的方法,请分享!

有一个使用 ranasckable 范围的简单解决方案

所以在你的模型中加入这样的东西

class User < ActiveRecord::Base
    ....
    scope :email_includes, ->(search) {
       current_scope = self
       search.split.uniq.each do |word|
         current_scope = current_scope.where('user.email ILIKE ?', "%#{word}%")  
       end
       current_scope
    }

    def self.ransackable_scopes(auth_object = nil)
      [ :email_includes]
    end
end

之后您可以使用 AA DSL 添加过滤器

喜欢

  filter :email_includes, as: :string, label: "Email"

UPD

如果将 email_contains_any 更改为 email_includes

应该可以工作