在线观看不卡亚洲电影_亚洲妓女99综合网_91青青青亚洲娱乐在线观看_日韩无码高清综合久久

鍍金池/ 教程/ Ruby/ 2.3 深入路由(routes)
寫在后面
寫在前面
第六章 Rails 的配置及部署
第四章 Rails 中的模型
4.4 模型中的校驗(Validates)
1.3 用戶界面(UI)設(shè)計
6.5 生產(chǎn)環(huán)境部署
3.2 表單
4.3 模型中的關(guān)聯(lián)關(guān)系(Relations)
4.5 模型中的回調(diào)(Callback)
第五章 Rails 中的控制器
4.2 深入模型查詢
5.2 控制器中的方法
6.2 緩存
3.4 模板引擎的使用
6.4 I18n
第一章 Ruby on Rails 概述
6.6 常用 Gem
1.2 Rails 文件簡介
2.2 REST 架構(gòu)
2.3 深入路由(routes)
第三章 Rails 中的視圖
6.3 異步任務(wù)及郵件發(fā)送
第二章 Rails 中的資源
3.3 視圖中的 AJAX 交互

2.3 深入路由(routes)

概要:

本課時詳細(xì)解讀如何設(shè)置復(fù)雜情況下的路由(routes),以及路由文件中常用方法。

知識點:

  1. routes 定義
  2. 嵌套(nested)
  3. namespace
  4. concern
  5. 參數(shù)
  6. 測試

正文

2.3.1 定義路由(routes)

上一節(jié),我們講了 Rails 通過 routes,來實現(xiàn) REST 風(fēng)格的架構(gòu)。本節(jié)我們講詳細(xì)介紹下如何使用 routes,定義我們想要的地址(URL)。

我們先為項目,創(chuàng)建一個 controller:

rails g controller home index welcome about contact

在我們專門講解 controller 前,先簡單解釋下:

  • g 是 generate 的縮寫,我想你已經(jīng)在 2.1.1 里看到了。
  • controller,說明我們創(chuàng)建的是一個 controller,也可以是 model。
  • home 是 controller 的名字。
  • index... 和其他幾個名字,是 controller 中的方法,并且會自動創(chuàng)建對應(yīng)的 views 文件。

好了,我們在它上面做一些簡單的例子,打開routes,你可以看到它已經(jīng)增加了幾個定義:

get 'home/index'
get 'home/welcome'
get 'home/about'
get 'home/contact'

我們訪問 http://localhost:3000/home/index 可以看到它。但是,如果我想訪問 http://localhost:3000/ 就進入到 index 方法呢?

get '/', to: 'home#index'
get '/welcome', to: 'home#welcome'

如上,我們自己定義了訪問和方法之間的對應(yīng)關(guān)系。其實我們更經(jīng)常使用 root 來定義地址:

root 'home#index'

運行 rake routes,我們可以看到

Prefix Verb URI Pattern Controller#Action
home_contact GET /home/contact(.:format) home#contact
GET / home#index
welcome GET /welcome(.:format) home#welcome
root GET / home#index

我們也可以用其他的 Verb 來定義非 GET 請求,比如

put '/haha', to: 'home#index'
delete '/hehe', to: 'home#index'
patch '/wawa', to: 'home#index'

routes 中我們可以拋開資源的要求(非 REST 風(fēng)格),直接設(shè)定一個訪問地址:

get '/something/:controller/:name/:action'

這時我們訪問 http://localhost:3000/something/home/aaa/index 也會進入到 'home#index' 中,因為 Rails 會這樣解析:

  • something 是個前綴
  • 訪問的 controller 是 home
  • name 參數(shù)是 aaa
  • 方法是 index

建議你看一下的終端:

Started GET "/something/home/aaa/index" for ::1 at 2015-02-19 17:10:26 +0800
Processing by HomeController#index as HTML
  Parameters: {"name"=>"aaa"}

Rails 已經(jīng)將你的請求轉(zhuǎn)移到對應(yīng)的 controller 中了。

如果一個地址,即可以接收 post 請求,也可以接收 get 等請求,我們可以使用 match 方法:

match ':controller/:action/:id', via: [:get, :post]

提示:在開發(fā)(development)環(huán)境中,修改 routes 是不需要重啟服務(wù)的。

2.3.1.1 擴展 resources

