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 (Create – Read – Update – Delete), 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:
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.