05/10/2019, 18:30

Resource, Resources, Nested Resource trong Rails

Rails Routes là gì? Request của người dùng sẽ được gửi đến đâu? Sự kết nối giữa Rails routes, Controller và View là gì? Rails RESTful là gì?... Đó là những câu hỏi của nhiều người khi mới bắt đầu với Ruby on Rails, bài viết này sẽ giải thích một cách cơ bản nhất những câu hỏi trên đồng thời đưa ...

Rails Routes là gì? Request của người dùng sẽ được gửi đến đâu? Sự kết nối giữa Rails routes, Controller và View là gì? Rails RESTful là gì?...

Đó là những câu hỏi của nhiều người khi mới bắt đầu với Ruby on Rails, bài viết này sẽ giải thích một cách cơ bản nhất những câu hỏi trên đồng thời đưa ra các ví dụ sử dụng một số kỹ thuật của Ruby on Rails để giúp các bạn dễ hiểu hơn về Rails Routes.

1. What is Rails Router

Routes trong Rails là một module có nhiệm vụ phát hiện ra các URL (request) từ trình duyệt gửi lên, nó cần phải biết mỗi một request chạy tương ứng với một action nào trong Controller. Nói một cách đơn giản thì khi người dụng nhập một đường dẫn url trên tên miền của bạn, Rails routes sẽ gọi đến đúng Controller và action tương ứng với url đó.Nếu không tìm thấy route phù hợp với yêu cầu, ứng dụng sẽ xảy ra lỗi. Ngoài ra, router còn sinh Paths và URLs từ code để người dùng có thể link nhanh đến đường dẫn mà họ muốn.

Trong sơ đồ trên, yêu cầu của người dùng đối với URL pages/home sẽ đi từ trình duyệt của người dùng đến Rails Router. Sau đó routes sẽ quyết định rằng request trên sẽ được xử lý bởi pages_controller.rb và action home tương ứng. Cuối cùng một response được trả về cho user (controller render HTML lại cho user).

Ứng dụng Rails yêu cầu routes phải khớp với request của người dùng và các action trong controller tương ứng. Các routes trong một ứng dung Rails được cấu hình trong file config/routes.rb. Trong sơ đồ trên routes tương ứng là:

Rails.application.routes.draw do
  get "/pages/home", to: "pages#home"
end

Để kiểm tra các routes trong ứng dụng của mình bạn sử dụng lệnh rails routes.

Routes sẽ tự động ánh xạ request từ trình duyệt đến action hoặc method tương ứng của pages_controller. Sau đó action xác định trang nào sẽ được hiển thị cho người dùng ( ở đây trang được hiển thị là home.html.erb.

2. Rails RESTful

REST là viết tắt của Representational State Transfer, hiểu nôm na thì REST là một kiến trúc trong lập trình website. Ứng dụng theo chuẩn RESTful sẽ coi web như một resource. Về cơ bản sẽ có 7 loại action mà bạn có thể làm với resource.

  • GET: index, show, new và edit
  • POST: create
  • PUT: update
  • DELETE: destroy

Trong Rails bạn có thể tạo ra các routes mặc định của RESTful bằng cách xử dụng từ khóa resources theo sau là tên của controller tương ứng, ví dụ:

resources :users

Lệnh trên tạo ra tất cả 7 routes ánh xạ đến controller users.

Dùng lệnh rails routes để kiểm tra.

3. Resource routing

3.1. CRUD, Verbs và Actions

Mỗi routes có một ánh xạ giữa giữa HTTP verbs và URLs để điều khiển các hành động. Như ví dụ ở trên.

resources :users

tạo ra 7 routes khác nhau , tất cả ánh xạ đến Users controller.

HTTP Verb Path Controller#Action User for
GET /users users#index Hiển thị tất cả user
GET /users/new users#new Trả về form HTML để tạo mới user
POST /users users#create Tạo mới user
GET /users/:id users#show Hiển thị một user
GET /users/:id/edit users#edit Trả về form HTML để sửa user
PATCH/PUT /users/:id users#update Cập nhật một user
DELETE /users/:id users#destroy Xóa một user

Giải thích qua một chút về bảng trên nhé ????

  • HTTP Verb là tên các phương thức.
  • Path là đường dẫn sẽ hiển thị trên trình duyệt khi bạn thực hiện 1 hành động nào đó, chẳng hạn, phương thức GET với đường dẫn là /users/:id sẽ thực hiện hành động show để hiển thị thông tin user mà id được truyền vào.

3.2 Path và URL helper

Việc tạo một resourceful route cũng tạo ra 1 số helper cho controller trong ứng dụng của bạn. Đó chính là path và url, Trong trường hợp với resources :users ta có:

  • users_path: trả về tất cả các user
  • new_user_path: trả về user/new
  • edit_user_path(:id): Trả về /user/:id/edit
  • user_path(:id) Trả về /users/:id

3.3 Controller Namespaces and Routing

Rails cho phép bạn có thể nhóm các controller vào một namespaces bằng từ khóa namespace. Ví dụ nhóm các Articles và Comments controller trong Admin controller.

namespace :admin do 
 resources :articles, :comments
end

Khi đó, để xem được các bài viết bạn phải thêm tiền tố admin vào url.

/admin/articles

Vẫn sẽ có 7 routes được tạo ra như sau bảng sau:

HTTP Verb Path Controller#Action Named Helper
GET /admin/articles /admin/articles#index admin_articles_path
GET /admin/articles/new /admin/articles#new new_admin_articles_path
POST /admin/articles /admin/articles#create admin_articles_path
GET /admin/articles/:id /admin/articles#show admin_articles_path(:id)
GET /admin/articles/:id/edit /admin/articles#edit edit_admin_articles_path(:id)
PATCH/PUT /admin/articles/:id /admin/articles#update admin_articles_path(:id)
DELETE /admin/articles/:id /admin/articles#destroy admin_articles_path(:id)

3.4 Giới hạn route muốn sử dụng

Rails cho phép các lập trình viên có thể lựa chọn các action mà họ muốn sử dụng bằng cách sử dụng các từ khóa như only hoặc except. Ví dụ:

resources :posts, only: [:index, :show]
resources :users, except: [:index]

Với cách config như trên thì với post bạn chỉ có 2 routes tương ứng với index và show đó là tác dụng của only. Ngược lại khi sử dụng except với user bạn sẽ có tất cả routes theo mặc định của RESTful ngoại trừ routes ứng với index dễ hiểu đúng không ????.

3.5 Non-RESTful Routes

RESTful là lựa chọn mặc định của 1 ứng dụng Rails, tuy nhiên bạn cũng có thể tự tạo ra một routes riêng và anh xạ nó vào 1 controller nhé.

get "/help", to: "static_pages#help"

Tuy nhiên khi còn có thể thì bạn vẫn nên cố gắng tuân thủ theo RESTful nhé ????.

3.6 Resources hay Resource?

Từ đầu bài viết đến giờ trong các ví dụ của mình đều chỉ dùng resources vậy nên các bạn cũng đã hiểu được resources làm được những gì trong ứng dụng Rails rồi đúng không? Tuy nhiên trong Rails cũng cung cấp cho lập trình viên một từ cách khác để tạo routes gần giống với resources đó là resource. Phần này sẽ nêu ra những điểm khác nhau giữa resources và resource.

Đầu tiên hãy xem sự khác nhau giữa 2 options này nhé!

Với resources

resources :users

Kết quả rails routes.

Như các bạn biết resources cung cấp cho lập trình viên đủ 7 routes là: index, new, create, show, edit, update, destroy theo đúng kiến trúc của RESTful đế hỗ trợ việc tương tác với database.

Với resource

resource :user

Kết quả rails routes

Còn với resoucre thì chỉ còn 6 routes thôi: new, create, show, edit, update, destroy. Và cũng dễ thấy trong các routes không sử dụng đến :id.

Vậy thì khi nào dùng đến resoucre nhỉ?

Ví dụ nhé: Khi người bạn muốn cho người dùng có thể xem thông tin của họ mà không cần id, lúc đó đường dẫn của bạn chỉ đơn giản là /profile thôi cũng có thể hiển thị thông tin của người đang đăng nhập hiện tại.

3.6 Nested Resources

Nested Resources là một kĩ thuật trong Rails, nó dùng để phản ánh mối quan hệ has_many giữa các model trong routes và sau đó thể hiện nó qua URLs. Việc sử dụng Nested Resources giúp code dễ hiểu hơn, giúp code DRY (don't repeat yourself). ví dụ sau đây sẽ giúp bạn hiểu hơn về Nested Resources.

#app/models/club.rb
class Club < ActiveRecord::Base
    has_many :fighters
end


#app/models/fighter.rb
class Fighter < ActiveRecord::Base
    belongs_to :club
end

Một club sẽ có nhiều fighters và một fighter sẽ thuộc về một club.

Trong file config/routes.rb ta cấu hình như sau:

resources :clubs do
  resources :fighters
end

Bây giờ ta đã có Nested Resources trong ứng dụng của mình, kiểm tra các routes đó nhé~

rails routes

Done! Vậy là Rails vẫn tạo ra đầy đủ các routes theo chuẩn RESTful, và nó sẽ có thêm tiền tố là clubs/:club_id đúng những gì chúng ta mong muốn.

Đến đây thay vì phải code như thế này trong file clubs_controller.rb.

def fighters_index
 @club = Club.find_by :id params[:id]
 @fighters = @club.fighters
 render template: "fighters/index"
end

Thì chúng ta có thể code mà vẫn tuân thủ các nguyên tắc của kiến trúc RESTful, ở trong file fighters_controller.rb ta viết:

def index
 if params[:club_id]
   @fighters = Club.find_by(:id params[:club_id]).includes(:clubs).fighters
 else
   @fighters = Fighter.all
 end
end

4. Kết luận

Trên đây là nhưng điều cơ bản về Rails Routing trong Rails mà tôi đã tìm hiểu được. Hy vọng thông qua bài viết này các bạn sẽ hiểu hơn về Rails Routing trong Rails.

Cảm ơn vì đã đọc bài!

Nguồn tham khảo:

https://guides.rubyonrails.org/routing.html#nested-resources https://dev.to/brittanytinnin/nested-resources-in-rails-5-4oea https://stackoverflow.com/questions/11356146/difference-between-resource-and-resources-in-rails-routing

0