Ruby on Railsでコントローラーの中でアクションは違えど
同じHTTPメソッドを使っている場合にどう住み分けをするかという話。
準備
scaffoldで本(Book)についてのコードを自動生成します。
$ rails g scaffold book title
本についての情報をすべてCSVでダウンロードするBooksController#download
を作成します。
ルーティングはget
を使って追加します。
Rails.application.routes.draw do
resources :books
get 'books/download'
end
/books/download
にアクセスすると対応するBooksController#show
が実行されます。
ルーティングはroutes.rbの上にある設定値が優先されるためdownload
があたかもid
のように処理されて例外が発生しています。
対策
ベストではないですが、URLフォーマットを特定の形式に制限するとうまくいきました。
:id
はすべて整数値であること期待するようにします。
つまり、/books/5
といった:id
が整数なアクセスであればBooksController#show
を実行するように制限すると、
その他のHTTPメソッドがGETであるルーティングはroutes.rbに準ずるようになりました。
Rails.application.routes.draw do
resources :books, constraints: {id: /[0-9]+/}
get 'books/download'
end
format
を利用してアクションを切り替えてもいいかもしれません。
CSVダウンロードだったら別にコントローラを作れという説もあります。
検証環境
Ruby 2.4
Rails 5.1.1