Railsルーティングを学ぶ①

クラスに新しいメソッドを自分で定義するのではなく、7つのメソッドのみ定義した方がスパゲッティコードになりづらいそう。

まだまだルーティングに関して理解が浅いため、今回はルーティングの学習を行っていきたい。

そもそものRailsルーティングの目的

Railsルーターは受け取ったURLを認識し、適切なコントローラ内アクションやRackアプリケーションに割り当てます。ルーターは、ビューでこれらのパスやURLを直接ハードコードすることを避けるためにパスやURLを生成することもできます。

Railに乗った開発を進めていくために必要。

URLを作成する書き方

「ボタンを押した際に次の画面に値を渡す」ようなアクションを作成したい場合を考える。

例えば下記のようなルーティングがあるとする。

get '/students/:id', to: 'students#show', as: 'student'

そして、アプリケーションのコントローラに以下のコードがあるとする。

@student = Student.find(params[:id])

上記に対応するビューは以下の通り。

<%= link_to 'Student Record', student_path(@student) %>

生成されるHTMLは以下の通り

<a href ="/patient">Patient record</a>

リンクをクリックするときや、ボタンをクリックして次の画面に遷移するときにaタグやbuttonタグがある。

その際に、遷移先を指定できるのが

<%= link_to 'Student Record', student_path(@student) %>

student_path(@student)部分になる。

これは、student#showに@studentにある値を渡していることを指している。

(@student)を添えることで、どのidの生徒情報に遷移すればいいのかを指定することができている。

リソースルーティング

毎回getやpostを直接指定してルーティングを作成するのは骨が折れる。railsはその手間をリソースフルなルーティングを使うことで簡単に省いてくれる。

ソースフルなルーティングを宣言することで、コントローラのindex、show、new、edit、create、update、destroyアクションを個別に宣言しなくても1行で宣言が完了できる。便利〜

Railsのリソースフルルーティングでは、(GET、PUTなどの) 各種HTTP動詞 (verb) と、コントローラ内アクションを指すURLが対応付けられます。1つのアクションは、データベース上での特定のCRUD (Create/Read/Update/Delete) 操作に対応付けられるルールになっています。

例えば下記のようなルーティングが定義されているとする。

resources :optimes

そこうすることでアプリケーション内に以下の7つのルーティングが作成され、いずれもFruitesコントローラに対応付けられることになる。

Untitled

1つに特定できるアクションはidが付く

上記7つのルーティングで、:idがついているパスとそうでないパスがあることに気づく。通常:idがパスは、前のページからparams[:id]で値を受け取っている。つまり、idを指定することができるアクションには:idが付くと言い換えることができる。

id有: show,edit,update,destroy

id無: index,new,create

名前空間

ある画面から次の画面に遷移するとき、名前空間が使われていることがよくある。namespaceと同じような挙動をするのがscopeとmodulemodule似て非なるものなので、以下のようにまとめた。

scope

blog配下にarticlesが入る。PATHに関してはnamespaceと同じ

scope :blog do
    resources :articles
  end

Controller
article#index

PATH
/blog/articles

namespace

PATH,Controllerの両方ともblogにネストされている。

namespace :blog do
    resources :articles
  end

Controller
blog/article#index

PATH
/blog/articles

module

Controllerのみがネストされている

**scope** module: :blog do
    resources :articles
  end

Controller
blog/article#index

PATH
/articles

ネストは浅い方がいい

上記のように、has_manyやbelongs_toで紐づけられたオブジェクト同士はまだ浅いネストの場合、かろうじて読むことができる。だが、子オブジェクトが増えるにつれてネストが深くなっていき、可読性の低いルーティングが出来上がってしまう。

例えば下記のような名前空間ルーティングがあるとする

resources :sports do
  resources :soccers do
    resources :balls
  end
end

このような深いリソースだと、下記のようにみづらいコードが出来上がってしまう。

/sports/1/soccers/2/balls/3

前述したような深いネストを避けるひとつの方法として、コレクション (index/new/createのような、idを持たないアクション) だけを親のスコープの下で生成するという手法がある。

resources :articles do
  resources :comments, only: [:index, :new, :create]
end
resources :comments, only: [:show, :edit, :update, :destroy]

これにより、articles/:id/comments/:idのような複雑なネストを回避することができた。

#生成されるパス
#上段
articles/comments/
#下段
comments/:id/

ちなみに:shallowオプションを使うと下記のように簡単な記述にすることができる。

resources :articles do
  resources :comments, shallow: true
#shallow: trueにするだけで、idのある無しを振り分けてくれる。
end

Rails のルーティング - Railsガイド

DHHはどのようにRailsのコントローラを書くのか | POSTD

Rule of three (computer programming) - Wikipedia

Doctrine