寝て起きて寝て

プログラミングが出来ない情報系のブログ

Railsのルーティング(2)~RESTfulのカスタマイズ~

今回はresources/resourceメソッドの各種オプションを活用し、予め決められたマッピングルールをカスタマイズできる方法を連々書いていく

ルートパラメータの制約条件

例えばIDに3桁の数字を入れさせたくない場合やそのIDを入れられると困る場合などに使う。 (あとは予め渡される値がわかっている場合とか)

このように制限を儲けたい場合は「constraints」オプションをルートティングに記述してあげる

構文的には

パラメータ名: 正規表現パターン

の形式

例:

Railbook::Application.routes.draw do
  resources :book, constraints:{id: /[0-9]{1,2}/}
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
end

これはbooksのリソースのidパラメータに対して「0~9の1~2桁の数値のみ適用」という設定をしている。

この条件に反したIDを入力した場合には

Routing Error
No route matches [GET] "/books/10000"

というエラーが表示される

同一の制約条件を複数のリソースに付けたい場合には以下のように記述する

constraints(id: /[0-9]{1,2}/)do
resources :books
resources :reviews
end

といったように記述する

正規表現では表現できない複雑な制約の定義

例えば現在の時刻によってルーティングを有効/無効を判定したい場合に使う

このような複雑な制約の定義をする場合 /modelsフォルダに作成する

9~18時の間だけルーティングを有効にし、それ以外の時間帯でのアクセスを拒否するプログラムを作る

/model/TimeConstraint.rb

class TimeConstraint
  def matches?(request)
   current = Time.now
   current.hour >= 9 && current.hour < 18
  end
end

ここで重要になってくるのは matches?メソッド部分で、これは制約クラスであることを表している。 またmatches?メソッドを使う条件としては

・引数としてリクエスト情報(requestオブジェクト)を受け取り ・戻り値としてルートを有効にすべきかどうか(true/false)を返す

必要がある

上記のプログラムでは

Time.nowでシステムの現在時刻を取得し、その時刻が9~18時以外の時間帯にアクセスしようとしようとするとエラーが表示される

route.rbには以下の様な記述をする

require 'TimeConstraint'

Railbook::Application.routes.draw do
  resources :books, constraints:TimeConstraint.new
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
end

formatパラメータの削除

そういやformatってなんだっけと調べてみると .xmlや.jsonのように拡張子の形式で出力フォーマットを指定することができる

リソースによっては複数のフォーマットに対応したくない場合に使うもの。

使い方はroute.rb

resources :books,format:false

とすればよい。 確認方法はrake routesなどで確認しformatが削除されてればおk

コントローラークラス/URLヘルパーの名前を修正する

resoures/resourceメソッドを使ってデフォルトで生成されたURLヘルパーの名前を変更したい場合は

controller/asオプションを指定する

マッピングすべきコントローラーや、生成するURLヘルパーの名前を変更することができる

route.rb

resources :users, controller: :members #1
resources  :reviews,as: :comments #2

1では本来usersリソースを使う場合UsersControllerが対応しているはずだがこの文を記述することによって MembersControllerに対応付けてマッピングしている

2ではasオプションを指定することによってcomments_pathやcomment_pathなどのヘルパーが用意される。

モジュール配下のコントローラーをマッピング

コントローラークラスが多くなった場合コントローラーを特定のサブフォルダにまとめたい場合に使う その場合まずコントローラークラスを生成する

bundle exec rails generate controller Admin::Books

これはcontrollers/adminフォルダの配下にbooks_controller.rbという名前で生成しろって文。

(ちなみにモジュール対応のコントローラークラスに対してテンプレートを設置する場合には 「views/モジュール名/コントローラー名」のフォルダ配下に設置する (今回の場合だと/views/admin/books))

このようなモジュール対応のコントローラークラスに対して、RESTfulインターフェイスを定義するには namespaceブロックを利用する

routes.rb

namespace :admin do
resources :books
end

これによって/admin/booksや/admin/books/:idなどのURLパターン admin_books_pathなどのURLヘルパーが生成される

またモジュールだけ認識してURLヘルパーに影響をだしたくないならscopeを使う

scope module: :admin do
  resources :books
end

これを行うとURLヘルパーやURLパターンにはモジュール名が含まれない (ちゃんと出来たかどうかはちゃんとrake routesで確認してね)

もう少しあるので一度ここで切る