読者です 読者をやめる 読者になる 読者になる

Blank?=False

「呉下の阿蒙にあらず」をモットーにしたITエンジニアの日々

Railsのリソースとルーティングについて

f:id:stonebeach-dakar:20160530220309p:plain

今回はRailsの基礎の1つ、リソースについて書いていきます。

リソースとは?

Railsにおけるリソースについて、基礎Ruby on Railsでは以下のように書かれています。

Railsにおけるリソースとは、コントローラが扱う対象に名前をつけたものです。

コントローラが扱うものといえばモデルだな!と思ったら、実際のところはセッション等も扱うので、モデルだけとは限らないと書かれていました。

つまり、モデル≒リソース,モデルはリソースの1種として捉えるのが良さそうです。

モデルの他のリソースとしては、セッション,画像,ファイル等が考えられます。

f:id:stonebeach-dakar:20160714203559p:plain

リソースのルーティングとは

ルーティングとは、動きだけ考えると色々なURIを作るやつというイメージ。
コレをちゃんと説明すると、それぞれのリソースに適した動作ができるURIを生成し、コントローラのアクションとのマッピングを行うというのがルーティングの役目、と自分は解釈しています。

なので、REST的に考えると、有るリソースに対して、表示する、作成する、編集する、削除する、のそれぞれの機能にあったユニークなURIを作るわけです。

例えば、ユーザーというリソースがあれば、表示するshow,新規作成するnew, 編集するedit, 削除するdestroyの4つのURIを作るのがルーティングです。
つまり、URIというリソースの通り道を作るわけですね。routeだけに。

このルーティングを行う場合、routes.rbには以下のように記述します。

Rails.application.routes.draw do
  resources :user
end

この記述をすることで、以下の様なルーティングができるわけです。
(今回、テスト用のRails5.0でやっていますので、Rails4~の方はrails routesrake routesに置き換えてください)

$ rails routes
   Prefix Verb   URI Pattern               Controller#Action
     root GET    /                         users#index
    users GET    /users(.:format)          users#index
          POST   /users(.:format)          users#create
 new_user GET    /users/new(.:format)      users#new
edit_user GET    /users/:id/edit(.:format) users#edit
     user GET    /users/:id(.:format)      users#show
          PATCH  /users/:id(.:format)      users#update
          PUT    /users/:id(.:format)      users#update
          DELETE /users/:id(.:format)      users#destroy

単数リソースと複数リソース

先ほどの、resources :user複数リソースです。
この他に、単数リソースというものがあります。

先ほどの、userを単数リソースとして宣言する場合、コードは以下のようになります。

Rails.application.routes.draw do
  resource :usr
end

生成されるURIパターンは以下のようになります。

$ rails routes
   Prefix Verb   URI Pattern          Controller#Action
     root GET    /                    users#index
     user POST   /user(.:format)      users#create
 new_user GET    /user/new(.:format)  users#new
edit_user GET    /user/edit(.:format) users#edit
          GET    /user(.:format)      users#show
          PATCH  /user(.:format)      users#update
          PUT    /user(.:format)      users#update
          DELETE /user(.:format)      users#destroy

どうちがうの?

users#showを比べてみます。

複数リソース 単数リソース
URI Pattern /users/:id(.:format) /user/(.:format)
Controller#action users#show users#show

見てわかる大きな違いはURI Patternで複数リソースには:idがあることです。
この:idはユーザーのIDです。つまり、複数いるユーザーのうち1人ということを表しています。
単数リソースでは:idはありません。なのでユーザーは1人しかいないということです。

このように必ず1つしかないリソースのルーティングをするときに、単数リソースを使います。

例えば、モデルはUsersを使うんだけどログインしているユーザーのアカウントだけを扱うリソースaccountが欲しい!という時に単数リソースが活用できます。

どこでつかうの?

最初に話にあげたセッションや、次の話になるネストされたリソース、先ほどのaccountリソース等で使います。
とは言うものはRailsではそこまで多くはないと思います。

