ドキュメントを読み込むのは大事、ということでRailsガイドを頭から読んでいく取り組みをしています。 各章ごとに、(Railsガイドにちゃんと書いてあるのに)知らなかった機能を雑にまとめていきます。
今回は、Rails のルーティングの章です。
浅いネスト
リンクはこちら
ルーティングで、リソースのネストを避ける方法としてidを必要とする(関連リソースのIDの特定が可能)アクションはネストから外すという方法が紹介されています。
同じリソースに対してルーティングを分けるというのは発想がなかったので、とても面白いと思いました。
resources :articles do resources :comments, only: [:index, :new, :create] end resources :comments, only: [:show, :edit, :update, :destroy]
上記はshallow: true
をつけることでもっとシンプルに記載できます。
使うとしたらこっちの方が良さそうですね。
resources :articles, shallow: true do resources :comments end
慣れの問題もあるかもですが、ネストを避けた結果分かりづらくなることもあると思うので、いろいろ意見を聞いてみたいなーと思いました。
concern
リンクはこちら
concernを使うことで共通化できる。知らなかったですが、使える場面ありそうですね。
concern :commentable do resources :comments end
resources :books, concerns: :commentable
追加されたnewアクションへのルーティングを追加する
リンクはこちら
特定のアクションのルーティングに続ける形でルーティングの設定ができるみたいです。
ただし、コントローラのアクションは下記の例で言うとCommentsコントローラのpreviewアクションで処理されます。
また、newアクションがなくなるわけでもないです。
resources :comments do get 'preview', on: :new end
Prefix | Verb | URI Pattern | Controller#Action |
---|---|---|---|
preview_new_book | GET | /books/new/preview(.:format) | books#preview |
new_book | GET | /books/new(.:format) | books#new |
defaultsでデフォルトのパラメータを設定できる
リンクはこちら
defaults
を使うことでデフォルトのパラーメータを設定できます。
セキュリティ上の理由で上書き不可になっているとのこと。サーバ側で設定した値が上書き可能だと、色々とセキュリティ事故が起きやすくなってしまうから、ということでしょうか。
したがって、ユースケースとしては、値を渡すというよりRailsガイドの例のように、フォーマットを指定するようなユースケースの方がイメージできるなと思いました。
resources :books, defaults: { dummy: true }
ちなみに上記の状態で、/books?dummy=false
とリクエストを送っても、paramsの中身はdummy: true
でした。
同じURLで複数種類のHTTPリクエストを受け付ける
リンクはこちら
match
とvia
を使って同じURLでGETとPOSTを受け付ける、みたいなことができます。
あまり有効なユースケースが思いつかないですが、例えばリプレイス案件で既存のサイトのURL構造をとりあえず変えたくないときなど、どうしてもというときには使えるということを覚えておくと良いかもなと思いました。
match 'photos', to: 'photos#show', via: [:get, :post]
リクエスト内容に応じて制限を加える
リンクはこちら
例えば、以下のようにすると、http://admin.example.com/photos
のように、admin
というサブドメインにアクセスがあった場合にのみ、対応することになるみたいです。
get 'photos', to: 'photos#index', constraints: { subdomain: 'admin' }
matchesを使った高度な制限
リンクはこちら
例えば以下の例だと、constraints
に渡したインスタンスがmatches?
でtrueを返すので、/books
にアクセスすると、booksコントローラのnewアクションが反応します。
class Restrict def matches?(request) true end end Rails.application.routes.draw do get 'books', to: 'books#new', constraints: Restrict.new end
ちなみにlogからは特に制限をしたからといって特別な履歴は出ていなかったです。
Started GET "/books/" for ... Processing by BooksController#new as HTML ...(略) Completed 200 OK
Rackアプリケーションにルーティングする
リンクはこちら
ルーターからすると、call
に応答すれば、特にアクションであるかは気にしない、とのことです。
例えば、以下のようにすると、/rack_demo
にアクセスした際に、Hello, World!
というテキストが表示されました。
class MyRackApp def call(env) [200, { "Content-Type" => "text/plain" }, ["Hello World!"]] end end Rails.application.routes.draw do get 'rack_demo', to: MyRackApp.new end
ちなみにlogは以下の1行だけでした。
Started GET "/rack_demo" for ...
resolve
リンクはこちら
例えば以下のようにすると、<%= link_to "Show this book", book %>
のように書いている箇所のリンクがbook_url
ではなく、dummy_url
を指すようになります。
ActionView::Template::Error (undefined method `dummy_url')
asオプションでヘルパーの命名をオーバーライド
リンクはこちら
as
オプションを使うことで、ヘルパーの命名をオーバーライドすることができます。
URLが長くなったときに短縮するとか、URLを変更するときにviewファイルの変更を一旦後回しにしたいときなどに使えそうかな?と思いました。
ただし、命名の衝突には注意が必要ですね。
path_namesでnewやeditのオーバーライド
リンクはこちら
ユーザーに見せるURLだけをnewやeditから変えたいときに使えそうです。
これも例えばサービスをRailsで作り替えたいときなどに、URL構成を変更せず、かつなるべくアクションはRails標準を使いたいときなどに使えそうですね。
resources :books, path_names: { new: 'make', edit: 'change' }
少し混乱しそうではありますが、ヘルパー名もnewやeditを使うことになります。
$ rails routes new_book GET /books/make(.:format) books#new
inflectionsで単数系、複数形の名前をオーバライド
リンクはこちら
inflections
で、単数系、複数形の名前を自由に調整できます。
例えば、Person
モデルをscaffoldで作成すると、コントローラの名前などはPeople
になります。
$ rails g scaffold Person ... create app/controllers/people_controller.rb
しかし、config/initializers/inflections.rb
を以下のようにすると、Persons
のコントローラを作成できました。
ActiveSupport::Inflector.inflections(:en) do |inflect| inflect.irregular 'person', 'persons' end
$ rails g scaffold Person ... create app/controllers/persons_controller.rb
paramでルーティングのパラメータをオーバーライド
リンクはこちら
ルーティングのidの部分を他の値にすることができるようです。
重複しないことが必須になると思うので難しいですが、何か明確な識別子があるなら、それを表示したいケースなどもありそうですね。
ルーティングのファイルを分割
リンクはこちら
ルーティングのファイルはdraw
を使うことで分割先のファイルを読み込むように指定できるようです。
Railsガイドには「本当に必要になるまでは分割しないこと」とあり、その理由としてscope
やnamespace`などで分割する方法がすでにあるから、と言うことでしたが、個人的には(ファイル分割は使ったことないですが)管理者か一般ユーザーかどうかでファイルを分けるくらいでもむしろ明確になっていいんじゃないの?と思ったりもしました。