安装 Mollie payments API 时出现 unpermitted_parameters
结论
unpermitted parameters: _method, authenticity_token 是 Rails Strong Parameters 发出的提示,通常与 Mollie API 无关。它说明表单把 Rails 自动生成的字段传给了 permit,不能据此判断支付接口是否被调用。
问题更可能出在后续流程上:mollie.payments.create 只负责在服务端创建支付,不会自动打开 Mollie 的付款页面。创建成功后,还要把浏览器重定向到 Mollie 返回的 checkout URL。
正确的调用流程
完整的支付流程通常如下:
- 保存 reservation。
- 调用 Mollie 创建 payment。
- 保存 Mollie 返回的 payment ID。
- 通过
redirect_to跳转到 Mollie 的付款页面。 - 支付完成后,Mollie 通过
redirectUrl将用户带回站点。 - 服务端重新查询 payment 状态,不能只根据用户是否返回页面来判断支付成功。
以旧版 Mollie Ruby API 为例:
def create
@reservation = Reservation.new(reservation_params)
if @reservation.save
mollie = Mollie::API::Client.new(ENV.fetch('MOLLIE_API_KEY'))
payment = mollie.payments.create(
amount: 10.00,
description: "Reservation #{@reservation.id}",
redirectUrl: reservation_url(@reservation)
)
@reservation.update(mollie_payment_id: payment.id)
redirect_to payment.payment_url
else
render :new
end
end
其中不能缺少最后的重定向:
redirect_to payment.payment_url
如果没有执行这行代码,即使 API 已成功创建 payment,用户也会继续停留在当前页面。
不同 gem 版本的字段可能不同
问题中的写法适用于较旧版本的 Mollie Ruby 客户端。新版客户端通常要求金额包含币种,参数名也改为 snake_case:
payment = mollie.payments.create(
amount: {
currency: 'EUR',
value: '10.00'
},
description: "Reservation #{@reservation.id}",
redirect_url: reservation_url(@reservation)
)
新版响应中的 checkout URL 也可能需要从链接对象中获取:
redirect_to payment._links.checkout.href
应当使用:
payment.payment_url
还是:
payment._links.checkout.href
要看项目实际安装的 gem 版本。不要混用不同版本文档里的参数格式。可以先通过日志确认返回对象,但不要输出完整对象,以免敏感信息被写入日志:
Rails.logger.info("Mollie payment created: #{payment.id}")
处理 unpermitted parameters
_method 和 authenticity_token 都是 Rails 的表单字段,不需要加入业务模型的允许参数。Strong Parameters 只应处理 reservation 下的嵌套字段:
private
def reservation_params
params.require(:reservation).permit(
:name,
:email,
:start_date,
:end_date
)
end
不要直接对整个 params 调用 permit:
# 不推荐
params.permit(:name, :email)
只要 reservation 的合法字段能够正常保存,这两项警告一般不会妨碍 Mollie API 调用。
检查保存条件
下面的判断不能说明 reservation 已成功保存:
if @reservation
对象只要已经创建,即使验证失败,通常也是真值。应该直接检查保存结果:
if @reservation.save
# 创建 Mollie payment
else
render :new
end
如果 reservation 已经在前面保存,也可以检查:
if @reservation.persisted?
其他注意事项
不要把 API 密钥直接写在 controller 中。问题里展示的测试密钥已经暴露,建议立即到 Mollie 后台撤销并重新生成,再通过环境变量读取:
mollie = Mollie::API::Client.new(ENV.fetch('MOLLIE_API_KEY'))
localhost 可以作为本机浏览器的返回地址,但 Mollie 的服务器无法访问你的本机。如果需要接收 webhook,就要使用 Mollie 能从公网访问的 HTTPS 地址。
Ruby 的 require 路径通常区分大小写。如果确实需要手动加载,应按照 gem 提供的路径编写,例如:
require 'mollie/api/client'
Rails 通过 Bundler 加载 gem 后,通常不需要在 controller 中再次 require。
创建支付失败时,SDK 一般会抛出异常。应记录清晰的错误信息,不要把异常当成普通的页面跳转处理:
begin
payment = mollie.payments.create(payment_attributes)
redirect_to payment.payment_url
rescue StandardError => e
Rails.logger.error("Mollie payment creation failed: #{e.class}: #{e.message}")
redirect_to @reservation, alert: '支付暂时无法创建,请稍后重试。'
end
生产环境中最好只捕获当前 Mollie gem 定义的具体异常类型,具体类名以项目所安装版本的文档为准。
备注:内容仅供参考。