ちなみに、400行近いRedimineのroutes.rbを見てもresourceは1つしかありません。。

リソースのネスト

Rails、というよりもほぼすべてのアプリケーションのデータは親子関係(階層関係)を持つことがほとんどです。
例えば、ExcelのワークブックはWorkbookというデータクラスの下にWorksheetが有り、更にその下にCellが有ります。

Railでも、has_many,has_one等でリソースの親子関係を作ることが有ります。
例として、「複数のユーザーがいて、それぞれのユーザーは、複数の本を持つ」という親子関係をルーティングしてみます。

イメージとしては、こういう感じです。
f:id:stonebeach-dakar:20160714220255p:plain

コードとしては以下のようになります。

Rails.application.routes.draw do
  resources :users do
    resources :books
  end
end

このコードが生成するURIパターンは、以下のようになります。

$ rails routes
 Prefix Verb   URI Pattern                              Controller#Action
    user_books GET    /users/:user_id/books(.:format)          books#index
               POST   /users/:user_id/books(.:format)          books#create
 new_user_book GET    /users/:user_id/books/new(.:format)      books#new
edit_user_book GET    /users/:user_id/books/:id/edit(.:format) books#edit
     user_book GET    /users/:user_id/books/:id(.:format)      books#show
               PATCH  /users/:user_id/books/:id(.:format)      books#update
               PUT    /users/:user_id/books/:id(.:format)      books#update
               DELETE /users/:user_id/books/:id(.:format)      books#destroy
         users GET    /users(.:format)                         users#index
               POST   /users(.:format)                         users#create
      new_user GET    /users/new(.:format)                     users#new
     edit_user GET    /users/:id/edit(.:format)                users#edit
          user GET    /users/:id(.:format)                     users#show
               PATCH  /users/:id(.:format)                     users#update
               PUT    /users/:id(.:format)                     users#update
               DELETE /users/:id(.:format)                     users#delete

books#showURIパターンを見ると、:user_idで特定のユーザーを示し、その下に/books/:idでそのユーザーが持つ特定の本を表示する、という風にURIが作られているのがわかると思います。
こういうわかりやすいURIを作るのがRESTなのです。

RESTの一部を無効化する

index,show,edit,deleteがすべてできることをRESTFulと言いますが、この内幾つかの項目は必要ないこともあります。
例えば、ネストしたリソースはindex,showだけできればいい、もしくはdelete,destroyはいらない、ということは良く有ります。

そういうときは、only,exceptオプションを使うことで実現できます。

index, showアクションのみ

Rails.application.routes.draw do
  resources :users, only:[ :index, :show ]
end
Prefix Verb URI Pattern          Controller#Action
  Prefix Verb URI Pattern          Controller#Action
 users GET  /users(.:format)     users#index
  user GET  /users/:id(.:format) users#show

delete,destroy以外のアクション

Rails.application.routes.draw do
  resources :users, except: [:delete, :destroy]
end
   Prefix Verb  URI Pattern               Controller#Action
    users GET   /users(.:format)          users#index
          POST  /users(.:format)          users#create
 new_user GET   /users/new(.:format)      users#new
edit_user GET   /users/:id/edit(.:format) users#edit
     user GET   /users/:id(.:format)      users#show
          PATCH /users/:id(.:format)      users#update
          PUT   /users/:id(.:format)      users#update

いつ使うの?

例えば、セッションのリソースでは、showupdateも必要ありませんよね。作る、廃棄する、の2つだけで十分です。
こういう時に、only:[ :create, :destroy ]の2つのアクションだけを持つリソースを作れます。

また、ネストしたリソースでは、ユーザーのアカウント画面では新規作成と削除はできないといった事が必要になります。
そういった時に使うことができます。

参考文献

改訂3版 基礎 Ruby on Rails 基礎シリーズ

改訂3版 基礎 Ruby on Rails 基礎シリーズ

Ruby on Rails 4 アプリケーションプログラミング

Ruby on Rails 4 アプリケーションプログラミング