在 ajax 表格中包含 Stripe 卡信息会删除 authenticity_token
Including Stripe card info in ajax form removes authenticity_token
我有一个 form_tag 使用 Ajax 通过 Stripe 保存新用户卡。它呈现一个 Stripe 卡片表单,将输入传递给控制器方法,然后应该提供一个 js 文件。它在没有 Stripe 的情况下工作,但有了它,我遇到了身份验证问题。
基本代码如下:
<%= form_tag(save_card_path, id:'payment-form', remote: true) do %>
<div id="card-element">
<!-- A Stripe Element will be inserted here. -->
</div>
<button id="submit-card" class="submit-btn">Save Card</button>
<% end %>
<script type="text/javascript">
var stripe = Stripe('<%= @stripe_public %>');
var elements = stripe.elements();
// Custom styling can be passed to options when creating an Element.
var style = {
base: {
// Add your base input styles here. For example:
fontSize: '20px',
color: "#32325d",
}
};
// Create an instance of the card Element.
var card = elements.create('card', {style: style});
// Add an instance of the card Element into the `card-element` <div>.
card.mount('#card-element');
card.addEventListener('change', function(event) {
var displayError = document.getElementById('card-errors');
if (event.error) {
displayError.textContent = event.error.message;
} else {
displayError.textContent = '';
}
});
// Create a token or display an error when the form is submitted.
var form = document.getElementById('payment-form');
form.addEventListener('submit', function(event) {
event.preventDefault();
stripe.createToken(card).then(function(result) {
if (result.error) {
// Inform the customer that there was an error.
var errorElement = document.getElementById('card-errors');
errorElement.textContent = result.error.message;
} else {
// Send the token to your server.
stripeTokenHandler(result.token);
}
});
});
function stripeTokenHandler(token) {
// Insert the token ID into the form so it gets submitted to the server
var form = document.getElementById('payment-form');
var hiddenInput = document.createElement('input');
hiddenInput.setAttribute('type', 'hidden');
hiddenInput.setAttribute('name', 'stripeToken');
hiddenInput.setAttribute('value', token.id);
form.appendChild(hiddenInput);
// Submit the form
form.submit();
}
</script>
card_controller.rb
def save_card
respond_to do |format|
format.js
end
end
save_card.js.erb
$("html").hide();
就像我说的,没有 Stripe 代码一切正常,并且参数中存在 authenticity_token
,但是我上面写的代码给出了以下错误:
def handle_unverified_request
raise ActionController::InvalidAuthenticityToken
end
只有参数:
{"utf8"=>"✓", "stripeToken"=>"<token>"}
当我将选项 authenticity_token: true
添加到表单时,参数再次包含一个 authenticity_token
,但现在当它到达 format.js
行时,我得到错误
ActionController::UnknownFormat
我在尝试通过 Ajax 以表单形式上传文件时曾 运行 遇到过类似的问题,但我发现了 remotipart gem,这就解决了它。但在这种情况下似乎没有帮助。
有谁知道为什么包含 Stripe 字段会摆脱我的 authenticity_token,以及为什么即使使用 authenticity_token,也无法识别 js 格式?
编辑:
Jquery-ujs 通过 //= require jquery_ujs
行包含在我的 application.js
中,<%= csrf_meta_tags %>
行包含在 application.html.erb
中,我的源代码包括行
<meta name="csrf-param" content="authenticity_token" />
<meta name="csrf-token" content="<TOKEN>" />
无论我的ajax调用是否有效,都是如此。
更新:
这是我添加选项 authenticity_token: true
:
时的完整日志
Started POST "/save_card" for 127.0.0.1 at 2020-02-20 00:07:04 +0100
Processing by UsersController#save_card as HTML
Parameters:
{"utf8"=>"✓",
"authenticity_token"=>"[LONG TOKEN]",
"post"=>"47", "transaction"=>"bid",
"stripeToken"=>"[STRIPE TOKEN]"}
User Load (0.9ms)
SELECT "users".* FROM "users" WHERE "users"."id" = ORDER BY
"users"."id" ASC LIMIT [["id", 2], ["LIMIT", 1]]
(0.3ms) BEGIN
SQL
(2.3ms) INSERT INTO "cards" ("stripe_customer_id", "brand",
"last4", "exp_month", "exp_year", "user_id", "created_at",
"updated_at") VALUES (, , , , , , , ) RETURNING "id"
[["stripe_customer_id", "[STRIPE TOKEN]"], ["brand", "Visa"],
["last4", "4242"], ["exp_month", "4"], ["exp_year", "2024"],
["user_id", 2], ["created_at", "2020-02-19 23:07:05.246789"],
["updated_at", "2020-02-19 23:07:05.246789"]]
(2.8ms) COMMIT
Completed 406 Not Acceptable in 672ms (ActiveRecord: 6.3ms)
ActionController::UnknownFormat (ActionController::UnknownFormat):
app/controllers/users_controller.rb:485:in `save_card' Started GET
"/serviceworker.js" for 127.0.0.1 at 2020-02-20 00:07:05 +0100 Started
GET "/serviceworker.js" for ::1 at 2020-02-20 00:07:21 +0100
这是我删除 authenticity_token: true
:
时的日志
Started POST "/save_card" for 127.0.0.1 at 2020-02-20 00:33:17 +0100
Processing by UsersController#save_card as HTML
Parameters:
{"utf8"=>"✓", "post"=>"47", "transaction"=>"bid",
"stripeToken"=>"[STRIPE TOKEN]"} Can't verify CSRF token
authenticity. Completed 422 Unprocessable Entity in 1ms (ActiveRecord:
0.0ms)
ActionController::InvalidAuthenticityToken
(ActionController::InvalidAuthenticityToken): actionpack (5.1.7)
lib/action_controller/metal/request_forgery_protection.rb:195:in
handle_unverified_request' actionpack (5.1.7)
lib/action_controller/metal/request_forgery_protection.rb:227:in
handle_unverified_request' devise (4.7.0)
lib/devise/controllers/helpers.rb:255:in handle_unverified_request'
actionpack (5.1.7)
lib/action_controller/metal/request_forgery_protection.rb:222:in
verify_authenticity_token' activesupport (5.1.7)
lib/active_support/callbacks.rb:413:in block in make_lambda'
activesupport (5.1.7) lib/active_support/callbacks.rb:197:in
block (2
levels) in halting' actionpack (5.1.7)
lib/abstract_controller/callbacks.rb:12:in block (2 levels) in
<module:Callbacks>' activesupport (5.1.7)
lib/active_support/callbacks.rb:198:in
block in halting'
activesupport (5.1.7) lib/active_support/callbacks.rb:507:in block in
invoke_before' activesupport (5.1.7)
lib/active_support/callbacks.rb:507:in
each' activesupport (5.1.7)
lib/active_support/callbacks.rb:507:in invoke_before' activesupport
(5.1.7) lib/active_support/callbacks.rb:130:in
run_callbacks'
actionpack (5.1.7) lib/abstract_controller/callbacks.rb:19:in
process_action' actionpack (5.1.7)
lib/action_controller/metal/rescue.rb:20:in
process_action'
actionpack (5.1.7)
lib/action_controller/metal/instrumentation.rb:32:in block in
process_action' activesupport (5.1.7)
lib/active_support/notifications.rb:166:in
block in instrument'
activesupport (5.1.7)
lib/active_support/notifications/instrumenter.rb:21:in instrument'
activesupport (5.1.7) lib/active_support/notifications.rb:166:in
instrument' actionpack (5.1.7)
lib/action_controller/metal/instrumentation.rb:30:in process_action'
actionpack (5.1.7)
lib/action_controller/metal/params_wrapper.rb:252:in
process_action'
activerecord (5.1.7)
lib/active_record/railties/controller_runtime.rb:22:in
process_action' actionpack (5.1.7)
lib/abstract_controller/base.rb:124:in
process' actionview (5.1.7)
lib/action_view/rendering.rb:30:in process' actionpack (5.1.7)
lib/action_controller/metal.rb:189:in
dispatch' actionpack (5.1.7)
lib/action_controller/metal.rb:253:in dispatch' actionpack (5.1.7)
lib/action_dispatch/routing/route_set.rb:49:in
dispatch' actionpack
(5.1.7) lib/action_dispatch/routing/route_set.rb:31:in serve'
actionpack (5.1.7) lib/action_dispatch/journey/router.rb:50:in
block
in serve' actionpack (5.1.7)
lib/action_dispatch/journey/router.rb:33:in each' actionpack (5.1.7)
lib/action_dispatch/journey/router.rb:33:in
serve' actionpack (5.1.7)
lib/action_dispatch/routing/route_set.rb:844:in call'
serviceworker-rails (0.6.0) lib/serviceworker/middleware.rb:35:in
call' remotipart (1.4.3) lib/remotipart/middleware.rb:32:in call'
warden (1.2.8) lib/warden/manager.rb:36:in
block in call' warden
(1.2.8) lib/warden/manager.rb:34:in catch' warden (1.2.8)
lib/warden/manager.rb:34:in
call' rack (2.0.7) lib/rack/etag.rb:25:in
call' rack (2.0.7) lib/rack/conditional_get.rb:38:in
call' rack
(2.0.7) lib/rack/head.rb:12:in call' rack (2.0.7)
lib/rack/session/abstract/id.rb:232:in
context' rack (2.0.7)
lib/rack/session/abstract/id.rb:226:in call' actionpack (5.1.7)
lib/action_dispatch/middleware/cookies.rb:613:in
call' activerecord
(5.1.7) lib/active_record/migration.rb:556:in call' actionpack
(5.1.7) lib/action_dispatch/middleware/callbacks.rb:26:in
block in
call' activesupport (5.1.7) lib/active_support/callbacks.rb:97:in
run_callbacks' actionpack (5.1.7)
lib/action_dispatch/middleware/callbacks.rb:24:in
call' actionpack
(5.1.7) lib/action_dispatch/middleware/executor.rb:12:in call'
actionpack (5.1.7)
lib/action_dispatch/middleware/debug_exceptions.rb:59:in
call'
web-console (3.7.0) lib/web_console/middleware.rb:135:in call_app'
web-console (3.7.0) lib/web_console/middleware.rb:30:in
block in
call' web-console (3.7.0) lib/web_console/middleware.rb:20:in catch'
web-console (3.7.0) lib/web_console/middleware.rb:20:in
call'
actionpack (5.1.7)
lib/action_dispatch/middleware/show_exceptions.rb:31:in call'
railties (5.1.7) lib/rails/rack/logger.rb:36:in
call_app' railties
(5.1.7) lib/rails/rack/logger.rb:24:in block in call' activesupport
(5.1.7) lib/active_support/tagged_logging.rb:69:in
block in tagged'
activesupport (5.1.7) lib/active_support/tagged_logging.rb:26:in
tagged' activesupport (5.1.7)
lib/active_support/tagged_logging.rb:69:in
tagged' railties (5.1.7)
lib/rails/rack/logger.rb:24:in call' sprockets-rails (3.2.1)
lib/sprockets/rails/quiet_assets.rb:13:in
call' actionpack (5.1.7)
lib/action_dispatch/middleware/remote_ip.rb:79:in call' actionpack
(5.1.7) lib/action_dispatch/middleware/request_id.rb:25:in
call' rack
(2.0.7) lib/rack/method_override.rb:22:in call' rack (2.0.7)
lib/rack/runtime.rb:22:in
call' activesupport (5.1.7)
lib/active_support/cache/strategy/local_cache_middleware.rb:27:in
call' actionpack (5.1.7)
lib/action_dispatch/middleware/executor.rb:12:in
call' actionpack
(5.1.7) lib/action_dispatch/middleware/static.rb:125:in call' rack
(2.0.7) lib/rack/sendfile.rb:111:in
call' railties (5.1.7)
lib/rails/engine.rb:522:in call' puma (3.12.1)
lib/puma/configuration.rb:227:in
call' puma (3.12.1)
lib/puma/server.rb:660:in handle_request' puma (3.12.1)
lib/puma/server.rb:474:in
process_client' puma (3.12.1)
lib/puma/server.rb:334:in block in run' puma (3.12.1)
lib/puma/thread_pool.rb:135:in
block in spawn_thread' Started GET
"/serviceworker.js" for 127.0.0.1 at 2020-02-20 00:33:18 +0100
你能试试下面的方法吗,
将选项 authenticity_token: true
添加到表单,然后参数再次包含 authenticity_token。并将您的 save_card.js
重命名为 save_card.js.erb
.
保持原样,只更新.submit()
实际问题是在 form.submit()
上作为 HTML
而不是作为 JS
发送。
https://github.com/rails/rails/issues/29546
//from
form.submit();
//to
form.dispatchEvent(new Event('submit', {bubbles: true}));
已更新
之前,您正在提交,然后要求再次提交。单击按钮,获取条带数据,然后提交我的答案。以下示例。
此外,您需要为点击提交按钮添加 disable/enable
,以忽略多次点击。
...
// Create a token or display an error when the form is submitted.
let submitCardBtn = document.getElementById('submit-card');
submitCardBtn.addEventListener('click', function(event) {
event.preventDefault();
// disable button
submitCardBtn.disabled = true;
stripe.createToken(card).then(function(result) {
if (result.error) {
// Inform the customer that there was an error.
var errorElement = document.getElementById('card-errors');
errorElement.textContent = result.error.message;
// enable button on false
submitCardBtn.disabled = false;
} else {
// Send the token to your server.
stripeTokenHandler(result.token);
}
});
});
function stripeTokenHandler(token) {
// Insert the token ID into the form so it gets submitted to the server
var form = document.getElementById('payment-form');
var hiddenInput = document.createElement('input');
hiddenInput.setAttribute('type', 'hidden');
hiddenInput.setAttribute('name', 'stripeToken');
hiddenInput.setAttribute('value', token.id);
form.appendChild(hiddenInput);
// Submit the form
form.dispatchEvent(new Event('submit', {bubbles: true}));
// enable button
submitCardBtn.disabled = false;
}
假设您在 Rails 5.X 并且您的 application.js
文件中有 //= require rails-ujs
而不是 form.submit()
,使用 Rails.fire(form, 'submit')
将允许您通过 Ajax
提交表单
我有一个 form_tag 使用 Ajax 通过 Stripe 保存新用户卡。它呈现一个 Stripe 卡片表单,将输入传递给控制器方法,然后应该提供一个 js 文件。它在没有 Stripe 的情况下工作,但有了它,我遇到了身份验证问题。
基本代码如下:
<%= form_tag(save_card_path, id:'payment-form', remote: true) do %>
<div id="card-element">
<!-- A Stripe Element will be inserted here. -->
</div>
<button id="submit-card" class="submit-btn">Save Card</button>
<% end %>
<script type="text/javascript">
var stripe = Stripe('<%= @stripe_public %>');
var elements = stripe.elements();
// Custom styling can be passed to options when creating an Element.
var style = {
base: {
// Add your base input styles here. For example:
fontSize: '20px',
color: "#32325d",
}
};
// Create an instance of the card Element.
var card = elements.create('card', {style: style});
// Add an instance of the card Element into the `card-element` <div>.
card.mount('#card-element');
card.addEventListener('change', function(event) {
var displayError = document.getElementById('card-errors');
if (event.error) {
displayError.textContent = event.error.message;
} else {
displayError.textContent = '';
}
});
// Create a token or display an error when the form is submitted.
var form = document.getElementById('payment-form');
form.addEventListener('submit', function(event) {
event.preventDefault();
stripe.createToken(card).then(function(result) {
if (result.error) {
// Inform the customer that there was an error.
var errorElement = document.getElementById('card-errors');
errorElement.textContent = result.error.message;
} else {
// Send the token to your server.
stripeTokenHandler(result.token);
}
});
});
function stripeTokenHandler(token) {
// Insert the token ID into the form so it gets submitted to the server
var form = document.getElementById('payment-form');
var hiddenInput = document.createElement('input');
hiddenInput.setAttribute('type', 'hidden');
hiddenInput.setAttribute('name', 'stripeToken');
hiddenInput.setAttribute('value', token.id);
form.appendChild(hiddenInput);
// Submit the form
form.submit();
}
</script>
card_controller.rb
def save_card
respond_to do |format|
format.js
end
end
save_card.js.erb
$("html").hide();
就像我说的,没有 Stripe 代码一切正常,并且参数中存在 authenticity_token
,但是我上面写的代码给出了以下错误:
def handle_unverified_request
raise ActionController::InvalidAuthenticityToken
end
只有参数:
{"utf8"=>"✓", "stripeToken"=>"<token>"}
当我将选项 authenticity_token: true
添加到表单时,参数再次包含一个 authenticity_token
,但现在当它到达 format.js
行时,我得到错误
ActionController::UnknownFormat
我在尝试通过 Ajax 以表单形式上传文件时曾 运行 遇到过类似的问题,但我发现了 remotipart gem,这就解决了它。但在这种情况下似乎没有帮助。
有谁知道为什么包含 Stripe 字段会摆脱我的 authenticity_token,以及为什么即使使用 authenticity_token,也无法识别 js 格式?
编辑:
Jquery-ujs 通过 //= require jquery_ujs
行包含在我的 application.js
中,<%= csrf_meta_tags %>
行包含在 application.html.erb
中,我的源代码包括行
<meta name="csrf-param" content="authenticity_token" />
<meta name="csrf-token" content="<TOKEN>" />
无论我的ajax调用是否有效,都是如此。
更新:
这是我添加选项 authenticity_token: true
:
Started POST "/save_card" for 127.0.0.1 at 2020-02-20 00:07:04 +0100
Processing by UsersController#save_card as HTML
Parameters: {"utf8"=>"✓", "authenticity_token"=>"[LONG TOKEN]", "post"=>"47", "transaction"=>"bid", "stripeToken"=>"[STRIPE TOKEN]"}
User Load (0.9ms)
SELECT "users".* FROM "users" WHERE "users"."id" = ORDER BY "users"."id" ASC LIMIT [["id", 2], ["LIMIT", 1]]
(0.3ms) BEGIN SQL
(2.3ms) INSERT INTO "cards" ("stripe_customer_id", "brand", "last4", "exp_month", "exp_year", "user_id", "created_at", "updated_at") VALUES (, , , , , , , ) RETURNING "id" [["stripe_customer_id", "[STRIPE TOKEN]"], ["brand", "Visa"], ["last4", "4242"], ["exp_month", "4"], ["exp_year", "2024"], ["user_id", 2], ["created_at", "2020-02-19 23:07:05.246789"], ["updated_at", "2020-02-19 23:07:05.246789"]]
(2.8ms) COMMIT
Completed 406 Not Acceptable in 672ms (ActiveRecord: 6.3ms)
ActionController::UnknownFormat (ActionController::UnknownFormat): app/controllers/users_controller.rb:485:in `save_card' Started GET "/serviceworker.js" for 127.0.0.1 at 2020-02-20 00:07:05 +0100 Started GET "/serviceworker.js" for ::1 at 2020-02-20 00:07:21 +0100
这是我删除 authenticity_token: true
:
Started POST "/save_card" for 127.0.0.1 at 2020-02-20 00:33:17 +0100
Processing by UsersController#save_card as HTML
Parameters: {"utf8"=>"✓", "post"=>"47", "transaction"=>"bid", "stripeToken"=>"[STRIPE TOKEN]"} Can't verify CSRF token authenticity. Completed 422 Unprocessable Entity in 1ms (ActiveRecord: 0.0ms)
ActionController::InvalidAuthenticityToken (ActionController::InvalidAuthenticityToken): actionpack (5.1.7) lib/action_controller/metal/request_forgery_protection.rb:195:in
handle_unverified_request' actionpack (5.1.7) lib/action_controller/metal/request_forgery_protection.rb:227:in
handle_unverified_request' devise (4.7.0) lib/devise/controllers/helpers.rb:255:inhandle_unverified_request' actionpack (5.1.7) lib/action_controller/metal/request_forgery_protection.rb:222:in
verify_authenticity_token' activesupport (5.1.7) lib/active_support/callbacks.rb:413:inblock in make_lambda' activesupport (5.1.7) lib/active_support/callbacks.rb:197:in
block (2 levels) in halting' actionpack (5.1.7) lib/abstract_controller/callbacks.rb:12:inblock (2 levels) in <module:Callbacks>' activesupport (5.1.7) lib/active_support/callbacks.rb:198:in
block in halting' activesupport (5.1.7) lib/active_support/callbacks.rb:507:inblock in invoke_before' activesupport (5.1.7) lib/active_support/callbacks.rb:507:in
each' activesupport (5.1.7) lib/active_support/callbacks.rb:507:ininvoke_before' activesupport (5.1.7) lib/active_support/callbacks.rb:130:in
run_callbacks' actionpack (5.1.7) lib/abstract_controller/callbacks.rb:19:inprocess_action' actionpack (5.1.7) lib/action_controller/metal/rescue.rb:20:in
process_action' actionpack (5.1.7) lib/action_controller/metal/instrumentation.rb:32:inblock in process_action' activesupport (5.1.7) lib/active_support/notifications.rb:166:in
block in instrument' activesupport (5.1.7) lib/active_support/notifications/instrumenter.rb:21:ininstrument' activesupport (5.1.7) lib/active_support/notifications.rb:166:in
instrument' actionpack (5.1.7) lib/action_controller/metal/instrumentation.rb:30:inprocess_action' actionpack (5.1.7) lib/action_controller/metal/params_wrapper.rb:252:in
process_action' activerecord (5.1.7) lib/active_record/railties/controller_runtime.rb:22:inprocess_action' actionpack (5.1.7) lib/abstract_controller/base.rb:124:in
process' actionview (5.1.7) lib/action_view/rendering.rb:30:inprocess' actionpack (5.1.7) lib/action_controller/metal.rb:189:in
dispatch' actionpack (5.1.7) lib/action_controller/metal.rb:253:indispatch' actionpack (5.1.7) lib/action_dispatch/routing/route_set.rb:49:in
dispatch' actionpack (5.1.7) lib/action_dispatch/routing/route_set.rb:31:inserve' actionpack (5.1.7) lib/action_dispatch/journey/router.rb:50:in
block in serve' actionpack (5.1.7) lib/action_dispatch/journey/router.rb:33:ineach' actionpack (5.1.7) lib/action_dispatch/journey/router.rb:33:in
serve' actionpack (5.1.7) lib/action_dispatch/routing/route_set.rb:844:incall' serviceworker-rails (0.6.0) lib/serviceworker/middleware.rb:35:in
call' remotipart (1.4.3) lib/remotipart/middleware.rb:32:incall' warden (1.2.8) lib/warden/manager.rb:36:in
block in call' warden (1.2.8) lib/warden/manager.rb:34:incatch' warden (1.2.8) lib/warden/manager.rb:34:in
call' rack (2.0.7) lib/rack/etag.rb:25:incall' rack (2.0.7) lib/rack/conditional_get.rb:38:in
call' rack (2.0.7) lib/rack/head.rb:12:incall' rack (2.0.7) lib/rack/session/abstract/id.rb:232:in
context' rack (2.0.7) lib/rack/session/abstract/id.rb:226:incall' actionpack (5.1.7) lib/action_dispatch/middleware/cookies.rb:613:in
call' activerecord (5.1.7) lib/active_record/migration.rb:556:incall' actionpack (5.1.7) lib/action_dispatch/middleware/callbacks.rb:26:in
block in call' activesupport (5.1.7) lib/active_support/callbacks.rb:97:inrun_callbacks' actionpack (5.1.7) lib/action_dispatch/middleware/callbacks.rb:24:in
call' actionpack (5.1.7) lib/action_dispatch/middleware/executor.rb:12:incall' actionpack (5.1.7) lib/action_dispatch/middleware/debug_exceptions.rb:59:in
call' web-console (3.7.0) lib/web_console/middleware.rb:135:incall_app' web-console (3.7.0) lib/web_console/middleware.rb:30:in
block in call' web-console (3.7.0) lib/web_console/middleware.rb:20:incatch' web-console (3.7.0) lib/web_console/middleware.rb:20:in
call' actionpack (5.1.7) lib/action_dispatch/middleware/show_exceptions.rb:31:incall' railties (5.1.7) lib/rails/rack/logger.rb:36:in
call_app' railties (5.1.7) lib/rails/rack/logger.rb:24:inblock in call' activesupport (5.1.7) lib/active_support/tagged_logging.rb:69:in
block in tagged' activesupport (5.1.7) lib/active_support/tagged_logging.rb:26:intagged' activesupport (5.1.7) lib/active_support/tagged_logging.rb:69:in
tagged' railties (5.1.7) lib/rails/rack/logger.rb:24:incall' sprockets-rails (3.2.1) lib/sprockets/rails/quiet_assets.rb:13:in
call' actionpack (5.1.7) lib/action_dispatch/middleware/remote_ip.rb:79:incall' actionpack (5.1.7) lib/action_dispatch/middleware/request_id.rb:25:in
call' rack (2.0.7) lib/rack/method_override.rb:22:incall' rack (2.0.7) lib/rack/runtime.rb:22:in
call' activesupport (5.1.7) lib/active_support/cache/strategy/local_cache_middleware.rb:27:incall' actionpack (5.1.7) lib/action_dispatch/middleware/executor.rb:12:in
call' actionpack (5.1.7) lib/action_dispatch/middleware/static.rb:125:incall' rack (2.0.7) lib/rack/sendfile.rb:111:in
call' railties (5.1.7) lib/rails/engine.rb:522:incall' puma (3.12.1) lib/puma/configuration.rb:227:in
call' puma (3.12.1) lib/puma/server.rb:660:inhandle_request' puma (3.12.1) lib/puma/server.rb:474:in
process_client' puma (3.12.1) lib/puma/server.rb:334:inblock in run' puma (3.12.1) lib/puma/thread_pool.rb:135:in
block in spawn_thread' Started GET "/serviceworker.js" for 127.0.0.1 at 2020-02-20 00:33:18 +0100
你能试试下面的方法吗,
将选项 authenticity_token: true
添加到表单,然后参数再次包含 authenticity_token。并将您的 save_card.js
重命名为 save_card.js.erb
.
保持原样,只更新.submit()
实际问题是在 form.submit()
上作为 HTML
而不是作为 JS
发送。
https://github.com/rails/rails/issues/29546
//from
form.submit();
//to
form.dispatchEvent(new Event('submit', {bubbles: true}));
已更新
之前,您正在提交,然后要求再次提交。单击按钮,获取条带数据,然后提交我的答案。以下示例。
此外,您需要为点击提交按钮添加 disable/enable
,以忽略多次点击。
...
// Create a token or display an error when the form is submitted.
let submitCardBtn = document.getElementById('submit-card');
submitCardBtn.addEventListener('click', function(event) {
event.preventDefault();
// disable button
submitCardBtn.disabled = true;
stripe.createToken(card).then(function(result) {
if (result.error) {
// Inform the customer that there was an error.
var errorElement = document.getElementById('card-errors');
errorElement.textContent = result.error.message;
// enable button on false
submitCardBtn.disabled = false;
} else {
// Send the token to your server.
stripeTokenHandler(result.token);
}
});
});
function stripeTokenHandler(token) {
// Insert the token ID into the form so it gets submitted to the server
var form = document.getElementById('payment-form');
var hiddenInput = document.createElement('input');
hiddenInput.setAttribute('type', 'hidden');
hiddenInput.setAttribute('name', 'stripeToken');
hiddenInput.setAttribute('value', token.id);
form.appendChild(hiddenInput);
// Submit the form
form.dispatchEvent(new Event('submit', {bubbles: true}));
// enable button
submitCardBtn.disabled = false;
}
假设您在 Rails 5.X 并且您的 application.js
文件中有 //= require rails-ujs
而不是 form.submit()
,使用 Rails.fire(form, 'submit')
将允许您通过 Ajax