Database di Ruby on Rails sebenarnya sudah dipermudah lewat ActiveRecord dan migrasi, tapi banyak pemula tetap bingung saat harus mengubah tabel, menghubungkan data, atau mencari query yang pas. Tips mengelola database Ruby on Rails berikut fokus pada hal-hal yang sering kamu temui di proyek pertama, mulai dari membuat migrasi sampai menghindari query berat.
Pahami dulu peran migrasi
Migrasi adalah file yang mencatat perubahan struktur database. Setiap kali kamu menambah kolom, membuat tabel baru, atau menghapus index, buat file migrasi. Jangan pernah mengubah database langsung lewat phpMyAdmin atau psql, karena perubahan itu tidak tercatat dan akan menyulitkan rekan tim.
Untuk membuat migrasi, jalankan perintah berikut di terminal:
rails generate migration AddUmurToUsers umur:integer
Perintah itu menghasilkan file di folder db/migrate. Buka file tersebut, lalu sesuaikan isinya. Setelah yakin, jalankan rails db:migrate. Kalau ingin membatalkan migrasi terakhir, gunakan rails db:rollback. Biasakan menulis migrasi yang bisa di-rollback dengan aman, misalnya dengan menyertakan metode down atau memakai change yang didukung.
Gunakan relasi antar tabel dengan tepat
Relasi adalah bagian yang paling sering salah paham. Tiga jenis yang umum: has_many, belongs_to, dan has_many :through. Contoh sederhana, seorang penulis punya banyak artikel:
class Penulis < ApplicationRecord
has_many :artikels
end
class Artikel < ApplicationRecord
belongs_to :penulis
end
Pastikan tabel artikels punya kolom penulis_id sebagai foreign key. Saat membuat model, kamu bisa langsung menambahkan referensi:
rails generate model Artikel judul:string penulis:references
Untuk relasi banyak ke banyak, misalnya artikel punya banyak tag dan tag dipakai banyak artikel, gunakan has_many :through dengan tabel penghubung. Hindari has_and_belongs_to_many kalau kamu perlu menyimpan data tambahan di tabel penghubung.
Manfaatkan scope untuk query yang sering dipakai
Scope membuat query bisa dipakai ulang dan lebih mudah dibaca. Misalnya kamu sering menampilkan artikel yang sudah terbit:
class Artikel < ApplicationRecord
scope :terbit, -> { where(status: 'terbit') }
scope :terbaru, -> { order(created_at: :desc) }
end
Dengan begitu, di controller kamu cukup menulis Artikel.terbit.terbaru. Scope juga bisa dirangkai dengan scope lain. Hindari menulis query panjang berulang di banyak tempat karena akan sulit dirawat.
Hati-hati dengan N+1 query
N+1 query terjadi saat kamu memuat daftar data lalu mengakses relasinya satu per satu. Contohnya, menampilkan daftar artikel beserta nama penulisnya:
@artikels = Artikel.all
# di view: artikel.penulis.nama
Kode di atas akan menjalankan satu query untuk artikel, lalu satu query tambahan untuk setiap penulis. Solusinya, gunakan includes:
@artikels = Artikel.includes(:penulis).all
Rails akan memuat data penulis dalam satu query terpisah, sehingga total query jauh lebih sedikit. Kalau kamu ingin memantau query yang berjalan, aktifkan bullet gem di lingkungan development. Gem ini memberi peringatan saat ada N+1 query atau query yang tidak perlu.
Biasakan menulis indeks pada kolom yang sering dicari
Indeks mempercepat pencarian, tapi memperlambat proses insert dan update. Tambahkan indeks pada kolom yang sering muncul di klausa where, order, atau join. Misalnya, kalau kamu sering mencari user berdasarkan email, buat migrasi:
add_index :users, :email, unique: true
Untuk tabel penghubung, indeks gabungan pada dua foreign key biasanya diperlukan. Kamu bisa menambahkannya lewat migrasi:
add_index :artikel_tags, [:artikel_id, :tag_id], unique: true
Jangan menambahkan indeks ke semua kolom karena akan membebani penyimpanan dan memperlambat penulisan data.
Gunakan transaksi saat mengubah beberapa tabel sekaligus
Kalau satu aksi menyentuh lebih dari satu tabel, bungkus dalam transaksi. Contohnya, saat membuat artikel sekaligus mencatat log aktivitas:
ActiveRecord::Base.transaction do
artikel = Artikel.create!(judul: 'Contoh')
Log.create!(aksi: 'buat_artikel', artikel_id: artikel.id)
end
Jika salah satu gagal, seluruh perubahan dibatalkan. Ini mencegah data setengah jadi yang bikin bingung saat debug. Untuk operasi yang melibatkan beberapa model, kamu juga bisa memakai accepts_nested_attributes_for agar semuanya tersimpan dalam satu transaksi.
Rutin backup dan kelola environment
Database production dan development sebaiknya dipisah. Gunakan file database.yml yang berbeda untuk setiap environment. Biasakan membuat backup sebelum menjalankan migrasi yang mengubah data, terutama di production. Di Rails, kamu bisa menggunakan rails db:seed untuk mengisi data awal, tapi jangan pernah menjalankan seed di production tanpa pengawasan.
Kalau kamu bekerja dalam tim, pastikan semua anggota menjalankan rails db:migrate setelah menarik kode terbaru. Sertakan juga file schema.rb dalam repositori agar struktur database selalu sinkron.
Ringkasan
Mengelola database di Rails pada dasarnya tentang disiplin: buat migrasi untuk setiap perubahan, gunakan relasi dan scope yang jelas, hindari N+1 query, tambahkan indeks pada kolom yang tepat, dan bungkus operasi multi-tabel dalam transaksi. Mulai dari kebiasaan kecil ini, database kamu akan lebih mudah dirawat seiring proyek bertambah besar.
Pertanyaan yang Sering Diajukan
Apakah boleh mengubah database langsung tanpa migrasi?
Sebaiknya jangan. Perubahan langsung tidak tercatat dan bisa membuat struktur database di tim tidak seragam. Selalu gunakan migrasi agar riwayat perubahan jelas dan bisa di-rollback.
Bagaimana cara tahu ada N+1 query?
Pasang gem bullet di development. Gem ini akan memberi notifikasi di log atau browser saat mendeteksi N+1 query. Kamu juga bisa melihat log query di log/development.log untuk memantau query yang berjalan.
Apa bedanya includes dan joins?
includes memuat data relasi dalam query terpisah, sedangkan joins menggabungkan tabel dalam satu query. Gunakan includes kalau kamu perlu mengakses data relasi, dan joins kalau hanya ingin memfilter berdasarkan kolom relasi tanpa memuat datanya.
