Ransack with Nested Attributes
In my app, I track plates which have a number of properties. They also have a location because I need to track where each plate has been. However, for the most part, what I really care about is where the plate is now, its current location. When I do my ransack search on the plates, I want to be able to have some check boxes with the possible locations. So, for example, people could search for all the plates that were annealed at a certain temperature and are located at Chicago. This means I have to search the locations for a given plate, but only for the latest location. I tried a number of different ways to do this in ransack and didn’t have much luck. I got it working how I wanted, but I’m fairly certain that this isn’t the best way to do it.
Basically, I use ransack for the regular search, but then search the results to see which of those plates are in the locations marked.
In my form view
<% Location::LOCATIONS.each do |location| %> <%= check_box_tag 'q[locations][]', location %> <%= location %> <% end %>
This puts a check box for each location that I have stored in my model. Right now we have about 10 locations and I doubt that we’ll get many more.
With that included in my form, I’ll get an array in q that holds my possible locations. So now, I just have to change my results method to check that the current locations in the list of plates and only keep those that are in the array of locations.
def results @q = Plate.search(params[:q]) # Check if have any locations here, if none are checked, don't need to do anything special @locations = params[:q][:locations] if @locations.nil? @plates = @q.result.by_serial_number else @all = @q.result.by_serial_number @hold = Enumerator.new do |y| @all.each do |plate| unless(plate.locations.current_location.last.nil?) if (@locations.include?(plate.locations.current_location.last.location)) y << plate end end end end @plates = @hold.to_a end if @plates.empty? redirect_to compare_path, notice: "No matching plates" else render action: "results" end end
I tried making a virtual attribute (home) in my plate model, but I couldn’t find a way for ransack to search based on that. In fact, I didn’t have much luck finding plates that showed up at a given location at any time, not just the last location. All of my tests kept showing all the plates, so I’m sure that I’m not handling the search of locations correctly. Since each plate has_many locations, it doesn’t work the same as my electroding searches. For electroding, each plate only has one. If I get more time, I’ll look into this more closely and see if I can set up the search properly. But for now, this works just fine.