1. Pengenalan Ruby on Rails
Ruby on Rails (atau biasa disebut Rails) adalah framework web open-source yang dibangun dengan bahasa Ruby oleh David Heinemeier Hansson pada tahun 2004. Rails mengikuti filosofi Convention over Configuration (CoC) dan Don't Repeat Yourself (DY), sehingga developer bisa fokus pada fitur alih-alih konfigurasi.
Rails digunakan oleh perusahaan besar seperti GitHub, Shopify, Airbnb, Basecamp, Twitter (awalnya), dan ribuan startup lainnya. Rails memungkinkan pengembangan web yang sangat cepat — Anda bisa membuat prototipe aplikasi web dalam hitungan jam.
Mengapa Menggunakan Rails?
| Keunggulan | Penjelasan |
|---|---|
| Convention over Configuration | Tidak perlu menulis banyak konfigurasi — Rails sudah mengatur semuanya |
| Don't Repeat Yourself | Setiap logika hanya ditulis sekali — mengurangi duplikasi |
| Generator yang Powerful | rails generate membuat model, controller, views, migration otomatis |
| Active Record (ORM) | Basis data yang elegan tanpa menulis SQL |
| Scaffolding | CRUD lengkap dibuat hanya dengan satu command |
| Ekosistem Gems | Ribuan library untuk autentikasi, API, background job, dll |
Rails vs Framework Lain
| Aspek | Rails | Django | Laravel |
|---|---|---|---|
| Bahasa | Ruby | Python | PHP |
| ORM | Active Record | Django ORM | Eloquent |
| Templating | ERB, Haml, Slim | Jinja2 | Blade |
| CLI | rails generate | django-admin | artisan |
| Filosofi | CoC + DRY | Battery Included | Elegant Syntax |
| Scaffolding | 🟢 Built-in | 🟡 Perlu extension | 🟢 Built-in |
flowchart TB
subgraph ecosystem["💎 RUBY ON RAILS ECOSYSTEM"]
direction TB
Router["🛤️ Router\n(Rails Routes)"]
Router --> Controller["🎮 Controller\n(ApplicationController)"]
Controller --> Model["📊 Model\n(ActiveRecord)"]
Model --> DB["("#quot;🗄️ Database\n(PostgreSQL/SQLite")#quot;)"]
Controller --> View["👁️ View\n(ERB Templates)"]
View --> Response["📤 HTTP Response"]
end
Gems["💎 Gems\n(devise, sidekiq, etc)"] --> ecosystem
style ecosystem fill:#0a0a12,stroke:#3ecf8e,stroke-width:2px
style Router fill:#2a1f0a,stroke:#f59e0b
style Controller fill:#0f2a1f,stroke:#3ecf8e,stroke-width:2px
style Model fill:#0f1d3a,stroke:#60a5fa
style View fill:#1a0f2e,stroke:#a78bfa
style DB fill:#2a0f1e,stroke:#f472b6
style Gems fill:#0a2a1f,stroke:#34d399
2. Instalasi dan Setup
Untuk menggunakan Rails, Anda memerlukan Ruby, RubyGems, dan Node.js (untuk Asset Pipeline).
Prasyarat
flowchart TB
Request["🌐 HTTP Request"] --> Router["🛤️ Router"]
Router --> Controller["🎮 Controller"]
Controller -->|"Query"| Model["📊 Model"]
Model --> DB["("#quot;🗄️ Database#quot;")"]
DB -->|"Data"| Model
Model -->|"Results"| Controller
Controller -->|"Render"| View["👁️ View"]
View --> Response["📤 HTTP Response"]
style Request fill:#2a0f1e,stroke:#f472b6
style Router fill:#2a1f0a,stroke:#f59e0b,stroke-width:1.5px
style Controller fill:#0f2a1f,stroke:#3ecf8e,stroke-width:2px
style Model fill:#0f1d3a,stroke:#60a5fa,stroke-width:1.5px
style DB fill:#2a0f1e,stroke:#f472b6
style View fill:#1a0f2e,stroke:#a78bfa,stroke-width:1.5px
style Response fill:#0a2a1f,stroke:#34d399
Alur Request Lengkap
# 1. Browser mengirim request: GET /users
# 2. Router (routes.rb) mencocokkan URL dengan controller action
# get '/users', to: 'users#index'
# 3. Controller menerima request dan memanggil Model
# class UsersController < ApplicationController
# def index
# @users = User.all # Query ke database via Model
# end
# end
# 4. Model mengambil data dari database
# SELECT * FROM users;
# 5. Controller mengirim data ke View
# @users tersedia di view
# 6. View merender HTML dengan data yang diterima
# <% @users.each do |user| %>
# <p><%= user.name %></p>
# <% end %>
# 7. HTML dikembalikan ke browser
4. Membuat Proyek Rails Baru
Rails menyediakan generator yang sangat powerful untuk membuat proyek baru, model, controller, views, dan banyak lagi.
Membuat Aplikasi Baru
# Buat aplikasi Rails baru dengan PostgreSQL
rails new blog_app -d postgresql
# Atau dengan SQLite (untuk pengembangan lokal)
rails new blog_app
# Masuk ke folder proyek
cd blog_app
# Lihat struktur folder yang dibuat
ls -la
# app/ - Kode utama (MVC)
# config/ - Konfigurasi aplikasi
# db/ - Database migrations & seeds
# public/ - File statis (CSS, JS, gambar)
# test/ atau spec/ - Unit test
# Gemfile - Dependency Ruby
# config.ru - Rack configuration
# Rakefile - Rake tasks
# Konfigurasi database di config/database.yml
# Jalankan setup database
rails db:create
rails db:migrate
# Jalankan server Rails
rails server
# => Booting Puma
# => Rails 7.1.3 application starting in development
# => Listening on http://127.0.0.1:3000
# Buka browser: http://localhost:3000
# Anda akan melihat halaman selamat datang Rails!
Folder Structure Rails
| Folder | Isi | Penjelasan |
|---|---|---|
app/models/ | user.rb | Model untuk interaksi database |
app/views/ | users/ | Template HTML untuk setiap resource |
app/controllers/ | users_controller.rb | Logika penanganan request |
config/routes.rb | Routing | URL mapping ke controller#action |
db/migrate/ | 20240101_create_users.rb | Skema database (migrations) |
config/database.yml | Konfigurasi | Pengaturan koneksi database |
Gemfile | Dependencies | Daftar gem yang dibutuhkan proyek |
Generator Commands
# Generator sangat penting di Rails
# Menunjukkan semua generator yang tersedia
rails generate --help
# Generate model
rails generate model User name:string email:string age:integer
# Menghasilkan:
# - app/models/user.rb
# - db/migrate/20240101000000_create_users.rb
# - test/models/user_test.rb
# Generate controller
rails generate controller Users index show new edit
# Menghasilkan:
# - app/controllers/users_controller.rb
# - app/views/users/index.html.erb
# - app/views/users/show.html.erb
# - test/controllers/users_controller_test.rb
# Generate scaffold (semua sekaligus: model + controller + views + tests)
rails generate scaffold Post title:string body:text user:references
# Ini menghasilkan CRUD lengkap!
# Generate migration tunggal
rails generate migration AddRoleToUsers role:string
# Generate resource (model + controller + routes)
rails generate resource Article title:string content:text
# Jalankan migration setelah generate
rails db:migrate
# Rollback migration jika salah
rails db:rollback
# Undo generate
rails destroy model User
rails destroy controller Users
5. Routing
Routing di Rails didefinisikan di config/routes.rb. Routing menentukan URL mana yang diarahkan ke controller action mana.
Basic Routing
# config/routes.rb
Rails.application.routes.draw do
# Root route (homepage)
root "pages#home"
# Basic routes
get '/about', to: 'pages#about'
get '/contact', to: 'pages#contact'
post '/contact', to: 'pages#submit_contact'
# RESTful routes dengan resource
resources :users
# Menghasilkan 7 route:
# GET /users => users#index
# GET /users/new => users#new
# POST /users => users#create
# GET /users/:id => users#show
# GET /users/:id/edit => users#edit
# PATCH /users/:id => users#update
# DELETE /users/:id => users#destroy
# Resources dengan pilihan tertentu
resources :posts, only: [:index, :show, :new, :create]
# Hanya membuat 4 route yang dipilih
resources :articles, except: [:destroy]
# Semua route kecuali destroy
# Nested resources
resources :users do
resources :posts
# Menghasilkan:
# GET /users/:user_id/posts
# GET /users/:user_id/posts/new
# GET /users/:user_id/posts/:id
# dll...
end
# Member routes (memerlukan ID)
resources :posts do
member do
post :publish
# POST /posts/:id/publish
post :archive
# POST /posts/:id/archive
end
end
# Collection routes (tidak memerlukan ID)
resources :posts do
collection do
get :search
# GET /posts/search
get :drafts
# GET /posts/drafts
end
end
# Namespace untuk API
namespace :api do
namespace :v1 do
resources :posts
# /api/v1/posts
end
end
end
Named Routes dan Path Helpers
# Ketika Anda mendefinisikan routes, Rails otomatis membuat
# helper methods:
# resources :users menghasilkan:
users_path # "/users"
user_path(@user) # "/users/1"
new_user_path # "/users/new"
edit_user_path(@user) # "/users/1/edit"
# Di controller:
redirect_to users_path
redirect_to user_path(@user)
redirect_to new_user_path
# Di views (ERB):
# <%= link_to "Semua User", users_path %>
# <%= link_to "Lihat User", user_path(@user) %>
# <%= link_to "Edit", edit_user_path(@user) %>
# <%= link_to "Hapus", user_path(@user), method: :delete %>
# Custom named route
get '/dashboard', to: 'pages#dashboard', as: :dashboard
# Menghasilkan: dashboard_path = "/dashboard"
# Cek semua routes yang tersedia:
# rails routes
# Atau di Rails 7+:
# rails routes --controller users
6. Controller dan Action
Controller menangani request HTTP dan mengirim response. Setiap controller action biasanya mengambil data dari model dan mengirimkannya ke view.
Controller Lengkap
# app/controllers/users_controller.rb
class UsersController < ApplicationController
before_action :set_user, only: [:show, :edit, :update, :destroy]
# GET /users
def index
@users = User.all.order(created_at: :desc)
@user_count = @users.count
end
# GET /users/:id
def show
# @user sudah diset oleh set_user (before_action)
end
# GET /users/new
def new
@user = User.new
end
# POST /users
def create
@user = User.new(user_params)
if @user.save
redirect_to @user, notice: "User berhasil dibuat!"
else
render :new, status: :unprocessable_entity
end
end
# GET /users/:id/edit
def edit
# @user sudah diset oleh set_user
end
# PATCH /users/:id
def update
if @user.update(user_params)
redirect_to @user, notice: "User berhasil diupdate!"
else
render :edit, status: :unprocessable_entity
end
end
# DELETE /users/:id
def destroy
@user.destroy
redirect_to users_path, notice: "User berhasil dihapus!"
end
private
def set_user
@user = User.find(params[:id])
end
# Strong Parameters — whitelist parameter yang diizinkan
def user_params
params.require(:user).permit(:name, :email, :age, :role)
end
end
Application Controller (Base Controller)
# app/controllers/application_controller.rb
class ApplicationController < ActionController::Base
before_action :set_locale
# Helper method untuk semua controllers & views
helper_method :current_user, :logged_in?
private
def current_user
@current_user ||= User.find_by(id: session[:user_id])
end
def logged_in?
current_user.present?
end
def require_login
unless logged_in?
redirect_to login_path, alert: "Anda harus login terlebih dahulu!"
end
end
def set_locale
I18n.locale = params[:locale] || I18n.default_locale
end
end
7. Views dan ERB Template
Views di Rails menggunakan template engine ERB (Embedded Ruby) yang memungkinkan Anda menulis Ruby code di dalam HTML. Ada juga alternatif seperti Haml dan Slim.
ERB Template
<%# app/views/users/index.html.erb %>
<h1>Daftar User (<%= @user_count %>)</h1>
<%# Flash messages %>
<% if notice %>
<div class="alert alert-success">
<%= notice %>
</div>
<% end %>
<% if @users.any? %>
<table class="table">
<thead>
<tr>
<th>Nama</th>
<th>Email</th>
<th>Umur</th>
<th>Aksi</th>
</tr>
</thead>
<tbody>
<% @users.each do |user| %>
<tr>
<td><%= user.name %></td>
<td><%= user.email %></td>
<td><%= user.age %></td>
<td>
<%= link_to "Lihat", user_path(user), class: "btn btn-info" %>
<%= link_to "Edit", edit_user_path(user), class: "btn btn-warning" %>
<%= link_to "Hapus", user_path(user),
data: { turbo_method: :delete, turbo_confirm: "Yakin?" },
class: "btn btn-danger" %>
</td>
</tr>
<% end %>
</tbody>
</table>
<% else %>
<p>Belum ada user.</p>
<% end %>
<%= link_to "Buat User Baru", new_user_path, class: "btn btn-primary" %>
Partials (Template Terpisah)
# Partial diawali dengan underscore: _user.html.erb
# app/views/users/_user.html.erb
<div class="user-card">
<h3><%= user.name %></h3>
<p>Email: <%= user.email %></p>
<p>Umur: <%= user.age %> tahun</p>
<%= link_to "Lihat Detail", user_path(user) %>
</div>
# Menggunakan partial di view utama:
# app/views/users/index.html.erb
<% @users.each do |user| %>
<%= render partial: "user", locals: { user: user } %>
<%# Atau shorthand: %>
<%= render user %>
<% end %>
# Partial dengan collection
<%= render partial: "user", collection: @users %>
# Setiap item otomatis tersedia sebagai 'user' di partial
# Layout partial (shared/_header.html.erb)
<%= render "shared/header" %>
# Yield untuk content_for di layout
<% content_for :title, "Daftar User" %>
# app/views/layouts/application.html.erb
# <title><%= content_for?(:title) ? yield(:title) : "BeebaneLabs" %></title>
Helper Methods
# app/helpers/users_helper.rb
module UsersHelper
def user_avatar(user, size: 50)
if user.avatar.attached?
image_tag user.avatar, size: "#{size}x#{size}", class: "avatar"
else
image_tag "default_avatar.png", size: "#{size}x#{size}", class: "avatar"
end
end
def format_umur(umur)
case umur
when 0..12 then "#{umur} tahun (Anak-anak)"
when 13..17 then "#{umur} tahun (Remaja)"
when 18..64 then "#{umur} tahun (Dewasa)"
else "#{umur} tahun (Lansia)"
end
end
def status_badge(user)
if user.active?
content_tag :span, "Aktif", class: "badge badge-success"
else
content_tag :span, "Nonaktif", class: "badge badge-danger"
end
end
end
# Menggunakan di view:
# <%= user_avatar(@user, size: 100) %>
# <%= format_umur(@user.age) %>
# <%= status_badge(@user) %>
8. Active Record
Active Record adalah ORM (Object-Relational Mapping) bawaan Rails yang memungkinkan Anda berinteraksi dengan database menggunakan Ruby objects. Anda bisa melakukan operasi CRUD tanpa menulis SQL!
Model Dasar
# app/models/user.rb
class User < ApplicationRecord
# Validations
validates :name, presence: true, length: { minimum: 2, maximum: 100 }
validates :email, presence: true, uniqueness: true,
format: { with: URI::MailTo::EMAIL_REGEXP }
validates :age, numericality: { greater_than: 0, less_than: 150 }
# Associations
has_many :posts, dependent: :destroy
has_many :comments, dependent: :destroy
# Scopes
scope :active, -> { where(active: true) }
scope :recent, -> { order(created_at: :desc).limit(10) }
scope :by_role, ->(role) { where(role: role) }
# Callbacks
before_save :downcase_email
# Instance methods
def full_info
"#{name} (#{email})"
end
def post_count
posts.count
end
# Class methods
def self.search(keyword)
where("name LIKE ? OR email LIKE ?", "%#{keyword}%", "%#{keyword}%")
end
private
def downcase_email
self.email = email.downcase
end
end
CRUD Operations
# Buka Rails console:
# rails console (atau: rails c)
# ===== CREATE =====
# Method 1: new + save
user = User.new(name: "Budi", email: "budi@mail.com", age: 25)
user.save # => true
# Method 2: create (new + save sekaligus)
User.create(name: "Rina", email: "rina@mail.com", age: 22)
# Method 3: create! (raises error jika gagal)
User.create!(name: "Andi", email: "andi@mail.com", age: 30)
# ===== READ =====
User.all # Semua user
User.find(1) # Cari berdasarkan ID
User.find_by(email: "budi@mail.com") # Cari berdasarkan atribut
User.where(age: 25) # Filter
User.where("age > ?", 20) # Filter dengan raw SQL
User.order(name: :asc) # Urutkan
User.limit(5) # Batasi 5 record
User.first # Record pertama
User.last # Record terakhir
User.count # Jumlah record
User.exists?(email: "budi@mail.com") # Cek keberadaan
# Chaining queries
User.active.recent.by_role("admin").where("age > ?", 18)
# ===== UPDATE =====
user = User.find(1)
user.name = "Budi Santoso"
user.save # => true
# Atau dengan update
user.update(name: "Budi Santoso", age: 26)
# Atau dengan update! (raises error)
user.update!(name: "Budi Santoso")
# Update multiple records
User.where(active: false).update_all(active: true)
# ===== DELETE =====
user = User.find(1)
user.destroy # Menghapus record dan memanggil callbacks
# Delete by condition
User.where("created_at < ?", 1.year.ago).destroy_all
9. Database Migrations
Migration di Rails adalah cara untuk mengubah skema database secara terstruktur dan reversible. Migration ditulis dalam Ruby, bukan SQL!
Membuat Migration
# Generate migration
rails generate migration CreateUsers name:string email:string age:integer
# Hasilnya: db/migrate/20240101120000_create_users.rb
class CreateUsers < ActiveRecord::Migration[7.1]
def change
create_table :users do |t|
t.string :name, null: false
t.string :email, null: false
t.integer :age
t.boolean :active, default: true
t.string :role, default: "user"
t.timestamps # created_at dan updated_at otomatis
end
# Tambahkan index
add_index :users, :email, unique: true
add_index :users, :role
end
end
# Jalankan migration
rails db:migrate
# == 20240101120000 CreateUsers: migrating ===================================
# -- create_table(:users)
# -> 0.0123s
# == 20240101120000 CreateUsers: migrated (0.0123s) =========================
Migration Commands
# Jalankan semua migration yang belum dijalankan
rails db:migrate
# Rollback migration terakhir
rails db:rollback
# Rollback 3 migration terakhir
rails db:rollback STEP=3
# Jalankan migration ke versi tertentu
rails db:migrate VERSION=20240101120000
# Reset database (drop + create + migrate + seed)
rails db:reset
# Seed data dari db/seeds.rb
rails db:seed
# Lihat status migration
rails db:migrate:status
# Cek skema database saat ini
cat db/schema.rb
Menambah Kolom Baru
# Generate migration untuk menambah kolom
rails generate migration AddPhoneToUsers phone:string
# Hasil: db/migrate/20240102120000_add_phone_to_users.rb
class AddPhoneToUsers < ActiveRecord::Migration[7.1]
def change
add_column :users, :phone, :string
add_column :users, :address, :text
add_column :users, :date_of_birth, :date
end
end
# Migration untuk menambah foreign key
rails generate migration AddUserRefToPosts user:references
# Hasil: db/migrate/20240103120000_add_user_ref_to_posts.rb
class AddUserRefToPosts < ActiveRecord::Migration[7.1]
def change
add_reference :posts, :user, null: false, foreign_key: true
# Atau:
# add_column :posts, :user_id, :bigint, null: false
# add_foreign_key :posts, :users
end
end
# Migration untuk mengubah kolom
class ChangeAgeInUsers < ActiveRecord::Migration[7.1]
def up
change_column :users, :age, :integer, default: 0
end
def down
change_column :users, :age, :integer, default: nil
end
end
# Migration untuk rename kolom
class RenameNameToFullNameInUsers < ActiveRecord::Migration[7.1]
def change
rename_column :users, :name, :full_name
end
end
10. Model Associations
Active Record Associations mendefinisikan hubungan antar model. Ada tiga jenis association utama: has_many, belongs_to, dan has_many :through.
Association Types
# User — has_many Posts
class User < ApplicationRecord
has_many :posts, dependent: :destroy
has_many :comments, dependent: :destroy
has_many :post_comments, through: :posts, source: :comments
has_one :profile, dependent: :destroy
has_and_belongs_to_many :roles
end
# Post — belongs_to User, has_many Comments
class Post < ApplicationRecord
belongs_to :user
has_many :comments, dependent: :destroy
has_many :tags, dependent: :destroy
has_one_attached :image
end
# Comment — belongs_to User and Post
class Comment < ApplicationRecord
belongs_to :user
belongs_to :post
end
# Profile — belongs_to User
class Profile < ApplicationRecord
belongs_to :user
end
# Tag — belongs_to Post
class Tag < ApplicationRecord
belongs_to :post
end
Menggunakan Associations
# Mendapatkan relasi
user = User.find(1)
user.posts # Semua post milik user ini
user.comments # Semua comment milik user ini
user.profile # Profile milik user ini
post = Post.find(1)
post.user # User yang memiliki post ini
post.comments # Semua comment pada post ini
# Membuat relasi baru
user.posts.create(title: "Post Baru", body: "Isi post")
user.posts.build(title: "Draft", body: "Draft post") # Tanpa save
# Mengakses data relasi dengan chaining
user.posts.published.recent # Post published milik user, urut terbaru
# Eager loading — menghindari N+1 query problem
# BAD — akan menjalankan N+1 queries:
users = User.all
users.each { |u| puts u.posts.count } # 1 query per user!
# GOOD — eager loading dengan includes:
users = User.includes(:posts).all
users.each { |u| puts u.posts.count } # Hanya 2 queries!
# Preload dan eager_load
User.preload(:posts) # 2 terpisah queries
User.eager_load(:posts) # 1 query dengan LEFT JOIN
User.includes(:posts).where(posts: { published: true }) # Hybrid
11. Validations dan Callbacks
Validations memastikan data yang masuk ke database valid dan konsisten. Callbacks memungkinkan Anda menjalankan kode sebelum/sesudah event tertentu pada model.
Validations
# app/models/post.rb
class Post < ApplicationRecord
belongs_to :user
# Validasi dasar
validates :title, presence: true,
length: { minimum: 5, maximum: 200 }
validates :body, presence: true,
length: { minimum: 10 }
validates :status, inclusion: { in: %w[draft published archived] }
validates :slug, uniqueness: true, allow_nil: true
# Custom validation
validate :title_not_profanity
# Conditional validation
validates :publish_date, presence: true, if: :published?
# Numericality
validates :view_count, numericality: {
greater_than_or_equal_to: 0,
only_integer: true
}
# Format validation
validates :slug, format: {
with: /\A[a-z0-9\-]+\z/,
message: "hanya boleh huruf kecil, angka, dan dash"
}
private
def title_not_profanity
bad_words = ["spam", "scam"]
if bad_words.any? { |word| title.downcase.include?(word) }
errors.add(:title, "mengandung kata yang tidak diizinkan")
end
end
end
Callbacks
# Callbacks tersedia dalam urutan berikut:
# before_validation → sebelum validasi
# after_validation → setelah validasi
# before_save → sebelum save (create & update)
# after_save → setelah save
# before_create → sebelum create
# after_create → setelah create
# before_update → sebelum update
# after_update → setelah update
# before_destroy → sebelum destroy
# after_destroy → setelah destroy
class Post < ApplicationRecord
before_save :generate_slug, :set_published_at
after_create :notify_followers
before_destroy :archive_content
private
def generate_slug
self.slug = title.parameterize if title.present? && slug.blank?
end
def set_published_at
if status_changed? && status == "published"
self.published_at = Time.current
end
end
def notify_followers
# Kirim notifikasi ke followers
NotificationService.new_post(self)
end
def archive_content
ArchivedPost.create!(
title: title,
body: body,
user_id: user_id,
archived_at: Time.current
)
end
end
12. Form dan CRUD
Rails memiliki helper form yang sangat powerful untuk membuat form HTML yang terintegrasi dengan model.
Form dengan form_with
<%# app/views/users/_form.html.erb %>
<%= form_with(model: @user, local: true) do |form| %>
<%# Tampilkan error jika ada %>
<% if @user.errors.any? %>
<div class="error-messages">
<h3><%= pluralize(@user.errors.count, "error") %> terjadi:</h3>
<ul>
<% @user.errors.full_messages.each do |message| %>
<li><%= message %></li>
<% end %>
</ul>
</div>
<% end %>
<div class="form-group">
<%= form.label :name, "Nama Lengkap" %>
<%= form.text_field :name, class: "form-control",
placeholder: "Masukkan nama..." %>
</div>
<div class="form-group">
<%= form.label :email, "Email" %>
<%= form.email_field :email, class: "form-control",
placeholder: "contoh@email.com" %>
</div>
<div class="form-group">
<%= form.label :age, "Umur" %>
<%= form.number_field :age, class: "form-control", min: 1, max: 150 %>
</div>
<div class="form-group">
<%= form.label :role, "Role" %>
<%= form.select :role,
options_for_select([
["User", "user"],
["Admin", "admin"],
["Moderator", "moderator"]
], @user.role),
{}, { class: "form-control" } %>
</div>
<div class="form-group">
<%= form.label :bio, "Bio" %>
<%= form.text_area :bio, class: "form-control", rows: 5 %>
</div>
<div class="form-group">
<%= form.label :active, "Aktif?" %>
<%= form.check_box :active %>
</div>
<div class="form-actions">
<%= form.submit "Simpan", class: "btn btn-primary" %>
<%= link_to "Batal", users_path, class: "btn btn-secondary" %>
</div>
<% end %>
Show View
<%# app/views/users/show.html.erb %>
<div class="user-detail">
<div class="user-header">
<h1><%= @user.name %></h1>
<%= status_badge(@user) %>
</div>
<div class="user-info">
<p><strong>Email:</strong> <%= @user.email %></p>
<p><strong>Umur:</strong> <%= format_umur(@user.age) %></p>
<p><strong>Role:</strong> <%= @user.role.capitalize %></p>
<p><strong>Bergabung:</strong> <%= l(@user.created_at, format: :long) %></p>
</div>
<% if @user.posts.any? %>
<h2>Posts (<%= @user.posts.count %>)</h2>
<% @user.posts.each do |post| %>
<div class="post-card">
<h3><%= post.title %></h3>
<p><%= truncate(post.body, length: 200) %></p>
<%= link_to "Baca selengkapnya", post_path(post) %>
</div>
<% end %>
<% end %>
<div class="actions">
<%= link_to "Edit", edit_user_path(@user), class: "btn btn-warning" %>
<%= link_to "Hapus", user_path(@user),
data: { turbo_method: :delete, turbo_confirm: "Yakin?" },
class: "btn btn-danger" %>
<%= link_to "Kembali", users_path, class: "btn btn-secondary" %>
</div>
</div>
13. Quiz: Uji Pemahamanmu!
Setelah membaca tutorial di atas, jawablah 5 pertanyaan berikut untuk menguji pemahamanmu tentang Ruby on Rails: