Membedah routing dan controllers Rails: resources, nested routes, member/collection, constraints, dan namespaces, plus strong params, render vs redirect, flash messages, dan filters before_action

Setelah di episode 3 kalian berhasil menjalankan app pertama dengan scaffold, episode 4 masuk ke jantung kontrol Rails: routing dan controllers. Scaffold memberi kalian 7 route otomatis; episode ini menjelaskan apa yang sebenarnya terjadi — dan bagaimana menyesuaikannya saat kebutuhan melampaui default.
Mengapa dua topik ini disatukan? Karena route dan controller adalah pasangan: route menentukan permintaan apa yang masuk, controller menentukan siapa yang menangani dan bagaimana. Menguasai keduanya berarti kalian bisa merancang URL API, menangani params, dan mengalihkan response — skill inti yang dipakai di semua episode selanjutnya.
Cara paling sering mendeklarasikan route adalah resources — satu baris menghasilkan 7 route RESTful:
Rails.application.routes.draw do
resources :posts
end| Metode | Path | Action | Kegunaan |
|---|---|---|---|
| GET | /posts | index | Daftar semua |
| GET | /posts/new | new | Form baru |
| POST | /posts | create | Simpan baru |
| GET | /posts/:id | show | Detail satu |
| GET | /posts/:id/edit | edit | Form edit |
| PATCH/PUT | /posts/:id | update | Simpan edit |
| DELETE | /posts/:id | destroy | Hapus |
Cek daftar route lengkap kapan saja:
bin/rails routes
bin/rails routes -g post-g post memfilter route yang mengandung "post" — sangat berguna saat project membesar.
Ketika resource memiliki relasi hierarkis (post → comments), gunakan nested route:
resources :posts do
resources :comments, only: %i[create destroy]
endMenghasilkan route seperti POST /posts/:post_id/comments. Route show/index comments biasanya tidak perlu (komentar tampil di dalam halaman post), jadi batasi dengan only:.
Untuk action tambahan di luar 7 default:
resources :posts do
collection do
get :search
end
member do
post :publish
end
endGET /posts/search → PostsController#search); member pada satu resource (POST /posts/:id/publish → PostsController#publish).Constraints membatasi route berdasarkan format, param, atau subdomain:
get "profile/:username", to: "profiles#show",
constraints: { username: /[a-z0-9_]+/ }Namespaces mengelompokkan route di bawah prefiks path dan module controller:
namespace :admin do
resources :users
endMenghasilkan GET /admin/users → Admin::UsersController#index. Ini pola standar untuk area administrasi.
Semua data dari form masuk lewat params. Rails 8 memakai params.expect yang lebih ketat (menggantikan require+permit di banyak kasus):
def post_params
params.expect(post: [:title, :body])
endKata kunci: whitelist. Field yang tidak di-expect/permit tidak akan pernah masuk ke model — inilah pertahanan utama terhadap mass assignment (dibahas detail di episode 18).
Dua cara merespons setelah action:
def create
@post = Post.new(post_params)
if @post.save
redirect_to @post, notice: "Berhasil dibuat"
else
render :new, status: :unprocessable_entity
end
endrender :new merender template tanpa request baru (status 422) — dipakai saat validasi gagal agar form tetap berisi data; redirect_to @post mengirim HTTP 302 sehingga browser melakukan request baru ke GET /posts/:id — dipakai setelah sukses agar refresh tidak mem-submit ulang.Pesan sekali pakai yang tampil di halaman berikutnya:
redirect_to @post, notice: "Post berhasil dibuat"notice dan alert adalah dua flash bawaan; keduanya dirender di layout (app/views/layouts/application.html.erb). Flash otomatis terhapus setelah request berikutnya.
Kode yang dijalankan sebelum action tertentu:
class PostsController < ApplicationController
before_action :set_post, only: %i[show edit update destroy]
before_action :require_login, except: %i[index show]
private
def set_post
@post = Post.find(params[:id])
end
endbefore_action adalah tempat natural untuk autentikasi (redirect_to login_path unless current_user) dan penyiapan resource bersama. only: dan except: mengontrol action mana yang terpengaruh; alternatif Rails 8: skip_before_action di controller turunan.
Route helpers (posts_path, post_path(post), new_post_path) otomatis dihasilkan dari nama route — dipakai di view dan redirect. Beberapa perintah inspeksi yang mempercepat navigasi:
bin/rails routes -c posts # route milik controller posts
bin/rails routes -g comments # route berisi 'comments'
bin/rails routes -E # expanded (semua helper)-E menampilkan nama helper-nya lengkap dengan method dan path.
Warning
Jangan terlalu dalam men-nest route — aturan praktisnya maksimal satu tingkat (misal posts/:post_id/comments). Nested tiga tingkat (group/:id/posts/:post_id/comments) membuat URL panjang, param bertumpuk, dan helper membingungkan.
only: — resources :posts menghasilkan 7 route padahal aplikasi internal mungkin cuma butuh 3; route ekstra = permukaan serangan lebih besar.render setelah redirect — memanggil redirect_to lalu render di action yang sama menghasilkan DoubleRenderError. Gunakan redirect_to lalu return, atau satu cabang if/else. Demikian pula before_action yang tidak diberi only/except akan diterapkan ke semua action — selalu deklarasikan cakupannya.Episode 4 membekali kalian bahasa routing dan controller Rails: resources + nested/member/collection/constraints/namespaces, strong params dengan params.expect, perbedaan render vs redirect_to, flash messages, dan filter before_action.
Inti yang harus dibawa pulang:
resources :posts menghasilkan 7 route RESTful + route helpers.only:.params.expect(post: [...]) adalah pertahanan mass assignment.render untuk validasi gagal, redirect_to untuk sukses (mencegah double submit).before_action untuk autentikasi & penyiapan resource bersama.Di episode 5 selanjutnya kita akan masuk ke dunia Active Record & Models — migrations, associations (has_many, belongs_to, through), validations, dan scopes, sambil membangun model Blog lengkap: Post, Comment, dan User dengan query chaining. Sampai jumpa di episode 5!