Custom search with ransacker
Asked Answered
D

2

14

I'm trying to add a custom filter to ActiveAdmin which is powered by Ransack these days. Unfortunately, ransacker is not documented at all and from the few resources online I fumbled together the following (in the User model):

ransacker :full_text, formatter: ->(search) {
  ids = User.search_in_all_translated(search).map(&:id)
  ids = ids.any? ? ids : nil
} do |parent|
  parent.table[:id]
end

The search_in_all_translated method returns an array of users which match the search string across all translated attributes.

On the admin page, the following filter is defined:

filter :full_text_in,
  label: 'full text search',
  as: :string

The filter itself works, so filtering tom will list all matching records. However, the value in the filter input switches to ["tom"].

Before applying the filter:

enter image description here

After applying the filter:

enter image description here

Any ideas how to fix this?

Differentiate answered 18/3, 2014 at 7:57 Comment(4)
I may be understanding this incorrectly, but isn't this the expected behaviour? When you are filtering in AA, matching records are displayed on submission and the filter itself gets the value as an input? Maybe you can add a screenshot?Bowden
@Bowden I've added screenshots to the question.Differentiate
You should not be using full_text_in, which basically implies that the search filter will be an array of inputs. I am not sure, but maybe you can try: full_text_eq instead.Bowden
The formatter returns an array of IDs and therefore the "in" predicate is necessary for this to work if there's more than one match. Otherwise, the SQL is invalid: WHERE "users"."id" = 8464, 28139, 13076, 3088.Differentiate
D
21

There's a feature for ransackable scopes waiting to be merged: https://github.com/activerecord-hackery/ransack/pull/288

UPDATE:

I've given the work of avit and glebm another go with PR https://github.com/activerecord-hackery/ransack/pull/390 which has been merged, it's therefore now possible to use scopes with Ransack. For the documentation, see the commit:

https://github.com/svoop/ransack/commit/72dd5d12d58919bf37199234cf13f9533f3b8cd5

Here's a real-life example:

class Project < ActiveRecord::Base
  scope :full_text_search, ->(search) { search_in_all_translated(search) }

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

In this example search_in_all_translated returns some complex indexed full text search SQL.

Differentiate answered 20/6, 2014 at 9:34 Comment(5)
Do you have any sort of documentation for how to use that? With Ransack, I've found a whole lot of wild speculative answers like "use this method" or "write X like Y" but very little by way of example. It's a huge guessing game and nothing ever seems to work properly.Tova
I've added an example.Differentiate
Are you saying that the ransackable scope returns a SQL query string?Iinden
Nevermind, I got it. The methods within ransackable scope are to return an Array of results. You sir have solved the answer to my many hours of searching.Iinden
Anyone here - who can help me in understanding how to define multiple ransackable_scopes? In the same class, I want to have separate definitions say for :full_text_search and :project_name.Umeh
N
0

in or cont_any do a search via an array. So in this case, it's doing a search Model.where(something: ["tom", "tom1", "tom2"] and because of the way the params[:q] works, it returns it to your input as an array. A quick and dirty fix I did to help user experience is added value: nil, to the input form

Nickell answered 17/6, 2014 at 15:47 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.