Rails – Routing

5/5 - (137 votes)

Routing là tính năng điều hướng một URL vào một phương thức nhất định, tính năng routing có trong hầu hết các web framework phổ biến như Django, Node.js…

Ví dụ

Chúng ta sẽ tạo một trang hiển thị sản phẩm và hiển thị trang này lên URL '/'.

Đầu tiên chúng ta tạo một controller có tên là store và có một phương thức là index như sau:

C:\Project\Rails\depot>rails generate controller store index
    create app/controllers/store_controller.rb
     route get 'store/index'
    invoke erb
    create   app/views/store
    create   app/views/store/index.html.erb
    invoke test_unit
    create   test/controllers/store_controller_test.rb
    invoke helper
    create   app/helpers/store_helper.rb
    invoke   test_unit
    invoke asserts
    invoke   coffee
    create     app/assets/javascripts/store.coffee
    invoke   scss
    create     app/assetss/stylesheets/store.scss

Nếu bạn còn nhớ thì mặc định Rails sẽ tự động điều hướng các URL dựa vào controller và các phương thức của chúng, chẳng hạn chúng ta vừa tạo controller tên store, trong đó có một phương thức tên index, thì Rails sẽ trỏ (hay route) URL /store/index về phương thức này, bạn có thể chạy server và test thử.

Thông tin về các routing này được lưu trong file routes.rb trong thư mục config như sau:

Rails.application.routes.draw do
    get 'store/index'   

    resources :products
    # The priority is based upon order of creation: first created -> highest priority.
    # See how all your routes lay out with "rake routes".

    # You can have the root of your site routed with "root"
    # root 'welcome#index'

    # Example of regular route:
    #     get 'products/:id' => 'catalog#view'

    # Example of named route that can be invoked with purchase_url(id: product.id)
    #     get 'products/:id/purchase' => 'catalog#purchase', as: :purchase

    # Example resource route (maps HTTP verbs to controller actions automatically):
    #     resources :products

    # Example resource route with options:
    #     resources :products do
    #         member do
    #             get 'short'
    #             post 'toggle'
    #         end
    #
    #         collection do
    #             get 'sold'
    #         end
    #     end

    # Example resource route with sub-resources:
    #     resources :products do
    #         resources :comments, :sales
    #         resource :seller
    #     end

    # Example resource route with more complex sub-resources:
    #     resources :products do
    #         resources :comments
    #         resources :sales do
    #             get 'recent', on: :collection
    #         end
    #     end

    # Example resource route with concerns:
    #     concern :toggleable do
    #         post 'toggle'
    #     end
    #     resources :posts, concerns: :toggleable
    #     resources :photos, concerns: :toggleable

    # Example resource route within a namespace:
    #     namespace :admin do
    #         # Directs /admin/products/* to Admin::ProductsController
    #         # (app/controllers/admin/products_controller.rb)
    #         resources :products
    #     end
end

File này do Rails tự tạo, dòng get 'store/index' rất trực quan, Rails định nghĩa đoạn URL /store/index sẽ được chuyển đến phương thức index trong controller store.

Tuy nhiên có một điều khó hiểu là trong các bài trước chúng ta có thể trỏ đến /product, /product/1, /product/1/edit ..v.v nhưng trong file routes.rb này lại không có dòng nào dạng như get 'product', lý do chúng ta có thể trỏ đến các URL product kia là nhờ vào dòng:

resources :products

Thông thường khi tạo một model chúng ta hay định nghĩa các phương thức thêm, sửa, xóa, cập nhật..v.v đây được gọi chung là các thao tác CRUD (CreateReadUpdateDelete), và như lẽ thông thường thì chúng ta sẽ phải tự định nghĩa controller cũng như các phương thức để thực hiện các thao tác đó, rồi khai báo các dòng get trong file routes.rb.

Chính vì thao tác CRUD quá phổ biến nên Rails đã đơn giản hóa việc này cho chúng ta, khi chúng ta khai báo products với resources, Rails sẽ hiểu là phải tự động xử lý các URL /product/... cho chúng ta luôn mà không cần phải khai báo ở đâu cả. Ngoài ra các lời gọi URL còn mang theo cả thông tin về phương thức nữa, như GET, POST, PUT…v.v Mặc định thì Rails định nghĩa 6 phương thức cùng với URL cho một model tương ứng như sau:

Phương thức gởi URL Controller#Phương thức xử lý Ý nghĩa
GET /products/new /products#new Trả về form HTML tạo một đối tượng mới
POST /products /products#create Tạo một đối tượng mới
GET /products /products#show Hiển thị thông tin về một đối tượng cụ thể
GET /products/edit /products#edit Trả về form chỉnh sửa một đối tượng
PATCH/PUT /products /products#update Cập nhật một đối tượng
DELETE /products /products#destroy Hủy một đối tượng

Tiếp theo, nếu bạn còn nhớ thì URL '/' sẽ được trả về một trang mẫu như sau:

capture

Chúng ta có thể sửa lại để Rails trỏ đến trang do chúng ta quy định như sau:

Rails.application.routes.draw do
    get 'store/index'

    resources :products
 
    root :to => 'store#index'
end

Bằng cách định nghĩa thuộc tính to của đối tượng root tới một URL như trên (controller và phương thức ngăn cách nhau bởi dấu '#') .

Tiếp theo chúng ta tạo một đối tượng để lưu trữ toàn bộ bản ghi trong controller, chúng ta sửa file store_controller.rb như sau:

class StoreController < ApplicationController
    def index
        @products = Product.all
    end
end

Chúng ta tham chiếu tới model Product và gọi phương thức all là sẽ lấy được danh sách các đối tượng (hay các bản ghi trong CSDL) của model đó.

Bây giờ chúng ta sẽ sửa lại view cho trang này một tí để hiển thị danh sách các sản phẩm, chúng ta sửa file view tương ứng là file app/views/store/index.html.erb như sau:

<% if notice %>
   <p id="notice"><%= notice %></p>
<% end %>

<h1>Product List</h1>

<% @products.each do |product| %>
    <div class="entry">
        <%= image_tag(product.image_url) %>
        <h3><%= product.title %></h3> 
        <%= sanitize(product.description) %>
        <div class="price_line">
            <span class="price"><%= product.price %></span>
        </div>
    </div>
<% end %>

Biến notice lưu giữ một chuỗi text thông báo, chẳng hạn như thông báo tạo thành công, hủy thành công… nếu có tồn tại thì chúng ta hiển thị ra.

Hàm image_tag sẽ tạo một thẻ <img> và nhận tham số là đường dẫn tham chiếu đến file ảnh.

Hàm sanitize() có tác dụng loại bỏ một số thẻ ký tự lạ trong một chuỗi. Chúng ta sẽ tìm hiểu sau.

capture

5 1 vote
Article Rating
Subscribe
Thông báo cho tôi qua email khi
guest

This site uses Akismet to reduce spam. Learn how your comment data is processed.

0 Comments
Inline Feedbacks
View all comments