インドカレーファンクラブ

パソコン、カメラ

【Rails】Routingの勉強

全体的な話

ルーティングは/config/routes.rbで制御する
ASP.NETのようにController側からAttributeで制御することはなさそう

現在のルーティングの一覧はrails routesで確認できる

記法については具体的な記述例をコメントと共に見るのが早いと思う

基本的なルーティング

Rails.application.routes.draw do
    # root用のルーティング
    # sample_controllerのindex()を実行
    root "sample#index"

    # GET /sample/new/
    # sample_controllerのnew()を実行
    get "sample/new" => "sample#new"
    # POST /sample/
    # sample_controllerのcreate()を実行
    # =>でもto:でもどっちでもいい
    post "sample", to: "saple#create"
end

これをもってrails routesをすると、 以下のように表示される

    Prefix Verb URI Pattern           Controller#Action
      root GET  /                     sample#index
sample_new GET  /sample/new(.:format) sample#new
    sample POST /sample(.:format)     saple#create

ここで出てきた(.:format)というものについて、
まずRailsのルーティングでは()で囲まれている部分は所謂Optionalなもの
なので上記の/sample(.:format)/sample, /sample.json, sample.htmlにマッチする

(.:format)じゃなくてHTMLだけにしたい時は色々指定する方法があるみたい
https://stackoverflow.com/questions/4579652/disable-format-routes-in-rails3

ついでにトレイリングスラッシュの有無はapplication.rbで以下のように設定すればいい

config.action_controller.default_url_options = { :trailing_slash => true }

参考:
https://qiita.com/naokazuterada/items/5f4bbf82f1c99222dc53

パラメータを渡す

Rails.application.routes.draw do
    # 例えば [GET /user/11] のようなリクエストを送ると
    # user_controllerのshow()を実行し、
    # showにはパラメータとして{id: '11'}が渡される
    get "user/:id" => "user#show"
    # GET /photo/01/234/
    # photo_controllerのshow()を実行
    # paramは {userid: '01', photoid: '234'}
    get "photo/:userid/:photoid", to: "photo#show"

    # default
    get "user/:id" => "user#show", defaults: {id: '111'}

    # matchとvia
    # show()に対してGET, POSTの両方をマッチさせる
    match "user", to: "user#show", via: [:get, :post]

    # constraints
    get "user/:id" => "user#show", constraints: {id: /[0-9]{8}/ }
end

リソースベースでのルーティング

以下のサイトを見るのがわかりやすい
重要そうなとこだけ書き出す

リソースベースのルーティング (以下リソースルーティング) を使うことで、リソースベースで構成されたコントローラに対応する共通のルーティングを手軽に宣言できます。リソースフルなルーティングを宣言することで、コントローラのindex、show、new、edit、create、update、destroyアクションを個別に宣言しなくても1行で宣言が完了します。 https://railsguides.jp/routing.html#%E3%83%AA%E3%82%BD%E3%83%BC%E3%82%B9%E3%83%99%E3%83%BC%E3%82%B9%E3%81%AE%E3%83%AB%E3%83%BC%E3%83%86%E3%82%A3%E3%83%B3%E3%82%B0-rails%E3%81%AE%E3%83%87%E3%83%95%E3%82%A9%E3%83%AB%E3%83%88

簡単にまとめると、リソースルーティングを使えば特定のリソースに関連するCRUD処理に対応するルーティングが一発で設定できるよ、というような感じ

このルールに則ればアクション名が散らないので確かに分かりやすいかも
(≒実質的に命名規則が定められる)
後述するcreateとかnewとか、あるいはgenerate, addあたりの語句は事実混ざりやすいし

(でもそんなルーティング一式全部定義することある?)

複数形リソース (resources)

複数存在するリソースに対してのルーティングはresourcesキーワードをもってルーティングを行う

上述のサイトのphotosでの例を実際に記述してrails routesをするとこうなる

Rails.application.routes.draw do
    resources :photos
end
    Prefix Verb   URI Pattern                Controller#Action
    photos GET    /photos(.:format)          photos#index
           POST   /photos(.:format)          photos#create
 new_photo GET    /photos/new(.:format)      photos#new
edit_photo GET    /photos/:id/edit(.:format) photos#edit
     photo GET    /photos/:id(.:format)      photos#show
           PATCH  /photos/:id(.:format)      photos#update
           PUT    /photos/:id(.:format)      photos#update
           DELETE /photos/:id(.:format)      photos#destroy

どのアクションが何をするものなのかは上記サイトを見るとわかりやすい
暗記のようなものなので慣れだと思う

単数形リソース (resource)

同様に単体でしか存在しないリソースに対してはresourceキーワードをもってルーティングを行う

以下の例はprofileというリソースでの例
ログイン中のユーザのprofileであれば単一みたいな...

Rails.application.routes.draw do
    resource :profile
end
      Prefix Verb   URI Pattern             Controller#Action
 new_profile GET    /profile/new(.:format)  profiles#new
edit_profile GET    /profile/edit(.:format) profiles#edit
     profile GET    /profile(.:format)      profiles#show
             PATCH  /profile(.:format)      profiles#update
             PUT    /profile(.:format)      profiles#update
             DELETE /profile(.:format)      profiles#destroy
             POST   /profile(.:format)      profiles#create

複数形の時と違ってindexがなくなっていることと、IDによる指定がなくなっているのがわかる
単一のリソースであってその存在が保証されているならば、newとdeleteは要らない気がする

アクションを絞る (only)

以下のようにonlyで絞れる

Rails.application.routes.draw do
    resources :photos  only: [:index, :show]
    resources :profile only: [:show]
end

アクションを追加する (member)

以下のようにアクションを追加できる

Rails.application.routes.draw do
  resources :photos do
    member do
      get 'preview'
      get 'hoge'
    end
  end
end

追加するアクションが一つならこの記法でもOK

Rails.application.routes.draw do
  resources :photos do
    get 'preview', on: :member
  end
end

scope/namespace/module

どれもごっちゃになりそう
この記事が綺麗にまとまってるので見たほうがはやい
https://qiita.com/ryosuketter/items/9240d8c2561b5989f049

概要だけ引用

URL ファイル構成
scope 指定のパスにしたい 変えたくない
namespace 指定のパスにしたい 指定のパスにしたい
module 変えたくない 指定のパスにしたい

ルーティング用ヘルパー

ルーティングとして定義したURLやPATHはいい感じに呼び出せる

ルーティング

Rails.application.routes.draw do
  root "sample#index"
  get "test" => "test#index"
  get "hoge" => "hoge#index", as: :huga #asを付けるとhelperの名称が変わる
  resources :photos
  resource  :profile
end

定義

            Prefix Verb   URI Pattern                        Controller#Action
              root GET    /                                  sample#index
              test GET    /test(.:format)                    test#index
              huga GET    /hoge(.:format)                    hoge#index
            photos GET    /photos(.:format)                  photos#index
                   POST   /photos(.:format)                  photos#create
         new_photo GET    /photos/new(.:format)              photos#new
        edit_photo GET    /photos/:id/edit(.:format)         photos#edit
             photo GET    /photos/:id(.:format)              photos#show
                   PATCH  /photos/:id(.:format)              photos#update
                   PUT    /photos/:id(.:format)              photos#update
                   DELETE /photos/:id(.:format)              photos#destroy
       new_profile GET    /profile/new(.:format)             profiles#new
      edit_profile GET    /profile/edit(.:format)            profiles#edit
           profile GET    /profile(.:format)                 profiles#show
                   PATCH  /profile(.:format)                 profiles#update
                   PUT    /profile(.:format)                 profiles#update
                   DELETE /profile(.:format)                 profiles#destroy
                   POST   /profile(.:format)                 profiles#create

Controller

class SampleController < ActionController::Base
    protect_from_forgery with: :exception
    def index
        @helpers = {
            :root_url  => root_url,
            :root_path => root_path,
            :test_url  => test_url,
            :test_path => test_path,

            # hogeはroutingで as: :hugaとしている
            # "hoge_url"  => hoge_url,
            # "hoge_path" => hoge_path,
            :huga_url  => huga_url,
            :huga_path => huga_path,

            :new_photo_url  => new_photo_url,
            :new_photo_path => new_photo_path,
            # photo_**ではダメ
            :photos_url  => photos_url,
            :photos_path => photos_path,

            :new_profile_url  => new_profile_url,
            :new_profile_path => new_profile_path,
        }
    end
end

html.erb

<% @helpers.each do |key, value| %>
    <%= key %>:
    <%= value %>
    <br/>
<% end %>

出力

root_url: http://localhost:3000/
root_path: /
test_url: http://localhost:3000/test
test_path: /test
huga_url: http://localhost:3000/hoge
huga_path: /hoge
new_photo_url: http://localhost:3000/photos/new
new_photo_path: /photos/new
photos_url: http://localhost:3000/photos
photos_path: /photos
new_profile_url: http://localhost:3000/profile/new
new_profile_path: /profile/new

基本的にはpathを使い、リダイレクトの場合のみurlを使うとのこと

参考: