Last active
July 17, 2017 04:44
-
-
Save dougc84/5fc60eb8a2224d358f88 to your computer and use it in GitHub Desktop.
Ransack - Polymorphic Associations Search Ransacker
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
class MyModel < ActiveRecord::Base | |
belongs_to :owner, polymorphic: true | |
ransacker :owner_name, formatter: proc { |value| | |
# To use this, you have to know what all of the possible owner types can be. | |
# For this example, the #owner_type could be either Group or Advertiser. | |
# The fields we want to search on are: | |
# Group#name | |
# Advertiser#contact_name | |
# | |
# This method does perform one database hit for each related table. | |
# This makes sense considering you are searching on each table's data. | |
# | |
# First, gather the IDs for MyModel where it matches the Advertiser#contact_name. | |
# Using a nested query on the #where conditional for #owner_id eliminates the | |
# need for two queries. | |
# | |
# Second, gather the IDs for MyModel where it matches Group#name. | |
# | |
# Each query will be finished with #pluck, which returns an array - either the IDs, | |
# or an empty array. Each array is joined simply by adding them together. | |
# | |
my_model_ids = MyModel.where( | |
owner_id: Advertiser.select('advertisers.id as owner_id').where('contact_name LIKE ?', "%#{value}%"), | |
owner_type: 'Advertiser' | |
).pluck(:id) + MyModel.where( | |
owner_id: Group.select('groups.id as owner_id').where('name LIKE ?', "%#{value}%"), | |
owner_type: 'Group' | |
).pluck(:id) | |
# Now that there is a list of the appropriate IDs that match the specification, | |
# return the array of IDs as the formatted value for the ransacker. | |
# #presence is provided by ActiveSupport, which basically is shorthand for: | |
# | |
# my_model_ids.any? ? my_model_ids : nil | |
# | |
# If there are no values, it will return nil, which tells Ransack that no | |
# records exist. An empty array may perform other searches unnecessarily. | |
my_model_ids.presence | |
} do |parent| | |
# #parent references the ransacker, and #table references the table for this | |
# model (MyModel). Pass in :id to #table to tell the ransacker the search is | |
# based on the ID field. | |
parent.table[:id] | |
end | |
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
= search_form_for @search do |f| | |
# For this search, the #in predicate needs to be used for Ransack to work properly, | |
# since, based on the implementation of the ransacker, we are finding IDs IN the | |
# current search model. Other predicates expect one singular return value. | |
# | |
# A value needs to manually be specified for the field. If the search is on | |
# "Minnesota", Ransack will output this as "[\"Minnesota\"]" when the page reloads, | |
# since it is an "in" predicate search, and, due to its nature, assumes it is an array | |
# of values. | |
# | |
= f.text_field :owner_name_in, value: params.fetch(:q, {}).fetch(:owner_name_in, nil) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment