简体   繁体   中英

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

Let's say I've got User class with an :email field. And let's say I'm using activeadmin to manage Users.

Making a filter that returns emails that match one string, eg "smith", is very simple. In admin/user.rb , I just include the line

filter :email 

This gives me a filter widget that does the job.

However, this filter doesn't let me search for the intersection of multiple terms. I can search for emails containing "smith", but not for emails containing both "smith" AND ".edu".

Google tells me that activerecord uses Ransack under the hood, and the Ransack demo has an 'advanced' mode that permits multiple term searches.

What's the easiest way to get a multiple term search widget into activeadmin?

Ideally, I'd like a widget that would allow me to enter smith .edu or smith AND .edu to filter for emails containing both terms.

there is simple solution using ranasckable scopes

So put something like this in your model

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

After this you can add filter with AA DSL

Like

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

UPD

should work if change email_contains_any to email_includes

I've figured out a solution but it's not pretty.

The good news is that Ransack has no trouble with multiple terms searches. These searches use the 'predicate' cont_all . The following line works for finding emails containing 'smith' and '.edu'.

User.ransack(email_cont_all: ['smith','.edu'] ).result

Since these searches are easy in Ransack, they're probably straightforward in Activeadmin, right? Wrong! To get them working, I needed to do three things.

  1. I put a custom ransack method (aka ransacker ) into User.rb . I named the ransacker email_multiple_terms .

     class User < ActiveRecord::Base # ... ransacker :email_multiple_terms do |parent| parent.table[:path] end 
  2. I declared a filter in my activeadmin dashboard, and associated it with the ransacker. Note that the search predicate cont_all is appended to the ransacker name.

admin/User.rb :

ActiveAdmin.register User do

# ...

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

This line creates the filter widget in Activeadmin. We're nearly there. One problem left: Activeadmin sends search queries to ransack as a single string (eg "smith .edu" ), whereas our ransacker wants the search terms as an array. Somewhere, we need to convert the single string into an array of search terms.

  1. I modified activeadmin to split the search string under certain conditions. The logic is in a method that I added to 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 

I then called this method inside apply_filtering .

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

This code is live in my own fork of activeadmin, here: https://github.com/dH-/activeadmin

So, to get multiple term search working, follow steps 1 and 2 above, and include my fork of AA in your Gemfile:

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

HTH.

If anyone's got a simpler method, please share!

Just add three filters to your model:

filter :email_cont
filter :email_start
filter :email_end

It gives you a flexible way to manage your search.

在此输入图像描述

This filter executes next sql code:

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

I expect that exactly what you're looking for.

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