Ransack: How to use ransacker?

Created on 25 Oct 2011  路  16Comments  路  Source: activerecord-hackery/ransack

I've got an ActiveRecord model with a scope and a ransacker defined like this:

  scope :by_country_state, lambda {|state|
    ddds = City.where(:country_state => state).map{|city| city.ddd}.uniq!
    where(:ddd => ddds)
  }
  ransacker :by_country_state

If I try to add f.text_field :by_country_state on the view, when I search I get ArgumentError (No valid predicate for by_country_state), if I try to add f.text_field :by_country_state_eq, I get:

TypeError (Cannot visit ActiveRecord::Associations::JoinDependency::JoinBase):
  app/models/telephone.rb:8:in `block in <class:Telephone>' 

Line 8 is the second line on my former blockquote.

I'm following this behavior from meta_search search_methods, so I might be taking the wrong approach, but I couldn't figure it out from the specs or the code. Could you help me, please?

Most helpful comment

Since this issue is supposed to be the documentation of ransackers, here are some things left unclear:

  • What options do ransackers support (like that formatter)?
  • What happens with the block of a ransacker?
  • What is this parent that is yeilded into the block?
  • Can other things be yielded there somehow?
  • What is a ransacker conceptually, how should I think about it (because at the moment I'm confused)?

All 16 comments

Got working this way:

  ransacker :by_country_state, formatter: proc { |v|
    City.where(country_state: v).map{ |city| city.ddd }.uniq
    }, splat_param: true do |parent|
    parent.table[:ddd]
  end

Hey @lunks, since there is zero documentation for ransackers, would you be kind enough to explain what the heck your code is doing? What is v, where does it go, what is a formatter, what happens inside the block, etc etc etc. I really appreciate your help understanding what's going on here. Thanks!

Sure, let me refactor it a little bit so it is more clearer:

  ransacker :by_state, formatter: proc { |current_state|
    City.where(state: current_state).map{ |city| city.area_code}.uniq
    }, splat_param: true do |parent|
    parent.table[:area_code]
  end

What I'm basically doing is picking a State out of a drop down. Once one is selected, I use it to find all cities which are contained in that given state, find out their area codes, and use it to filter my current model (in this case, Call).

TL;DR
Given a state, find me all calls within that area, using its cities area codes.

Is that clearer?

Ok so, the ransacker takes the value that is dropped into your formatter proc, current_state, and then turns that into an array of unique area codes.

The rest confuses me still: splat param means multiple area codes will be used in a search?

And, how do the area codes end up in the block? That's what really is confusing me... I see you're telling the ransacker you want to search the area_code column on the parent table, but how does it know what you want to search for?

Not sure about splat_params. Perhaps it worked without it? I don't have access to the codebase anymore.

The ransacker creates something like a virtual attribute: I can then use f.text_field :by_state_in field and everything will work magically.

Yeah, the problem I'm having is a more complex query than just matching a string. If you don't mind, can you take a look here: https://github.com/ernie/ransack/issues/164

I've been working on this for days, and it feels like voodoo.

By the way, thank you so very much for responding to my cry for help here, it has been a nightmare trying to get answers to how this works, and unfortunately there isn't much documentation.

Not a problem at all. I've commented on it and ping the original repo owner. I'm not sure he's working on it and actively supporting it, though. Good luck!

Hey guys, is there a way to add sql HAVING with ransacker?

Since this issue is supposed to be the documentation of ransackers, here are some things left unclear:

  • What options do ransackers support (like that formatter)?
  • What happens with the block of a ransacker?
  • What is this parent that is yeilded into the block?
  • Can other things be yielded there somehow?
  • What is a ransacker conceptually, how should I think about it (because at the moment I'm confused)?

+1 on some actual documentation here

Probably, my notes on this topic may help somebody, in future:
Custom Filters using ransacker in ActiveAdmin interfaces

Why is it so hard just to use a scope? I very much identify with this: https://github.com/activerecord-hackery/ransack/issues/164#issuecomment-19613313

Looks like it's now possible out of the box: https://github.com/activerecord-hackery/ransack/commit/72dd5d12d58919bf37199234cf13f9533f3b8cd5

Just tried - works perfectly. Upgraded from meta_search without any issues.

Just update to latest master: gem 'ransack', github: 'activerecord-hackery/ransack'

Hi..

This doesn't work

ransacker :by_items, formatter: proc { |v|
   Item.all
    }, splat_param: true do |parent|
    parent.table[:id]
  end

but this works

ransacker(:by_items, formatter: proc { |v|
     Item.all.map("Depending what you want to filter with v").map(&:id)
  }, splat_param:true )do |parent|
    parent.table[:id]
  end

The parrent.table[:id] is to render the Item that you filter with id. If you dont give an id, it will render an empty page.

Was this page helpful?
0 / 5 - 0 ratings