Documentation for Ransacker #345

Closed
svoop opened this Issue Mar 18, 2014 · 19 comments

Comments

Projects
None yet
7 participants
@svoop
Contributor

svoop commented Mar 18, 2014

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.

@jonatack

This comment has been minimized.

Show comment
Hide comment
@jonatack

jonatack Mar 18, 2014

Member

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).

Member

jonatack commented Mar 18, 2014

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).

@svoop

This comment has been minimized.

Show comment
Hide comment
@svoop

svoop Mar 18, 2014

Contributor

Hello @jonatack

I'm not sure "the community" understands the Ransackers enough to contribute documentation, I certainly don't 😄 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.

Contributor

svoop commented Mar 18, 2014

Hello @jonatack

I'm not sure "the community" understands the Ransackers enough to contribute documentation, I certainly don't 😄 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.

@ernie

This comment has been minimized.

Show comment
Hide comment
@ernie

ernie Mar 18, 2014

Member

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.

Member

ernie commented Mar 18, 2014

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.

@svoop

This comment has been minimized.

Show comment
Hide comment
@svoop

svoop Mar 18, 2014

Contributor

@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?)

Contributor

svoop commented Mar 18, 2014

@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?)

@jonatack

This comment has been minimized.

Show comment
Hide comment
@jonatack

jonatack Mar 18, 2014

Member

@svoop what Ernie said :)

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

Member

jonatack commented Mar 18, 2014

@svoop what Ernie said :)

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

@svoop

This comment has been minimized.

Show comment
Hide comment
@svoop

svoop Mar 27, 2014

Contributor

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?

Contributor

svoop commented Mar 27, 2014

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?

@jonatack

This comment has been minimized.

Show comment
Hide comment
@jonatack

jonatack Mar 29, 2014

Member

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.

Member

jonatack commented Mar 29, 2014

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.

@svoop

This comment has been minimized.

Show comment
Hide comment
@svoop

svoop Mar 30, 2014

Contributor

@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.

Contributor

svoop commented Mar 30, 2014

@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.

@radar

This comment has been minimized.

Show comment
Hide comment
@radar

radar Mar 30, 2014

Member

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.

Member

radar commented Mar 30, 2014

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.

@seanlinsley

This comment has been minimized.

Show comment
Hide comment
@seanlinsley

seanlinsley Mar 30, 2014

Contributor

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 😛

Contributor

seanlinsley commented Mar 30, 2014

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 😛

@radar

This comment has been minimized.

Show comment
Hide comment
@radar

radar Mar 30, 2014

Member

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.

Member

radar commented Mar 30, 2014

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.

@radar

This comment has been minimized.

Show comment
Hide comment
@radar

radar Mar 30, 2014

Member

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

Member

radar commented Mar 30, 2014

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

@jonatack

This comment has been minimized.

Show comment
Hide comment
@jonatack

jonatack Mar 31, 2014

Member

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.

Member

jonatack commented Mar 31, 2014

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.

@svoop

This comment has been minimized.

Show comment
Hide comment
@svoop

svoop Mar 31, 2014

Contributor

@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.

Contributor

svoop commented Mar 31, 2014

@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.

@svoop

This comment has been minimized.

Show comment
Hide comment
@svoop

svoop Mar 31, 2014

Contributor

@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.

Contributor

svoop commented Mar 31, 2014

@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.

@ka8725

This comment has been minimized.

Show comment
Hide comment
@ka8725

ka8725 Apr 16, 2014

@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.

ka8725 commented Apr 16, 2014

@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.

@qpowell

This comment has been minimized.

Show comment
Hide comment
@qpowell

qpowell Apr 28, 2014

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.

qpowell commented Apr 28, 2014

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.

@jonatack

This comment has been minimized.

Show comment
Hide comment
@jonatack

jonatack May 1, 2014

Member

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.

Member

jonatack commented May 1, 2014

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.

@jonatack jonatack closed this May 1, 2014

@svoop

This comment has been minimized.

Show comment
Hide comment
@svoop

svoop May 5, 2014

Contributor

Thanks, @jonatack!

Contributor

svoop commented May 5, 2014

Thanks, @jonatack!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment