Rails 7特性测试中PUT路由触发GET请求致路由匹配失败
Rails 7特性测试中点击按钮触发GET而非PUT请求的问题解决
问题背景
我在给Rails 7应用写特性测试,用的是RSpec、Capybara和Capybara-Webkit。功能是用户点击「Archive」按钮,用PUT方法归档一条开发者应用记录。浏览器里功能正常,但跑测试时,测试居然用GET请求访问路径,直接报路由不存在的错。把路由改成GET的话测试能过,但这明显不符合更新操作的REST规范。为啥测试里的点击事件会发GET而不是PUT?
错误信息
Failure/Error: raise ActionController::RoutingError, "No route matches [#{env['REQUEST_METHOD']}] #{env['PATH_INFO'].inspect}" ActionController::RoutingError: No route matches [GET] "/developer_apps/1/archive"
测试代码
scenario "can archive their developer app", js: true do visit developer_app_path(@developer_app) click_on 'Archive' expect(page).to have_content "Developer app archived" expect(page).to have_content "Status: Archived" end
视图按钮代码
<%= link_to "Archive", archive_developer_app_path(@developer_app), class: 'btn btn-danger', data: { "turbo-method": :put, turbo_confirm: "Are you sure?" } %>
路由配置
put '/developer_apps/:id/archive', to: 'developer_apps#archive', as: :archive_developer_app
问题原因与解决办法
原因
Rails 7默认用Turbo来处理非GET请求的链接——Turbo会拦截链接点击事件,根据data-turbo-method属性生成对应的PUT/DELETE请求。但Capybara-Webkit是个老款无头浏览器驱动,它不支持Turbo的这些前端逻辑,只会把链接当成普通的GET请求来处理,自然就找不到对应的PUT路由了。
解决办法
有三种可行方案:
- 换用支持Turbo的驱动:比如换成
cuprite或者selenium-webdriver(搭配Chrome/Firefox),这些驱动会完整加载前端JS,包括Turbo,能正确识别data-turbo-method属性并发起对应请求。这是最推荐的方案,符合Rails 7的默认技术栈。 - 测试中直接发送PUT请求:如果不想换驱动,可以跳过点击操作,直接在测试里发送PUT请求,之后再刷新页面验证结果:
scenario "can archive their developer app", js: true do visit developer_app_path(@developer_app) page.driver.put archive_developer_app_path(@developer_app) visit developer_app_path(@developer_app) expect(page).to have_content "Developer app archived" expect(page).to have_content "Status: Archived" end - 临时回退到Rails UJS:如果一定要用Capybara-Webkit,可以把视图里的
data-turbo-method改成data-method,同时在项目中引入rails-ujs。不过这不符合Rails 7的默认配置,不建议长期使用。
内容的提问来源于stack exchange,提问作者abarron
相关产品推荐
相关产品推荐

