Sejak memasang "dark" theme, saya cenderung menjadi malas menulis. Untuk sementara, dark theme saya disable dulu yaa. Terima kasih (^_^) (bandithijo, 2024/09/15) ●
Prerequisite
Ruby 2.6.3
Rails 5.2.3
PostgreSQL 11.5
Prakata
Pada artikel sebelumnya, “Membuat Tab Filter by Category dengan Ransack pada Rails”, saya sudah pernah membahas mengenai Ransack gem. Namun, bukan dimanfaatkan untuk pencarian, melainkan untuk mengakali dalam membuat fungsi tab yang akan menghasilkan index list yang sudah difilter berdasarkan hasil dari field tertentu. Wkwkwk.
Nah, kali ini saya akan menuliskan catatan yang memanfaatkan Ransack gem dengan benar (mungkin). (^_^)
Yaitu, membuat fitur pencarian yang diimplementasikan pada text_field
dan akan menampilkan autocomplete suggestion dari populasi data dari suatu field.
Misal, dalam project yang saya kerjakan adalah field location dan nama dari experience. Jadi, autocomplete suggestion nya akan menampilkan data dari 2 field. Atau mungkin bisa disebut autocomplete suggestion based on category.
Kira-kira, hasilnya akan seperti ini.
Nah, pada implementasi fitur ini, saya menggunakan bantuan JQuery plugin yang bernama EasyAutocomplete. Saya menggunakan tipe categories.
Instalasi
Ransack
Proses instalasi Ransack gem, sama seperti gem-gem pada umumnya. Gabungkan dengan formasi gem yang teman-teman miliki di Gemfile
.
1
2
3
4
5
# ...
# ...
# ...
gem 'ransack', '~> 2.3'
Jangan lupa untuk diinstall.
$ bundle install
Setelah selesai, selanjutnya saya akan memasang EasyAutocomplete JQuery plugin.
EasyAutocomplete
Proses instalasi ini ada banyak varian, namun untuk catatan kali ini, saya memilih untuk memasang secara manual.
Download langsung dari EasyAutocomplete official website, di sini.
Versi yang paling up-to-date pada saat catatan ini dibuat adalah EasyAutocomplete 1.3.5.
Hasil dari download ini berupa file terkompresi EasyAutocomplete-1.3.5.zip.
Kalau kita buka, akan seperti ini.
EasyAutocomplete-1.3.5/
├─ easy-autocomplete.css
├─ easy-autocomplete.min.css
├─ easy-autocomplete.themes.css
├─ easy-autocomplete.themes.min.css
├─ jquery.easy-autocomplete.js
├─ jquery.easy-autocomplete.min.js
└─ maps/
Nah, tinggal saya distribusikan ke dalam Rails project. Tapi tentu saja tidak semua.
Gunakan yang diperlukan saja.
Saya memilih,
easy-autocomplete.css
jquery.easy-autocomplete.js
Kemudian saya distribusikan ke dalam direktori vendor/
yang ada di Rails project saya.
.
├─ app/
├─ bin/
├─ config/
├─ db/
├─ lib/
├─ log/
├─ node_modules/
├─ public/
├─ storage/
├─ test/
├─ tmp/
├─ vendor/
│ └─ assets/
│ ├─ javascripts/
│ │ └─ easy-autocomplete.css
│ └─ stylesheets/
│ └─ jquery.easy-autocomplete.js
├─ config.ru
├─ Gemfile
├─ Gemfile.lock
├─ package.json
├─ Rakefile
└─ README.md
Nah, setelah file javascript dan stylesheet tersebut saya distribusikan, saya dapat mulai mengimplementasikan fungsi pencarian dengan menggunakan Ransack.
Saya akan mulai dari controller.
Controller
Karena saya akan menampilkan hasil dari pencarian pada halaman experience index. Maka, saya akan membuat pemanggilan object pada Experiences controller.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
class ExperiencesController < ApplicationController
def index
# Default for Ransack
@search = Experience.search(params[:search], params[:q])
@experiences = @search.result(distinct: true).page(params[:page]).per(10)
# For Autocomplete Suggestion in Search Feature
@experience_locations = Experience.ransack(location_cont: params[:q]).result(distinct: true).select('experiences.location')
@experience_names = Experience.ransack(name_cont: params[:q]).result(distinct: true)
respond_to do |format|
format.html {}
format.json {
@experience_locations = @experience_locations
@experience_names = @experience_names
}
end
end
def show
@experience = Experience.friendly.find(params[:id])
end
end
Terlihat pada action :index
, saya membuat dua buah instance variable yang bernama @experience_locations
dan @experience_names
yang kemudian saya masukkan ke dalam blok respond_to
untuk ditampilkan dalam format JSON.
Populasi data dalam format JSON inilah yang nantinya akan digunakan oleh EasyAutocomplete dalam menampilkan autocomplete suggestion data.
Selanjutnya, saya akan membuat script dengan Javascript untuk menghandle dimana data akan ditampilkan pada view template serta format tampilannya akan seperti apa.
Saya akan membuat file topsearch.js
pada directory app/assets/javascripts/
.
Dan menambahkannya pada app/assets/javascripts/application.js
.
1
2
3
4
5
// ...
// ...
// ...
//= require topsearch
Kenapa saya namakan topsearch
karena feature ini diletakkan pada navigation bar yang posisinya ada di bagian atas, dan akan digunakan di setiap halaman pada web aplikasi.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
document.addEventListener("turbolinks:load", function() {
$input = $("[data-behavior='autocomplete']")
var options = {
getValue: "name",
url: function(phrase) {
return "/experiences.json?q=" + phrase;
},
categories: [
{
listLocation: "experience_locations",
header: "<i class='icon-location'></i> Locations",
},
{
listLocation: "experience_names",
header: "<i class='icon-map'></i> Experiences",
},
],
list: {
onChooseEvent: function() {
var name = $input.getSelectedItemData().name
$input.val(name).ready(function() {
document.getElementById("search").focus()
})
}
},
theme: "bandithijo-plate"
}
$input.easyAutocomplete(options)
});
Sebenarnya, saya tidak benar-benar mengerti tentang Javascript. Tapi saya yakin, teman-teman lebih mengerti daripada saya.
Bisa teman-teman perhatikan di atas.
Saya membuat variable options
yang berisi,
Variable $input
berisi variable $("[data-behavior='autocomplete']")
.
data-behavior
adalah properties pada view template yang akan saya tambahkan pada text input berupa search_field_tag
.
listLocation:
berisi "experience_locations"
dan "experience_names"
yang berasal dari instance variable yang saya buat sebelumnya pada experiences controller.
header:
berisi title dari category. Dalam kasus saya, “Locations” dan “Experiences”. Saya dapat pula menuliskan dalam html form, misal menambahkan bootstrap icon seperti ilustrasi pada Gambar 1 dan Gambar 2.
theme:
adalah tema dari stylesheet yang dapat saya pilih apabila teman-teman menambahkan file easy-autocomplete.themes.css
pada direktori vendor/assets/stylesheets/
. Namun, dalam hal ini, saya meng-custom sendiri tema yang saya pergunakan dan saya beri nama bandithijo-plate
. Saya modifikasi dari tema bawaan EasyAutocomplete yang bernama “easy-autocomplete.eac-plate” yang ada di dalam file easy-autocomplete.theme.css
.
Kemudian tinggal saya panggil dengan $input.easyAutocomplete(options)
.
Sekarang saya buat form pencariannya di view template.
View
Form pencarian yang saya mau, bukan hanya terletak pada halaman tertentu. Melainkan, pada navigation bar. Yang artinya, dapat saya gunakan pada setiap halaman.
Nah, karena saya menggunakan Bootstrap Navigation Bar, pasti sudah paham, kalau ada contoh template yang menyediakan input field untuk pencarian. Tinggal dimodifikasi saja sesuai dengan sintaks ERB.
Class pada contoh di bawah, hanya ilustrasi yaa.
1
2
3
4
5
6
7
8
9
...
...
<%= form_tag experiences_path, local: true, method: :get, class: "form-group" do %>
<%= search_field_tag :search, params[:search] || nil, class: "form-control", placeholder: "Where are you going?", data: {behavior: "autocomplete"} %>
<% end %>
...
...
Form pencarian di atas, akan dialamatkan ke experiences index, maka dari itu target alamatnya adalah experiences_path
.
Menggunakan search_field_tag
dari Ransack, dengan params[:search]
yang akan di-passing ke experiences controller.
Kemudian, properties data: {behavior: "autocomplete"}
adalah lokasi dari EasyAutocomplete akan menampilkan autocomplete suggestion yang sudah saya defisinikan pada topsearch.js
sebelumnya, data-behavior="autocomplete"
Untuk mengambil nilai JSON yang sudah saya buat pada controller, saya menggunakan JSON Builder.
Kemudian, saya membuat file bernama index.json.jbuilder
pada app/view/experiences/
, berdampingan dengan index.html.erb
pada view template dari experiences.
Isinya seperti ini.
1
2
3
4
5
6
7
8
9
10
11
12
13
json.experience_locations do
json.array!(@experience_locations) do |experience|
json.name experience.location
json.url public_experiences_path(q: { location_cont: experience.location })
end
end
json.experience_names do
json.array!(@experience_names) do |experience|
json.name experience.name
json.url public_experiences_path(q: { name_cont: experience.name })
end
end
Dapat dilihat pada blok kode di atas, bahwa saya memanggil instance variable @experience_locations
dan @experience_names
yang sudah saya definisikan sebelumnya pada experiences controller.
location_cont
dan name_cont
adalah predicates _cont
yang disediakan oleh Ransack yang berarti “Contains value”.
Apabila kita coba di Browser, dengan url form seperti ini,
http://localhost:3000/experiences.json?q=location_atau_nama_experience
akan seperti ini hasilnya.
Nah, langkah terakhir tinggal membuat blok kode untuk menampilkan hasil pencarian pada index.html.erb
.
Untuk detailnya dapat teman-teman olah sendiri.
1
2
3
4
5
6
7
8
9
10
11
<% @experiences.each do |experience| %>
...
...
<h5> <%= experience.name.titleize %> </h5>
...
...
<% end %>
Selesai!
Mudah-mudahan bermanfaat.
Mungkin pada kesempatan yang lain, akan saya buatkan demo projectnya dan membuat GitHub reponya.
Atau dapat juga saya menuliskan cara lain dengan memanfaatkan JQuery plugin yang lain, seperti Select2.
Sepertinya menarik, kalo lebih banyak pilihan.
Oke, sepertinya hanya segini saja yang dapat saya tuliskan.
Terima kasih.
(^_^)
Referensi
-
easyautocomplete.com/
Diakses tanggal: 2019/12/07 -
github.com/activerecord-hackery/ransack
Diakses tanggal: 2019/12/07
Lisensi
Atribusi-NonKomersial-BerbagiSerupa 4.0 Internasional (CC BY-NC-SA 4.0)
Penulis
My journey kicks off from reading textbooks as a former Medical Student to digging bugs as a Software Engineer – a delightful rollercoaster of career twists. Embracing failure with the grace of a Cat avoiding water, I've seamlessly transitioned from Stethoscope to Keyboard. Armed with ability for learning and adapting faster than a Heart Beat, I'm on a mission to turn Code into a Product.
- Rizqi Nur Assyaufi