前面我們已經(jīng)定義了一個 resource :products,這在實際開發(fā)中還是不夠的,比如,一個 Product 下如果查看評論,比如,顯示賣的最好的十個 Products:

resources :products do
  collection do
    get :top # 排行榜功能
  end
  member do
    post :buy # 添加到購物車
  end
end

運行 rake routes 可以看到:

Prefix Verb URI Pattern Controller#Action
top_products GET /products/top(.:format) products#top
buy_product POST /products/:id/buy(.:format) products#buy

不同的是,collection 用于 products 中增加方法,member 給具體一個 product 增加方法。

補充一點,我們可以在一行里,定義多個 resources,比如:

resources :photos, :books, :videos

雖然方便,但不夠靈活,實踐中還是要按照需求調(diào)整的。

我們在這里提出了兩個功能需求:top 排行榜,和添加到購物車。這里我使用 trello.com 來記錄這兩個需求。

http://wiki.jikexueyuan.com/project/rails-practice/images/chapter_2/trello.png" alt="" />

我在“計劃”里增加了一個 card,在 checklist 中記錄了這兩個需求。當(dāng)我們開始功能開發(fā)的時候,可以將 card 拖動到“進行中”,當(dāng)我們完成一個功能的時候,可以在 checklist 的項目前打一個√,當(dāng)我們完成一個 card 的任務(wù)后,可以講 card 拖動到“完成”中。

Rails 被很多開發(fā)團隊使用,在一些開發(fā)團隊中,經(jīng)常會提到敏捷開發(fā),trello 是一個很好的敏捷開發(fā)工具,可以方便的管理我們的日常工作,和記錄項目進展?fàn)顟B(tài)。

2.3.1.2 單個資源 resource

resource :settings
resource :profile

這是設(shè)定一個單數(shù)資源的方法,項目里,哪些是單數(shù)呢?比如系統(tǒng)設(shè)定,比如當(dāng)前用戶的個人信息,運行 rake routes 可以看到,它是沒有 :id 這個參數(shù)的。

在這個例子里,我們還未給 settings 和 profile 創(chuàng)建 controller 和 view,不過這不妨礙 routes 產(chǎn)生我們想要的地址。

2.3.1.3 選擇方法

resources 給我們創(chuàng)建了七個方法,但是不見得我們都要用到,為了代碼的整潔[1],我們可以做一些排除:

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

only 表示我們需要的方法,except 表示我們不需要的方法。通常,我們的確會像上面這么做,比如我們的網(wǎng)站只提供用戶(User)的列表和查看功能,而管理功能(增刪改)要在管理界面進行,而它的地址一般不會是 /users/1/edit 這樣,而是 /admin/users/1/edit。

[1]這是個人癖好,有的人的確不愿意這么做,不過 Rails 給了我們讓項目變得“整潔”的方法。

2.3.1.5 地址解析的輔助方法

剛才,我們講到了 _path 這個后綴,Rails 還有一個 _url。

地址 結(jié)果
products_path '/products'
products_url 'http://localhost:3000/products'

_path_url 是 routes 的輔助方法,我們在下一章將詳細(xì)介紹。

2.3.2 嵌套的路由(routes)

在我們定義資源的時候,有時候一個資源會有它的子資源,比如一個商品(product)會有多個商品種類(variants),當(dāng)我們購買一個商品的時候,也需要選擇哪個種類,比如T恤的種類氛圍尺碼,而每一個尺碼有不同的價格。

這時該如何定義 routes 呢?

resources :products do
  resources :variants
end

運行 rake routes,可以看到一個商品(product)下,增加了這些routes:

Prefix Verb URI Pattern Controller#Action
product_variants GET /products/:product_id/variants(.:format) variants#index
POST /products/:product_id/variants(.:format) variants#create
new_product_variant GET /products/:product_id/variants/new(.:format) variants#new
edit_product_variant GET /products/:product_id/variants/:id/edit(.:format) variants#edit
product_variant GET /products/:product_id/variants/:id(.:format) variants#show
PATCH /products/:product_id/variants/:id(.:format) variants#update
PUT /products/:product_id/variants/:id(.:format) variants#update
DELETE /products/:product_id/variants/:id(.:format) variants#destroy

我們?yōu)?variants 也使用一下 scaffold

rails g scaffold variant product_id:integer price:decimal size

