Bài 7: Controllers và Request Handling
Vai trò của Controllers
Controllers trong Rails đóng vai trò trung gian giữa Models và Views. Chúng xử lý requests, tương tác với Models, và chuẩn bị dữ liệu cho Views.
Cấu trúc cơ bản của một Controller
class UsersController < ApplicationController
def index
@users = User.all
end
def show
@user = User.find(params[:id])
end
def new
@user = User.new
end
def create
@user = User.new(user_params)
if @user.save
redirect_to @user, notice: 'User was successfully created.'
else
render :new
end
end
private
def user_params
params.require(:user).permit(:name, :email, :password)
end
end
Filters và Callbacks
Filters cho phép bạn chạy code trước, sau hoặc xung quanh các actions của controller.
class ApplicationController < ActionController::Base
before_action :require_login
after_action :log_action
around_action :wrap_in_transaction, only: [:create, :update, :destroy]
private
def require_login
unless current_user
flash[:error] = "You must be logged in to access this section"
redirect_to login_url
end
end
def log_action
Rails.logger.info "Action completed: #{action_name}"
end
def wrap_in_transaction
ActiveRecord::Base.transaction do
yield
end
end
end
Strong Parameters
Strong Parameters là một tính năng bảo mật giúp kiểm soát dữ liệu được phép truyền vào trong mass assignment.
class UsersController < ApplicationController
def create
@user = User.new(user_params)
# ...
end
private
def user_params
params.require(:user).permit(:name, :email, :password)
end
end
Session và Cookies
Rails cung cấp các cơ chế để lưu trữ dữ liệu giữa các requests.
class SessionsController < ApplicationController
def create
user = User.authenticate(params[:email], params[:password])
if user
session[:user_id] = user.id
redirect_to root_url, notice: "Logged in!"
else
flash.now.alert = "Invalid email or password"
render "new"
end
end
def destroy
session[:user_id] = nil
redirect_to root_url, notice: "Logged out!"
end
end
API development với Rails
Rails cung cấp các công cụ mạnh mẽ để xây dựng APIs.
class Api::V1::UsersController < ApplicationController
skip_before_action :verify_authenticity_token
before_action :authenticate_token
def index
@users = User.all
render json: @users
end
def show
@user = User.find(params[:id])
render json: @user
end
private
def authenticate_token
unless valid_token?
render json: { error: 'Invalid token' }, status: :unauthorized
end
end
def valid_token?
request.headers['Authorization'] == 'Bearer valid_token'
end
end
Request và Response Cycle
Hiểu rõ về chu trình request-response rất quan trọng trong Rails.
- Request đến server
- Router xác định controller và action
- Controller xử lý request
- Controller tương tác với Model (nếu cần)
- Controller chuẩn bị dữ liệu cho View
- View render kết quả
- Response được gửi lại cho client
Exception Handling
Xử lý ngoại lệ một cách graceful là rất quan trọng trong Rails.
class ApplicationController < ActionController::Base
rescue_from ActiveRecord::RecordNotFound, with: :record_not_found
rescue_from User::NotAuthorized, with: :user_not_authorized
private
def record_not_found
render plain: "404 Not Found", status: 404
end
def user_not_authorized
flash[:alert] = "You are not authorized to perform this action."
redirect_to(request.referrer || root_path)
end
end
Caching trong Controllers
Caching có thể cải thiện đáng kể hiệu suất của ứng dụng.
class ProductsController < ApplicationController
def index
@products = Rails.cache.fetch("products", expires_in: 12.hours) do
Product.all.to_a
end
end
end
Concerns
Concerns cho phép bạn chia sẻ logic giữa các controllers.
# app/controllers/concerns/authenticatable.rb
module Authenticatable
extend ActiveSupport::Concern
included do
before_action :require_login
end
private
def require_login
unless current_user
redirect_to login_path, alert: "Please log in first"
end
end
end
class UsersController < ApplicationController
include Authenticatable
# ...
end
Testing Controllers
Testing controllers là một phần quan trọng trong phát triển Rails.
# test/controllers/users_controller_test.rb
require 'test_helper'
class UsersControllerTest < ActionDispatch::IntegrationTest
test "should get index" do
get users_url
assert_response :success
end
test "should create user" do
assert_difference('User.count') do
post users_url, params: { user: { name: 'John', email: 'john@example.com' } }
end
assert_redirected_to user_url(User.last)
end
end
Kết luận
Controllers đóng vai trò trung tâm trong ứng dụng Rails, xử lý requests, tương tác với models, và chuẩn bị dữ liệu cho views. Hiểu rõ về cách hoạt động của controllers và các kỹ thuật xử lý requests sẽ giúp bạn xây dựng các ứng dụng Rails mạnh mẽ và linh hoạt.
Trong thực tế, việc giữ cho controllers "gầy" (thin) bằng cách di chuyển logic phức tạp vào models hoặc service objects là một practice tốt. Điều này giúp code dễ đọc, dễ bảo trì và dễ test hơn.
Trong bài tiếp theo, chúng ta sẽ đi sâu vào việc testing trong Ruby on Rails, một khía cạnh quan trọng để đảm bảo chất lượng và độ tin cậy của ứng dụng.