为何指定method: :patch仍触发GET请求,出现No route matches错误?
问题描述
我想给未完成结账的客户发送含魔法链接的邮件,该链接可先登录用户,再触发控制器的update动作。邮件中使用的link_to代码如下:
<%= link_to( "Continue to checkout", "#{checkout_url(host: @account.complete_url, id: @user.current_subscription_cart)}?msgver=#{@user.create_message_verifier}", method: :patch, subscription_cart: { item_id: @item_id }, ) %>
我的checkouts_controller包含update动作:
def update # update cart with item_id param and continue end
路由配置为:
resources :checkouts, only: [:create, :update]
对应的update路由为:
checkout_path PATCH /checkouts/:id(.:format) checkouts#update
生成的链接带有data-method="patch"属性:
<a data-method="patch" href="https://demo.test.io/checkouts/67?msgver=TOKEN">Continue to checkout</a> => https://demo.test.io/checkouts/67?msgver=TOKEN
但点击链接时却报错:
No route matches [GET] "/checkouts/67"
为何指定了method: :patch,仍发起GET请求?
原因与解决方案
核心原因
Rails的link_to指定method: :patch时,完全依赖Rails UJS(Unobtrusive JavaScript)脚本实现非GET请求的转换。但邮件客户端不会加载Rails的UJS脚本,点击链接时只会触发浏览器默认的GET请求,无法触发PATCH请求。
解决方法
方法1:改用GET请求处理逻辑
既然邮件环境无法支持UJS,可调整路由和控制器,允许通过GET请求执行原update动作的逻辑:
- 修改路由,添加GET方法支持:
resources :checkouts, only: [:create] # 同时支持PATCH和GET请求访问update动作 patch '/checkouts/:id', to: 'checkouts#update', as: :checkout get '/checkouts/:id', to: 'checkouts#update', as: :checkout_continue
- 更新
link_to代码,去掉method: :patch参数,直接使用GET链接:
<%= link_to( "Continue to checkout", checkout_continue_url( host: @account.complete_url, id: @user.current_subscription_cart, msgver: @user.create_message_verifier, subscription_cart: { item_id: @item_id } ) ) %>
注意:必须确保update动作通过msgver严格验证用户身份,防止恶意请求。
方法2:用表单模拟PATCH请求(邮件兼容方案)
在邮件中嵌入隐藏表单,用按钮模拟链接样式,通过表单提交发送PATCH请求(无需依赖JS):
<form action="<%= checkout_url(host: @account.complete_url, id: @user.current_subscription_cart) %>?msgver=<%= @user.create_message_verifier %>" method="post"> <input type="hidden" name="_method" value="patch"> <input type="hidden" name="subscription_cart[item_id]" value="<%= @item_id %>"> <button type="submit" style="border: none; background: transparent; color: #0066cc; text-decoration: underline; cursor: pointer;">Continue to checkout</button> </form>
大部分邮件客户端支持表单提交,这种方式能稳定触发PATCH请求。
内容的提问来源于stack exchange,提问作者pinkfloyd90
相关产品推荐
相关产品推荐

