Ransack: Documentation for Ransacker

Created on 18 Mar 2014  路  19Comments  路  Source: activerecord-hackery/ransack

The Ransacker class is IMHO a crutial part of Ransack, however, due to the lack of documentation and examples, it's both a time consuming and frustrating task to work with Ransacker. Fortunately, not too many people had to deal with them so far.

This is going to change because ActiveAdmin (master branch) has switched from meta_search to Ransack. This means all existing Rails 3.2 applications with ActiveAdmin backend must port their custom filters to Ransack in order to update to Rails 4. The old approach with scopes/search_method is no longer possible... enter Ransacker.

It would be very helpful to have some documentation and examples for Ransacker. I'd even throw in a few bucks, say $50 or so. Anybody else willing to tip as well?


To illustrate, here's an example from a real application. First the Rails 3.2 code which uses meta_search. The search_in_all_translated method searches all attributes which hold translations in a Postgres HSTORE structure. ActiveAdmin uses Formtastic to render forms:

# app/models/user.rb
scope :full_text_contains, ->(search) { search_in_all_translated(search) }
search_method :full_text_contains

# app/admin/users.rb (ActiveAdmin)
filter :full_text_contains,
  label: 'full text search'

And here the port to Ransacker ready for Rails 4:

# app/models/user.rb
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

# app/admin/users.rb (ActiveAdmin)
filter :full_text_in,
  label: 'full text search',
  as: :string

The search itself works, but the value in the search form input is not correct after the search as described on Stackoverflow:

Before:

dhuok

After:

o53uy

Looking at "my" Ransacker, it feels wrong, ill-used. But without documentation and maybe some examples, I'm lost - and apparently, I'm not the only one.

All 19 comments

Hi @svoop I agree that ransackers need to be better documented and definitely welcome pull requests from the community.

I rely on Ransack for search in my Ruby/Rails apps but don't use ransackers that much anymore. Nowadays I've replaced them with indexed database search fields instead (as I've described several times on other issues here) because they are faster and scale better. From what I see, a fair number of use cases that users try to solve with ransackers could be better solved differently. I still use one or two simple ransackers for converting user query strings to dates like below but that's about it.

app/models/event.rb

  ransacker :event_date_casted do |parent|
    Arel::Nodes::SqlLiteral.new("date(events.date)")
  end

app/views/events/_search.erb

<%= f.search_field :event_date_casted_date_equals, placeholder: t(:date_format) %>

config/initializers/ransack.rb

Ransack.configure do |config|
  config.add_predicate 'date_equals',
    arel_predicate: 'eq',
    formatter: proc { |v| process_date(v).to_date },
    validator: proc { |v| v.present? },
    compounds: true,
    type: :string
end

Personally my priority for Ransack when I get time will be to bring Rails 4.1 compatibility into master in time for the upcoming 4.1 general release (in the meantime, the Ransack "rails-4.1" branch is currently working fine for 4.1 and 4.2.0alpha).

Hello @jonatack

I'm not sure "the community" understands the Ransackers enough to contribute documentation, I certainly don't :smile: Maybe the authors could do the first step? Just looking at your example, I have no real clue how to read and understand it.

I agree, indexed search fields are faster and more scalable, I use them approach in the frontend. But speed is not an issue for the backend filters since they are rarely used and I don't want to bloat the database schema for every funky filter my backend users use once every couple of months.

The entire premise behind ransack is to provide access to Arel predicate methods. A ransacker can return any Arel node that allows the usual predicate methods. It's as easy as that. The difficulty folks are having is not in using Ransack so much as understanding Arel, it seems to me.

@ernie You're right, at least as far as I'm concerned. In fact, I'm inhaling the Arel documentation right now. But this doesn't explain e.g. what parent refers to. (In my example above parent is ActiveRecord::Associations::JoinDependency::JoinBase... ehm?)

@svoop what Ernie said :)

I updated my example in more detail, if that helps.

Thank you for your explanations and examples, I finally somewhat wrapped my mind around ransackers and could replace my old search_method incarnations ...

... but one: the fulltext search from the illustration example above.

The search_in_all_translated(search) builds a complex fulltext query on PostgreSQL hstore attibutes such as:

User.search_in_all_translated('foobar').to_sql
# => SELECT "users".* 
       FROM "users"  
       WHERE (
         TO_TSVECTOR('german', description -> 'de') @@ PLAINTO_TSQUERY('german', 'foobar') OR 
         TO_TSVECTOR('french', description -> 'fr') @@ PLAINTO_TSQUERY('french', 'foobar') OR 
         TO_TSVECTOR('english', description -> 'en') @@ PLAINTO_TSQUERY('english', 'foobar')
       )

The ransacker is not really useful here, but neither is IMHO an "indexed database search field" because PostgreSQL's tsvector syntax dosn't use a predicate known to Ransack. And I have to use Ransack since ActiveAdmin doesn't give me a choice here.

Can this be done at all without monkey patching Ransack?

Hi @svoop yes, PostgreSQL is getting pretty capable at fulltext search and it's great to see. You might be able to patch Ransack, and please share if you do make it work. Having said that, I wouldn't use ActiveAdmin or Ransack for this. I'd roll my own admin backend, use ransack for what it does well, and code a seperate query for the fulltext search. These aren't necessarily "one-size fits all" tools (and I wouldn't want to be overly dependant on them if they were). Cheers.

@jonatack I don't have much of a choice here, the project is using AA for the entire backend and in order to update the app to Rails 4, I must switch to Ransack. And there are many others who find themselves in a similar catch-22. The solution IMHO is for Ransack to support scopes to harness the power of more elaborate database backends. I try to get a patch based on #288 to work with AA, but it's not yet working properly.

Solution: stop using Active Admin. Seriously! AA is only good for VERY BASIC admin backends. If you want something more complex, you're better off building it yourself. Same goes for Devise and authentication.

If it's stopping you from doing what you want to do then that's a BAD thing and you should probably build the admin backend yourself as per @jonatack's and my suggestions.

It's Ransack that's the problem in this case. I moved Active Admin from Metasearch to Ransack in order to support Rails 4, but Ransack doesn't support scopes when Metasearch did. That understandably puts people in a difficult situation, when their existing applications depend on complex scopes. Suggesting that someone stop using a gem because its dependency dropped what many consider a core feature isn't very nice :stuck_out_tongue:

I am in the business of keeping Ransack light and powerful. I am not in the business of moulding it to the madness that is Active Admin. I know that's not a nice opinion to have. There are many like it, but this one is mine.

We are aware that people want Ransack to support scopes. Some of the _oldest issues_ in Ransack are about its lack for scopes. If it were easy to do, we would do it. It _appears_ that it is not easy to do, and so it has not been done.

@svoop Can you share with me an application that reproduces this issue?

I agree with @radar. Depending on a gem for complex or mission-critical parts of an application is a warning flag to me and something that I reckon will come back to bite me if I don't understand what is going on in the gem well enough to patch it or fix problems.

If scopes support instead of ransackers was an insurmountable pain point for the good people who take the time to submit working pull requests, I suppose it would be done by now. Some of them have come close. It would be great if someone who really needs scopes support could dig into the current PRs and contribute.

@jonatack It's in the making, see #288. Not everybody has enough insight to contribute.

@radar Will do so this afternoon.

It's not my decision whether to replace AA or not. And the decision made is: not. So I have to be pragmatic here - whether I like it or not.

@radar

I've created a simple lab app. It has two branches:

  • "master" uses the vanilla ransack 1.1.0 and is thus not working.
  • "search_scopes" is based on the search_scopes branch of glebm/ransack which includes the incomplete implementation of search scopes by @avit as of #288. This works.

https://github.com/svoop/ransack_scopes_lab

The scope does as simple LIKE which of course ransack could do out of the box. The real use case is a more complex scope e.g. using PostgreSQL full text search.

@seanlinsley I've forked meta_search and fixed its problems with rails 4. So if you want to have worked scopes now you may use my fork of meta_search.

Wow. So much good information in this thread. @ernie is right. Now that I think about it, most of the problems I've encountered w/ Ransack were a result of my lack of understanding Arel. I imagine most of the active issues on the project are probably similar. I probably check every month to see if there's something I can contribute to on the project and that lack of understanding bites me every time.

While we're on the subject of documentation though, @radar, is there a list somewhere of things that DO need to be more thoroughly documented in the project? If so I'd like to help.

I started a "Using Ransackers" section in the wiki here:

https://github.com/activerecord-hackery/ransack/wiki/Using-Ransackers

If anyone would like to add code examples to it or improve it, that would be great.

Thanks, @jonatack!

Was this page helpful?
0 / 5 - 0 ratings