Kỹ thuật tạo các trang tĩnh (static pages) trong Rails

Khi viết một ứng dụng web, có những trang chỉ chứa nội dung tĩnh hoặc không bao gồm dữ liệu lấy ra từ cơ sở dữ liệu. Chính xác hơn, điều này chỉ đúng một cách tương đối và chúng ta tạm gọi đó là những trang (tương đối) tĩnh. Thuật ngữ tiếng anh tương ứng là static pages. Trong bài viết này, tôi sẽ giới thiệu một cách để tạo những trang tĩnh khi làm việc với Rails framework.

1 Thiết lập môi trường

Bài tutorial này được thực hiện trên hệ điều hành Ubuntu 16.04 LTS, 64-bit có cài Ruby phiên bản 2.3.3, Rails phiên bản 5.0.2. Đầu tiên chúng ta sẽ thực hiện câu lệnh ở terminal để tạo một thư mục Rails app mới với tên hợp lệ, chẳng hạn như demo:

cd ~/Desktop
rails new demo

2 Controller

Tiếp theo bạn cần tạo một controller với tên phù hợp, ở đây tôi sẽ chọn là StaticPages. Có thể dùng lệnh rails để tạo controller:

rails generate controller StaticPages

Hoặc chúng ta sẽ tạo một cách thủ công:

touch app/controllers/static_pages_controller.rb

Sau đó bạn mở file controller vừa tạo, thêm vào action show:

class StaticPagesController < ApplicationController
  def show
  end
end

Action show này sẽ được sử dụng để render ra các trang tĩnh có tên giống với tham số truyền vào. Các trang đó sẽ được chứa trong thư mục app/view/static_pages và có phần mở rộng là .html.erb. Tóm lại, action show sẽ được cài đặt như sau:

class StaticPagesController < ApplicationController
  def show
    render template: "static_pages/#{params[:page]}"
  end
end

3 Tạo route để điều hướng các request

Trong file config/routes.rb, chúng ta viết:

Rails.application.routes.draw do
  get "/static_pages/:page", to: "static_pages#show"
end

Câu lệnh này sẽ gửi các get request với url có dạng /static_pages/*** tới action show của controller StaticPages để xử lý. Mọi thứ gần như đã hoàn thành! Việc còn lại là tạo view để hiển thị các trang tĩnh.

4 Tạo một trang tĩnh

Trong thư mục app/view/static_pages, bạn tạo 1 file có tên là about.html.erb để viết nội dung sẽ hiển thị lên trình duyệt. Nếu trước đó bạn chọn cách tạo controller thủ công thì trước khi tạo file này chúng ta cần tạo thư mục static_pages.

Chẳng hạn tôi sẽ viết nội dung sau vào file about.html.erb:

<h1>About page</h1>

Done! Bạn bật rails server, gõ lên trình duyệt đường dẫn http://localhost:3000/static_pages/about, kết quả hiển thị thật...mỹ mãn:

5 Tạo trang chủ

Chúng ta sẽ đặt nội dung của trang chủ ở file app/view/static_pages/home.html.erb, chẳng hạn như:

<h1>This is my homepage.</h1>

Để thiết lập khi gửi get request với url localhost:3000 mặc định sẽ hiển thị trang home này, trong file config/routes.rb chúng ta sử dụng method root:

Rails.application.routes.draw do
  root "static_pages#show", page: "home"
  get "/static_pages/:page", to: "static_pages#show"
end

Kết quả thu được như sau:

6 Xử lý lỗi "Not Found"

Về cơ bản, chúng ta đã dựng ra được các trang tĩnh, nhưng bạn có thể nhận thấy là chưa có phần xử lý khi người dùng gõ vào một đường dẫn url để truy cập đến một trang không tồn tại, chẳng hạn như http://localhost:3000/static_pages/about123. Cách mà các website thường áp dụng là hiển thị thông báo không tìm thấy trang đó, đồng thời trả về mã trạng thái HTTP 404.

Cụ thể, trong code controller chúng ta sẽ viết một phương thức valid_page? để kiểm tra xem trang mà người dùng truy cập có tồn tại trong hệ thống hay không, nếu có thì trả về true, nếu sai trả về false. Dựa trên giá trị boolean của phương thức valid_page?, action show sẽ render ra template tương ứng:

class StaticPagesController < ApplicationController
  def show
    if valid_page?
      render template: "static_pages/#{params[:page]}"
    else
      render file: "public/404.html", status: :not_found
    end
  end

  private

  def valid_page?
    File.exist?(Pathname.new(Rails.root + "app/views/static_pages/#{params[:page]}.html.erb"))
  end
end

Như đã nói ở trên, chúng ta sẽ bổ sung một boolean medthod valid_page? vào class StaticPagesController, với scope là private vì nó chỉ cần sử dụng ở class này.

Khi gọi đến method root của module Rails, kết quả trả về là đường dẫn gốc của ứng dụng. Sau đó dùng phép nối chuỗi (string concatenation) để tạo thành đường dẫn đầy đủ của trang tĩnh mà người dùng định truy cập đến.

Tiếp tục, phương thức new của class Pathname nhận tham số truyền vào là đường dẫn đó, tạo ra một đối tượng thuộc class. Đối tượng này lại trở thành tham số của boolean method exist? trong lớp File. Nếu trang tĩnh mà người dùng muốn truy cập tồn tại, đường dẫn đầy đủ của nó sẽ hợp lệ, từ đó kết quả trả về của cả câu lệnh là true, nghĩa là file tồn tại, và ngược lại.

Action show sẽ sử dụng method valid_page? này để đưa ra kết quả phù hợp cho người dùng. Theo mặc định, các ứng dụng Rails có một trang thông báo lỗi 404 (not found) ở trong thư mục public.

Bây giờ, nếu bạn tìm đến một file không tồn tại, giao diện tương ứng sẽ hiển thị, ví dụ như:

7 Bổ sung

Giả sử chúng ta muốn tạo một thư mục con trong thư mục app/view/static_pages để chứa các trang tĩnh phục vụ một mục đích chung chuyên biệt, khác với các trang tĩnh còn lại. Tôi tạm gọi tên thư mục con đó là features, trong đó có các file chẳng hạn như first_feature.html.erb, second_feature.html.erb, v.v...

Nếu chỉ dừng ở việc tạo thêm các file view như vậy, khi truy cập trên trình duyệt sẽ bị lỗi "Routing Error":

Nguyên nhân là do trong file config/routes.rb hiện tại có câu lệnh:

get "/static_pages/:page", to: "static_pages#show"

Với cách viết này, chúng ta đang truyền tham số page cho action show dưới dạng một string, nó sẽ không xử lý được trường hợp khi tham số page có dạng features/first_feature. Cách viết để khắc phục vấn đề:

get "/static_pages/*page", to: "static_pages#show"

Chỉ cần thay dấu : bằng dấu *, chúng ta đã cho phép tham số page truyền đến actionshow có dạng một array, kết quả là trang tĩnh mong muốn sẽ hiển thị bình thường:

8 Kết luận

Trên đây, tôi đã trình bày một cách nhanh gọn để cài đặt các trang tĩnh trong một ứng dụng Rails. Tôi đề xuất thêm một cách làm khác với việc sử dụng gem high_voltage. Nó sẽ cung cấp một Rails engine để giúp bạn nhanh chóng thực hiện tác vụ này, ngoài ra còn có thêm các helper hữu ích khác. Hi vọng bài viết sẽ hữu ích. Cảm ơn các bạn đã đón đọc.