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?

svoop
  • 3,318
  • 1
  • 23
  • 41
  • 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? – Stoic Mar 18 '14 at 08:22
  • @Stoic I've added screenshots to the question. – svoop Mar 18 '14 at 08:27
  • 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. – Stoic Mar 18 '14 at 08:46
  • 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`. – svoop Mar 18 '14 at 09:50

2 Answers2

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.

svoop
  • 3,318
  • 1
  • 23
  • 41
  • 1
    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. – charredUtensil Jun 30 '14 at 22:25
  • I've added an example. – svoop Jul 04 '14 at 16:29
  • Are you saying that the ransackable scope returns a SQL query string? – 6ft Dan Nov 06 '14 at 02:25
  • 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. – 6ft Dan Nov 06 '14 at 02:29
  • 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. – user1575044 Mar 08 '18 at 10:10
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

Mohamed El Mahallawy
  • 13,024
  • 13
  • 52
  • 84