iT邦幫忙

2023 iThome 鐵人賽

DAY 16
0
自我挑戰組

富士大顆系列 第 16

vol. 16 Rails 的導航員:routes.rb 「請往這邊走哦!」(下)

  • 分享至 

  • xImage
  •  

你好,我是富士大顆 Aiko
那經過了上一篇的洗禮(???),應該是對網路概念有了較深一層的認識
接著繼續昨天的主題摟 gogo


CoC in routes

當 Controller 名稱包含兩個或更多的單字時,通常會用 CamelCase 來命名,在 Route 設定中使用 snake_case。

例如:
Controller:UserManagementController
Route就會是:user_management

OrderHistoryController -> order_history
ProductManagementController -> product_management
UserProfileController -> user_profile
CustomerSupportController -> customer_support
AccountSettingsController -> account_settings

resources / resource 的差別?

resources 和 resource 都用於自動生成一組 RESTful 路由,但兩者有幾個重要的不同點:

功能/特點 resources resource
資源類型 複數(例如:多篇文章) 單一(例如:profile)
ID 參數 包含(例如:/articles/1 不包含(例如:/profile
CRUD 操作 完整 不包括 index
生成的 route
index 有(GET /articles
new 有(GET /articles/new 有(GET /profile/new
create 有(POST /articles 有(POST /profile
show 有(GET /articles/:id 有(GET /profile
edit 有(GET /articles/:id/edit 有(GET /profile/edit
update 有(PATCH/PUT /articles/:id 有(PATCH/PUT /profile
destroy 有(DELETE /articles/:id 有(DELETE /profile

所以主要的差別就是:

  1. 使用情境
  2. resource 通常不包括 index
  3. resource 不帶 id

only / except:

限制 resources 有哪些 actions 。

resources :photos, only: [:index, :show]
resources :users, except: [:destroy]

不需要那麼多 CRUD 的連結嗎?那就用 only & except

巢狀式 Nested Route

resource & resources

兩者也可以相互搭配使用,例如在電商網站中,user 會有一個 profile,但有多個送貨地址:

resource :profile do
  resources :addresses
end

會產生一個巢狀 Nested Route,連結會長得像這樣:/profile/addresses
這也是 Nested Route 的基礎使用

namespace

將相關的 route 組織在一個 namespace 下,通常用於後台或管理介面,對 Controller、View 和 Route 名稱都有影響。

namespace :admin do
  resources :posts, :photos
end

連結會長這樣:/admin/posts/new `/admin/photos/new

scope :

namespace 類似,可以更自由產生 URL。

scope "/admin" do
  resources :posts
end

連結會長這樣:/admin/posts

scope & namespace

特性 namespace scope
影響 Controller、View 和 Route 名稱 僅 URL
Controller 命名 例如:Admin::PostsController 例如:PostsController
Route 帶前綴,例如 admin_posts 不改變,例如 posts
View 路徑 會在 app/views/admin/posts 會在 app/views/posts
靈活性 較低,主要用於邏輯隔離 高,可搭配 :module、:as
# 使用 scope with module 和 as
scope module: 'admin', as: 'admin' do
  resources :posts
end
# Controller 會是 Admin::PostsController,View 會在 app/views/admin/posts,
# Route 名稱會是 admin_posts,輔助方法就會是 admin_posts_path

連結樣貌會是:admin/posts

member:

在單一資源上設定額外的 Route。

resources :photos do
  member do
    get 'preview'
  end
end

會產生:photos/:id/preview

collection:

在集合資源上設定額外的 Route。

resources :photos do
  collection do
    get 'search'
  end
end

會產生:photos/search

shallow

簡化 nested resoureces 的 route。
例如:

resources :users do
  resources :books
end

這會生成以下的一些 routes:

  • 新增文章:/users/:user_id/articles/new
  • 顯示文章:/users/:user_id/articles/:id
  • 修改文章:/users/:user_id/articles/:id/edit

如果你加上 shallow: true,如:

resources :users do
  resources :articles, shallow: true
end

那麼,對於那些不需要父層資源 :id(在這裡是 users)來進行動作(通常是 :show, :edit, :update, :destroy),route 會變得更簡短:

  • 新增文章(仍然需要父資源):/users/:user_id/articles/new
  • 顯示文章(不需要父資源 id 來辨識):/articles/:id
  • 修改文章(不需要父資源 id 來辨識):/articles/:id/edit

總共會有這些 url:

HTTP 方法 URL 路徑 action 說明
GET /users index 列出所有 user
GET /users/new new 新增 user (的表單)
POST /users create 新增 user
GET /users/:id show 查看某 user
GET /users/:id/edit edit 編輯某 user (的表單)
PATCH/PUT /users/:id update 更新某 user
DELETE /users/:id destroy 刪除某 user
GET /users/:user_id/articles index 列出某 user 的所有文章
GET /users/:user_id/articles/new new 新增某 user 文章(的表單)
POST /users/:user_id/articles create 新增某 user 的文章
GET /articles/:id show 查看某文章(不需 :user_id
GET /articles/:id/edit edit 編輯某文章(的表單)(不需 :user_id
PATCH/PUT /articles/:id update 更新某文章(不需 :user_id
DELETE /articles/:id destroy 刪除某文章(不需 :user_id

總之 shallow = true,只有在真正需要父資源來辨認子資源的情況下,才會在 URL 中包含父資源。這不僅簡化了 URL,也更簡單在 Controller 中處理資源,不用多餘的資料庫查詢。

as:

自訂 route 的名稱。

resources :photos, as: 'images'

連結就會是 images/new
也會產生 images_path 的 helper
在其他的 view 或 controller 就要用 as 的 path

<%= link_to '新圖片', images_path %>
redirect_to images_path

concerns:

將共用的 route 集中管理。例如,如果你有 messages 和 articles 兩種資源,而它們都可以被評論,則你可能會有相似的 route 來處理這些評論。而使用 concerns 就可以將這些共用的 route 集中管理,減少重複。

concern :commentable do
  resources :comments
end

resources :messages, concerns: :commentable

這裡有一個 concern 叫做 :commentable。這個 concern 包含了一個子資源:comments。

接著,在 resources :messages 中使用 concerns: :commentable,這會將 :commentable concern 中的所有 route 規則應用到 messages 這個資源上。

會生成:
/messages/:message_id/comments (用於列出所有與特定訊息相關的評論)
/messages/:message_id/comments/:id (用於顯示、編輯或刪除一條與特定訊息相關的評論)

如果你有其他也可以被評論的資源,比如 articles,你也可以這麼做:

resources :articles, concerns: :commentable

articles 資源也會自動擁有相同的 comments 子資源 route

面試題

login_path &login_url 的差別?

分類 login_path login_url
路徑格式 生成的是相對路徑,例如 /login 生成的是絕對 URL,例如 http://www.example.com/login
使用場合 通常在同一個專案內的不同頁面之間導航時使用。 常用於需要完整 URL 的場合,例如在電子郵件模板或外部服務中。
環境 可變換,不依賴於特定的網域或協定。 通常包含主機名和協定,所以它是特定於一個環境。
設定選項 允許傳遞額外的參數來自定 route。 除了允許傳遞的參數外,還可以指定像是 :host, :port 等選項。

login_path

可使用參數

# 不帶任何額外參數
redirect_to login_path

# 帶有額外參數
redirect_to login_path(param1: "value1", param2: "value2")

會生成 /login?param1=value1&param2=value2

login_url 除了可使用參數,還可以指定 host, port, protocol

同樣,login_url 也可以接受參數,以及 :host, :port, :protocol 等選項。

# 帶參數
redirect_to login_url(param1: "value1", param2: "value2")

生成 http://your_default_host/login?param1=value1&param2=value2 的 URL。

redirect_to login_url(host: 'www.example.com', port: 3000)

生成 http://www.example.com:3000/login

組合使用

也可以組合使用這些選項:

redirect_to login_url(param1: "value1", host: 'www.example.com', port: 3000)

這會生成 http://www.example.com:3000/login?param1=value1

簡單來說,選擇使用哪一個主要取決於實際需求。

講解這段 code

Rails.application.routes.draw do 
  root 'pages#home'
    namespace :admin do 
      resources :urls do
        member do
          delete :reset_counter 
          get :report
        end 
      end
    end
  resources :users, only: [] do 
    collection do
      post :developer_apply 
    end
  resources :books, shallow: true 
  end
end
  1. Rails.application.routes.draw do ... end: 是設定 route 規則的地方,可以在 block 內使用各種方法(如 root, resources, namespace 等)來設定 route 。

  2. root 'pages#home': 設定根路徑(即網站的首頁)為 pages 控制器的 home 動作。

  3. namespace :admin do ... end: 有一個名為 admin 的 namespace。所有在這個 block 內的Controller 和 route 都會加上 /admin 前綴。

    • resources :urls do ... end: 在 admin namespace 下,創建一組 RESTful 規則給 urls 資源。

    • member do ... end: 針對單一 url 資源指定兩個動作:

      • delete :reset_counter: 刪除 method,用於 :reset_counter。
      • get :report: 讀取 method,用於報告(report)。
  4. resources :users, only: [] do ... end: users 資源的 route ,但 only: [] 限制了沒有任何 method(如 :index, :show 等),所以這裡主要是為了使用 nested route。

    • collection do ... end: 可以在整個 users 的集合資源上動作,不會對特定的 user 進行操作。

      • post :developer_apply: 新增 method ,使用於 users 資源的集合,:developer_apply 是 UsersController 的一個 action。= post 'developer_apply', to: 'users#developer_apply'
    • resources :books, shallow: true: 在 users 資源內有一個 books 資源,並設定為shallow,books 不用總是需要指定父資源(user)就能對子資源(book)進行操作,有助於避免不必要的資料庫查詢。假設是 show/update/destory 頁面 route 都會長這樣:/books/:id

如果沒有 shallow: true,一個特定的書的 show 頁面的可能會像這樣:
/users/:user_id/books/:id

CSRF 是什麼?可以用來解決什麼?

CSRF(Cross-Site Request Forgery,跨站請求偽造)是一種網路安全攻擊手法,攻擊者利用使用者已登入的狀態,在不知情的情況下發送偽造的請求到目標網站。這樣可以讓攻擊者執行不當的操作,如更改密碼、轉帳等。

防禦 CSRF 的一種常見方式是使用一種稱為「反偽造令牌」(Anti-Forgery Token)的機制。當使用者在一個表單頁面時,服務端會生成一個隨機的令牌,並將其嵌入表單中。當表單提交時,服務端會檢查這個令牌是否與先前發出的令牌可以對上。只有在令牌相呼應的情況下,請求才會被處理。

RESTful 是什麼?

RESTful(Representational State Transfer)是一種軟體架構風格,常用於網路應用程式和服務的設計。它使用標準的 HTTP 方法(如 GET、POST、PUT、DELETE 等)來執行 CRUD(Create、Read、Update、Delete)操作。

在 RESTful 架構中,資源(Resources)是一個核心概念,每個資源都有一個唯一的 URL。透過不同的 HTTP 方法和這些 URL 的組合,你可以執行不同的操作。例如:

  • 使用 GET 來讀取資料
  • 使用 POST 來新增資料
  • 使用 PUT 來更新已存在的資料
  • 使用 DELETE 來刪除資料

皆大歡喜
(喘)


上一篇
vol. 15 Rails 的導航員:routes.rb 「請往這邊走哦!」(上)
下一篇
vol. 17 Rails 來 new 一下!熟悉一下專案流程與指令吧
系列文
富士大顆30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言