Skip to content

Instantly share code, notes, and snippets.

@smoil
Last active March 2, 2020 00:32
Show Gist options
  • Star 22 You must be signed in to star a gist
  • Fork 7 You must be signed in to fork a gist
  • Save smoil/5061616 to your computer and use it in GitHub Desktop.
Save smoil/5061616 to your computer and use it in GitHub Desktop.
Ajax select/multi select in Rails using Select2
class Account < ActiveRecord::Base
def self.search(name = nil)
# search logic
end
end
class AccountsController < ApplicationController
def search
# this returns a hash of search results
records = RecordSearcher.call(Account.by_name, params)
render json: records.to_json, callback: params[:callback]
end
end
# bind to selectors
jQuery ->
account_args =
url: "/accounts/search.json"
options:
placeholder: "Search for an account"
$(".account-select").ajaxSelect(account_args.url, account_args.options)
$(".account-multi-select").ajaxSelect(
account_args.url,
placeholder: account_args.options
multiple: true
)
/ form input for user.stringy_account_ids, note data is set to pre-render exisiting results
= f.label :stringy_account_ids, "Accounts"
= f.hidden_field :stringy_account_ids, class: "account-multi-select", data: { records: f.object.accounts.select(["accounts.id","accounts.name"]) }
# customize options to suit your needs and/or forgo creating a first class jquery function
jQuery.fn.ajaxSelect = (url, options) ->
defaults =
placeholder: "Search for a record"
formatter: (record) ->
record.name
multiple: false
allow_clear: true
settings = $.extend(defaults, options)
this.select2
initSelection: (elm, callback) ->
results = $(elm).data "records"
callback(results)
placeholder: settings.placeholder
allowClear: settings.allow_clear
minimumInputLength: 3
multiple: settings.multiple
ajax:
url: url
dataType: "jsonp"
quietMillis: 100
data: (term, page) ->
query: term
limit: 10
page: page
results: (data, page) ->
more = (page * 10) < data.total
results: data.records
more: more
formatResult: settings.formatter
formatSelection: settings.formatter
# a simple class to generate search results, you can provide a block if you have different data attributes
class RecordSearcher
attr_reader :records
def initialize(records, params = {})
unless records.respond_to? :search
raise ArgumentError, "records must repond to .search"
end
default_params = {
query: nil,
page: nil,
limit: nil
}
params.reverse_merge!(default_params)
@records = records.search(params[:query]).page(params[:page])
.per(params[:limit])
end
def call(&block)
{
total: records.total_count,
records: records.map do |record|
if block_given?
block.call(record)
else
{ name: record.name, id: record.id }
end
end
}
end
def self.call(records, params = {}, &block)
new(records, params).call(&block)
end
end
# invoking in a class will add methods stringy_whatever_ids, and stringy_whatever_ids=
module StringyAssociationIds
def stringy_ids(association)
define_method("stringy_#{association}_ids=") do |comma_seperated_ids|
self.send("#{association}_ids=", comma_seperated_ids.to_s.split(","))
end
define_method("stringy_#{association}_ids") do
send("#{association}_ids").join(",")
end
end
end
ActiveRecord::Base.extend(StringyAssociationIds)
class User < ActiveRecord::Base
has_many :accounts
stringy_ids :account
end
@aniketstiwari
Copy link

Can you make a tutorial on it because it is not self-explanatory

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