症状
Rails6.0.3のAPIモードでeditアクションに対してアクセスしようとしたとき、下記エラーが発生しアクセスできませんでした。 No route matches「ルーティングがマッチしていない」と怒られています。ActionController::RoutingError (No route matches [GET] "/api/v1/hoges/2/edit"):
actionpack (6.0.3.6) lib/action_dispatch/middleware/debug_exceptions.rb:36:in `call'
actionpack (6.0.3.6) lib/action_dispatch/middleware/show_exceptions.rb:33:in `call'
railties (6.0.3.6) lib/rails/rack/logger.rb:37:in `call_app'
railties (6.0.3.6) lib/rails/rack/logger.rb:26:in `block in call'
activesupport (6.0.3.6) lib/active_support/tagged_logging.rb:80:in `block in tagged'
activesupport (6.0.3.6) lib/active_support/tagged_logging.rb:28:in `tagged'
activesupport (6.0.3.6) lib/active_support/tagged_logging.rb:80:in `tagged'
railties (6.0.3.6) lib/rails/rack/logger.rb:26:in `call'
actionpack (6.0.3.6) lib/action_dispatch/middleware/request_id.rb:27:in `call'
rack (2.2.3) lib/rack/runtime.rb:22:in `call'
activesupport (6.0.3.6) lib/active_support/cache/strategy/local_cache_middleware.rb:29:in `call'
actionpack (6.0.3.6) lib/action_dispatch/middleware/executor.rb:14:in `call'
actionpack (6.0.3.6) lib/action_dispatch/middleware/static.rb:126:in `call'
rack (2.2.3) lib/rack/sendfile.rb:110:in `call'
actionpack (6.0.3.6) lib/action_dispatch/middleware/host_authorization.rb:82:in `call'
rack-cors (1.1.1) lib/rack/cors.rb:100:in `call'
railties (6.0.3.6) lib/rails/engine.rb:527:in `call'
puma (4.3.7) lib/puma/configuration.rb:228:in `call'
puma (4.3.7) lib/puma/server.rb:713:in `handle_request'
puma (4.3.7) lib/puma/server.rb:472:in `process_client'
puma (4.3.7) lib/puma/server.rb:328:in `block in run'
puma (4.3.7) lib/puma/thread_pool.rb:134:in `block in spawn_thread'
ルーティングを確認すると、何となく問題なさそうです。
resouceだと、特定のデータにアクセスするようなルーティングは制限されますが、今回使っているのはeditやshowなどの特定のデータにアクセスできるアクションにも対応できるようにしています。
Rails.application.routes.draw do
namespace :api do
namespace :v1 do
resources :fugasdo
resources :hoges
end
resources :hoges
end
end
end
実際にどのようなルーティングが存在しているかをrake routesで確認します。
rake routes
Prefix Verb URI Pattern Controller#Action
api_v1_fuga_hoges GET /api/v1/fugas/:fuga_id/hoges(.:format) api/v1/hoges#index
POST /api/v1/fugas/:fuga_id/hoges(.:format) api/v1/hoges#create
api_v1_fugat_food GET /api/v1/fugas/:fuga_id/hoges/:id(.:format) api/v1/hoges#show
PATCH /api/v1/fugas/:fuga_id/hoges/:id(.:format) api/v1/hoges#update
PUT /api/v1/fugas/:fuga_id/hoges/:id(.:format) api/v1/hoges#update
DELETE /api/v1/fugas/:fuga_id/hoges/:id(.:format) api/v1/hoges#destroy
api_v1_fugas GET /api/v1/fugas(.:format) api/v1/fugas#index
POST /api/v1/fugas(.:format) api/v1/fugas#create
api_v1_fugat GET /api/v1/fugas/:id(.:format) api/v1/fugas#show
PATCH /api/v1/fugas/:id(.:format) api/v1/fugas#update
PUT /api/v1/fugas/:id(.:format) api/v1/fugas#update
DELETE /api/v1/fugas/:id(.:format) api/v1/fugas#destroy
api_v1_hoges GET /api/v1/hoges(.:format) api/v1/hoges#index
POST /api/v1/hoges(.:format) api/v1/hoges#create
api_v1_food GET /api/v1/hoges/:id(.:format) api/v1/hoges#show
PATCH /api/v1/hoges/:id(.:format) api/v1/hoges#update
PUT /api/v1/hoges/:id(.:format) api/v1/hoges#update
DELETE /api/v1/hoges/:id(.:format) api/v1/hoges#destroy
rails_postmark_inbound_emails POST /rails/action_mailbox/postmark/inbound_emails(.:format) action_mailbox/ingresses/postmark/inbound_emails#create
rails_relay_inbound_emails POST /rails/action_mailbox/relay/inbound_emails(.:format) action_mailbox/ingresses/relay/inbound_emails#create
rails_sendgrid_inbound_emails POST /rails/action_mailbox/sendgrid/inbound_emails(.:format) action_mailbox/ingresses/sendgrid/inbound_emails#create
rails_mandrill_inbound_health_check GET /rails/action_mailbox/mandrill/inbound_emails(.:format) action_mailbox/ingresses/mandrill/inbound_emails#health_check
rails_mandrill_inbound_emails POST /rails/action_mailbox/mandrill/inbound_emails(.:format) action_mailbox/ingresses/mandrill/inbound_emails#create
rails_mailgun_inbound_emails POST /rails/action_mailbox/mailgun/inbound_emails/mime(.:format) action_mailbox/ingresses/mailgun/inbound_emails#create
rails_conductor_inbound_emails GET /rails/conductor/action_mailbox/inbound_emails(.:format) rails/conductor/action_mailbox/inbound_emails#index
POST /rails/conductor/action_mailbox/inbound_emails(.:format) rails/conductor/action_mailbox/inbound_emails#create
rails_conductor_inbound_email GET /rails/conductor/action_mailbox/inbound_emails/:id(.:format) rails/conductor/action_mailbox/inbound_emails#show
PATCH /rails/conductor/action_mailbox/inbound_emails/:id(.:format) rails/conductor/action_mailbox/inbound_emails#update
PUT /rails/conductor/action_mailbox/inbound_emails/:id(.:format) rails/conductor/action_mailbox/inbound_emails#update
DELETE /rails/conductor/action_mailbox/inbound_emails/:id(.:format) rails/conductor/action_mailbox/inbound_emails#destroy
rails_conductor_inbound_email_reroute POST /rails/conductor/action_mailbox/:inbound_email_id/reroute(.:format) rails/conductor/action_mailbox/reroutes#create
rails_service_blob GET /rails/active_storage/blobs/:signed_id/*filename(.:format) active_storage/blobs#show
rails_blob_representation GET /rails/active_storage/representations/:signed_blob_id/:variation_key/*filename(.:format) active_storage/representations#show
rails_disk_service GET /rails/active_storage/disk/:encoded_key/*filename(.:format) active_storage/disk#show
update_rails_disk_service PUT /rails/active_storage/disk/:encoded_token(.:format) active_storage/disk#update
rails_direct_uploads POST /rails/active_storage/direct_uploads(.:format) active_storage/direct_uploads#create
上記の中に「edit」に該当するルーティングは存在しませんでした。
resoucesを使っても[edit」のルーティングが存在しないようです。
調べてみると、Railsガイドの「浅いネスト」に今回の原因となりそうな記述がありました。
要約すると、「親スコープ(fuga)の中でidを指定しないアクションのみを生成できる」というものでした。
つまり、今回のhugaに関するルーティングでは、routeファイルが上から読み込まれている関係上、最初にfuga以下にあったhogeリソースにヒットし、そこではid指定があるアクションが生成されていなかったから、このようになってしまったのかと思いましたが、resoucesの順序を変更してもルーティングにeditが追加されませんでした。
解決方法
resoucesで使用するアクションを明示的に書いたら、ルーティングエラーが出なくなりました。resources :hoges,only: [:index, :show, :new, :create, :destroy, :edit, :update] do
end
RailsAPIモードだったので、生成されるルーティングは下記になります。
ゆえに、editやdestroyなどがルーティングでそもそも生成されない仕様で、resoucesでも使えないようです。
rake routes
api_v1_posts GET /api/v1/posts(.:format) api/v1/posts#index
POST /api/v1/posts(.:format) api/v1/posts#create
api_v1_post GET /api/v1/posts/:id(.:format) api/v1/posts#show
PATCH /api/v1/posts/:id(.:format) api/v1/posts#update
PUT /api/v1/posts/:id(.:format) api/v1/posts#update
DELETE /api/v1/posts/:id(.:format) api/v1/posts#destroy