はじめに
Railsでアプリ開発をしていて、意図通りにアクションが実行されないことはよくあると思います。
その原因は様々あると思いますが、今回は未来の自分の為にいくつか例を投稿します。
ついでに初学者の方々の助けにもなれば幸いです。
ルーティングの記述の順番を確認する。
Railsのルーティングは、ルートの定義順によって評価されます。
つまり、最初にマッチしたものが実行されます。
以下の場合item_export_list_path
をリクエストすると
item#export_list
ではなくitem#show
が実行されてしまいます。
post 'items/:id', to: 'item#show', as: 'items_show'
post 'items/item_list', to: 'item#export_list', as: 'item_export_list'
なので以下のように順番を入れ替えて修正
post 'items/item_list', to: 'item#export_list', as: 'item_export_list'
post 'items/:id', to: 'item#show', as: 'items_show'
これでitem_export_list_path
をリクエストすると
意図通りitem#export_list
が実行されました。
詳しい原因はよくわかっていないのでchatgptに聞いてみた。
:id は任意の文字列にマッチするため、post 'items/:id' の方が広範なパスにマッチすると判断されます。
/items/export_list というパスが来た場合、Railsはまず最初のルートから順にマッチするかどうかを確認します。post 'items/:id' の方は :id が任意の文字列にマッチするため、このパスにもマッチしてしまいます。そのため、最初のルートがマッチしてしまい、items#show アクションが実行されてしまいます。
つまりは、/:id
は文字列にもマッチすることがあり、
/items/export_list
(この場合/export_listが文字列)のリクエストがより前に定義していたitems/:id
と判断されitem#show
が実行されたということでしょうか。
基本的に、今回のようにルーティングを設定する場合はitems/:id
のようなルーティングは:id以外を渡した場合も呼ばれる可能性があるため後ろに定義しておくことが無難という考え方で問題ないのでしょうか。
なんちゃってエンジニアの私に教えていただければ幸いです。
javascriptを設定せずにlink_to
を使用している場合
javascriptを設定しておらず、link_to
でmethod: :post
などget以外を指定している場合はデフォルトでgetリクエストが生成されるので違ったアクションが呼ばれてしまうことがあります。
javascriptを有効にした場合はjavascriptが介入して指定したHTTPメソッドでリクエストしてくれます。
javascriptを有効にしない場合はbutton_to
に書きかえるか
<%= form_with(url: XXXXX_path) do |form| %>
<input type="submit" value="button">
<% end %>
のように実装することで対応できます。
最後に
今後も開発していくなかで新しく陥ってしまった事例など出てきましたら記事に追記していこうと思います。
間違った内容や表現などありましたらご指摘いただけますと幸いです。