view raw
Elena Tanasoiu Elena Tanasoiu - 8 months ago 70
Ruby Question

Sending parameter to Ransack from Active Admin filter

I'm trying to make a filter in Active Admin on a customer's first name and last name in one single input field. The first_name and last_name are separate fields.

My solution fails if you have a middle name. If the customer's name is "John H. Smith", then "John" and "Smith" give the correct result, but "John Smith" will not find anything because of the extra 'H.'.

ActiveAdmin.register Customer do
filter :full_name_cont, label: 'Name', as: :string

# In the Customer model:

ransacker :full_name, formatter: proc { |full_name| full_name.downcase.to_s } do |parent|'||','||',
parent.table[:first_name], ' '

So now I'm trying to send the search term "John H. Smith" as a parameter to ransacker, so I can split the name up into multiple parts and search if any of them match first name or last name:

ransacker :full_name, args: [:parent, :ransacker_args] do |parent, args|
full_name = args.first
search_items = full_name.split(" ")
condition = "concat_ws(first_name, ' ', last_name) LIKE '%#{search_items.first}%'"
search_items.each do |item|
condition += " OR concat_ws(first_name, ' ', last_name) LIKE '%#{item}%'" if item != search_items.first

Unfortunately, args is always empty.

Does anyone know how to send parameters to ransacker?


The solution for this was to create a new Ransack predicate that considers spaces as wildcards.

The idea was also presented in this issue: Make an OR with ransack

# In config/initializers/ransack.rb

Ransack.configure do |config|
  config.add_predicate 'contains',
         :arel_predicate => 'matches', # so we can use the SQL wildcard "%"
         # Format the incoming value: add the SQL wildcard character "%" to the beginning and the end of
         # the string, replace spaces by "%", and replace multiple occurrences of "%" by a single "%".
         # For using * and ? instead as wild cards use this #{Ransack::Constants.escape_wildcards(v).gsub("*", "%").gsub('?','_')}
         :formatter => proc {|v| ("%#{v.gsub(" ", "%")}%").squeeze("%")}

And then in the model I used this ransack code from the examples in

# ActiveAdmin - customers.rb
# I re-open the model 
class Customer
  ransacker :full_name do |parent|'||',
              parent.table[:first_name], ' '),

ActiveAdmin.register Customer do