在運行 rails s 前,記得要更新數(shù)據(jù)庫:

rake db:migrate

記得,我們應(yīng)該刪除 routes 中自動添加的 resources :variants,因為我們不需要在 http://localhost:3000/variants 下看到它,不是么?我們可以在每一個商品(Product)頁面,比如:http://localhost:3000/products/1 中看到它了。

2.3.3 路由中的命名空間(namespace)

接下來我們說兩個項目中經(jīng)常會見到的情形。

一個項目,肯定要有 admin 的,我們?nèi)绾伟压芾淼刂范挤诺?http://localhost:3000/admin/ 這個目錄下?

namespace :admin do
  resources :products
end

這時,這樣就足夠了,不過,它所使用的 controller 和 view 是在 admin 這個文件夾下面的,多說一點,它的controller 代碼也是在 Admin 這個 module 下的。如果你還對 Ruby 的 module 不熟悉,是時候補充下了。

它的代碼是:

class Admin::ProductsController < ApplicationController
  ...
end

這里,我們反過來想,能否讓 /admin/articles 下的代碼去訪問 ArticlesController ?這里不再是 Admin:: 開頭的。這時我們用到 scope

scope '/admin' do
  resources :articles
end

對于 admin 下的資源管理,可以試試 active admin 這個 Gem。

https://github.com/activeadmin/activeadmin

2.3.4 concern 方法

再來看一個讓 routes 更簡潔,也很實用的方法。

concern :commentable do
  resources :comments
end

concern :image_attachable do
  resources :images, only: :index
end

resources :messages, concerns: :commentable
resources :articles, concerns: [:commentable, :image_attachable]

concern 定義好的資源,可以被其他 resource 里多次引用。

Rails 的原則之一:不要重復(fù)自己(Don't Repeat Yourself)

2.3.5 有用的參數(shù)

:as 別名

如果再上面地址后面,加上 as 參數(shù),會直接創(chuàng)建一個別名的地址,比如

get 'home/welcome', as: :welcome

之前,我們在 views 或者 controller 中,連接到或跳轉(zhuǎn)到 /home/index 可以這么寫:home_welcome_path,增加了 :as 后,就變成了 welcome_path 了。好處是,如果我們某一天更改了對應(yīng)的 action 甚至 controller,這個寫法 welcome_path 是不會變的,而只需要改動 routes 中的定義。

在定義 routes 時,要注意不要重復(fù)定義,因為:寫在上面的會覆蓋下面的。比如:

get 'home/index', to: 'home#welcome'
get 'home/index'

訪問 http://localhost:3000/home/index 會進入到 welcome 方法中。

下面在介紹幾個實用的參數(shù)。

shallow

這時 Rails 4 中增加的一個很實用的參數(shù)。

resources :products do
  resources :comments, shallow: true
end

它把 index、new 和 create 方法保留在了 products/:id 這個資源下,而把其他方法,重新放回到 /comments 下。這樣的考慮是避免過多的實用嵌套 routes,并且讓代碼更簡潔。

constraints

我們可以給 routes 建立約束(Constraints),比如:

get 'photos/:id', to: 'photos#show', constraints: { id: /[A-Z]\d{5}/ }

這時,id 為 A 到 Z 開頭,且后面為5位數(shù)字的 id,才符合路由條件,轉(zhuǎn)入到 show 方法。而 products/A123456 將會提示 No route matches

2.3.6 Rspec 測試

通常,我們會在 controller 中寫上測試,不過 Rspec 也為我們提供了測試路由的方法。我們在 spec 下建立一個routing 文件夾,并且添加一個 products_routing_spec.rb 的文件:

RSpec.describe ProductsController, type: :routing do
  describe "routing" do

    it "routes to #index" do
      expect(:get => "/products").to route_to("products#index")
    end
    ...

我們?yōu)樗鼏为氝\行測試,因為scaffold 自動為我們添加的測試代碼,我們將在后面的章節(jié)完成:

% rspec spec/routing/products_routing_spec.rb

routes 測試的參考,可以查看這里。

好了,本章結(jié)束了,本節(jié)的內(nèi)容多來自 Rails 手冊中的 Rails Routing from the Outside In,你也可以找到在 這里 找到本章調(diào)試的代碼。下一章,我們將開始完成 shop 的頁面(views)代碼,希望它可以讓你更加了解 Rails。