条纹令牌未附加到 Rails 应用程序的请求正文 [英] Stripe token not getting attached to request body for Rails App

查看:43
本文介绍了条纹令牌未附加到 Rails 应用程序的请求正文的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在制作一个 Rails 应用程序,允许用户成为 $X/yr 的订阅用户,但我被困在订阅页面上,无论我做什么,stripeToken 都不会附加到请求中,并且 CreateSubscription.rb 说这客户没有附加的付款来源".我的 turbolinks 已禁用.

我的条纹日志说它正在收到一个带有 POST 正文的请求:电子邮件:raf6000@gmail.com"计划:praducks-yearly"但错误如下抛出 - 因为没有附加到请求的源对象 -错误:类型:invalid_request_error"消息:该客户没有附加的付款来源"

CreateSubscription.rb

class CreateSubscriptiondef self.call(计划,电子邮件地址,令牌)用户,raw_token = CreateUser.call(email_address)订阅 = Subscription.new(计划:计划,用户:用户)开始stripe_sub = nil如果 user.stripe_customer_id.blank?puts "客户是新的"把 token.nil?customer = Stripe::Customer.create(来源:令牌,电子邮件:user.email,计划:plan.stripe_id,)user.stripe_customer_id = customer.id用户.保存!stripe_sub = customer.subscriptions.first别的puts "客户存在"customer = Stripe::Customer.retrieve(user.stripe_customer_id)# 检查客户是否是条带客户,但没有添加源# 如果没有来源,则在此处更新客户:-# 如果 customer.sources.total_count == 0# customer.source = 令牌# 客户.save# 结尾stripe_sub = customer.subscriptions.create(计划:plan.stripe_id)结尾subscription.stripe_id = stripe_sub.id订阅.保存!救援 Stripe::StripeError =>电子subscription.errors[:base] <<电子邮件结尾订阅结尾结尾

CreateUser.rb

class CreateUserdef self.call(email_address)用户 = User.find_by(email: email_address)如果 user.present 返回用户?raw_token, enc_token = Devise.token_generator.generate(用户,:reset_password_token)密码 = SecureRandom.hex(32)用户 = User.create!(电子邮件:电子邮件地址,密码:密码,密码确认:密码,reset_password_token: enc_token,reset_password_sent_at:Time.now)返回用户,raw_token结尾结尾

subscription.js

jQuery(function($) {$('#payment-form').submit(function(event) {var $form = $(this);警报('点击');$form.find('button').prop('disabled', true);Stripe.card.createToken($form, stripeResponseHandler);返回假;});});功能条带响应处理程序(状态,响应){var $form = $('#payment-form');如果(响应.错误){//在表单上显示错误$form.find('.payment-errors').text(response.error.message);$form.find('button').prop('disabled', false);} 别的 {//响应包含 id 和 card,其中包含额外的卡片详细信息var token = response.id;//将令牌插入到表单中,以便将其提交给服务器$form.append($('<input type="hidden" name="stripeToken"/>').val(token));//并提交$form.get(0).submit();}};

订阅控制器

class SubscriptionsController <应用控制器before_filter :authenticate_user!before_filter :load_plans定义索引# 如果 !current_user.subscription.nil?# redirect_to edit_subscription_path# 结尾结尾定义新@subscription = Subscription.new@plan = Plan.find_by_id(params[:plan_id])如果@plan.nil?redirect_to subscriptions_path, :notice =>请先选择一个方案."结尾结尾定义创建@plan = Plan.find(params[:plan_id])puts params[:stripeToken]@subscription = CreateSubscription.call(@计划,参数[:email_address],参数[:stripeToken])如果@subscription.errors.blank?flash[:notice] = '感谢您的升级!' +'在 Praducks.com 享受您的高级会员资格.' +我们还向您发送了一封电子邮件,其中包含您购买的详细信息."重定向到/"别的渲染:新结尾结尾定义编辑@subscription = current_user.subscription如果@subscription.nil?redirect_to subscriptions_path, :notice =>请在进行更改之前先加入会员"结尾结尾定义更新@subscription = current_user.subscription@subscription = ChangeSubscriptionCard.call(@订阅,参数[:stripeToken])如果@subscription.errors.blank?flash[:notice] = '账户更新!'重定向到/"别的渲染:编辑结尾结尾受保护def load_plans@plans = Plan.where(published: true).order('amount')结尾私人的# 永远不要相信来自可怕互联网的参数,只允许白名单通过.def subscriptions_paramsparams.require(:subscription).permit(:email_address, :stripeToken)结尾结尾

new.html.erb

<!--<link href="//netdna.bootstrapcdn.com/twitter-bootstrap/2.3.2/css/bootstrap-combined.min.css" rel="stylesheet">--><div class="col2"><div class="shoppingcart"><% 除非@subscription.errors.blank?%><%=@subscription.errors.full_messages.to_sentence %><%结束%><h4 class="heading colr">加入<%=@plan.name %></h4><div class="clear"></div><div class="cart_form"><div class="form_cont"><%= form_for @subscription, url: subscription_path, html: { id: 'payment-form' } do |f|%><input type="hidden" name="plan_id" value="<%= @plan.id %>"/><input type="hidden" name="stripeEmail" value="<%= current_user.email %>"/><input type="hidden" name="email_address" value="<%= current_user.email %>"/><span class="payment-errors"></span><%= f.label :Email_Address %>: <%= current_user.email %><div class="clear"></div><%= f.label :Card_Number %><div class="clear"></div><input type="text" size="20" data-stripe="number"/>*<div class="clear"></div><%=f.label:CVC%><div class="clear"></div><input type="text" size="4" data-stripe="cvc"/>*<div class="clear"></div><%= f.label :"过期时间 (MM/YYYY)" %><div class="clear"></div><input type="text" data-stripe="exp-month" placeholder="mm" id="exp" limit="2"/><input type="text" data-stripe="exp-year" placeholder="yyyy" id="exp" limit="4"/>*<div class="clear"></div><button type="submit">加入</button><%结束%>

application.html.erb

 <%= full_title(yield(:title)) %><% if params[:beta] == "1" %><% session[:beta] = "1" %><%结束%><!--CSS--><%= stylesheet_link_tag 'application', media: 'all' %><!--<%= javascript_include_tag '应用程序',输入:'text/javascript'%>--><script type="text/javascript" src="https://s3-us-west-2.amazonaws.com/praducks-uploads/jquery.min.js"></script><link rel="stylesheet" href="//maxcdn.bootstrapcdn.com/font-awesome/4.3.0/css/font-awesome.min.css"><%= csrf_meta_tags %><meta name="viewport" content="width=device-width, initial-scale=1"/><!-- Prelang: Analytics/Google Analytics --><%= analytics_init 如果 Rails.env.production?或 Rails.env.development?%><!--Javascript--><script type="text/javascript" src="https://js.stripe.com/v2/"></script><script type="text/javascript">$(函数(){Stripe.setPublishableKey('<%= Rails.configuration.stripe[:publishable_key] %>');});<script type="text/javascript" src="/js/subscriptions.js"></script><body data-no-turbolink><div id ="wrapper_sec"><% if Rails.env.production?%><% if session[:beta] == "1" %><%=渲染部分:元素/导航栏"%><%= bootstrap_flash %><!-- 面包屑区--><%= render partial: "elements/crumbs" 除非 current_page?(root_url) %><div class="clear"></div><%=产率%><%=渲染部分:元素/页脚"%><%其他%><%=渲染布局/即将推出"%><%结束%><%其他%><%=渲染部分:元素/导航栏"%><%= bootstrap_flash %><!-- 横幅--><%= 如果 current_page?(root_url) %,则渲染元素/横幅"<!-- 面包屑区--><%=渲染部分:元素/面包屑"%><div class="clear"></div><div id="content_sec"><%=渲染元素/左导航"%><%=产率%>

<%=渲染部分:元素/页脚"%><%结束%>

解决方案

在本地运行这段代码后,我看到了一些事情:

我注意到使用 rails 辅助方法 javascript_include_tag 未包含 subscriptions.js.除非您已将脚本放在应用的 public/js 文件夹中,否则您的脚本可能不在页面上.

假设你在 public/js 中确实有它并且它在页面上,我在提交表单时注意到这个错误:

未捕获的类型错误:$form.find(...).prop 不是函数

由于此错误,您的提交处理程序永远不会到达 return false 以防止表单提交,因此它在没有条带令牌的情况下提交.

页面上的 jquery 版本是 1.3.2,.prop 不可用,这是导致此错误的原因.

如果您不想升级您的 jquery 版本,您可以将 .prop 替换为 .attr:

$form.find('button').prop('disabled', true);

变成:

$form.find('button').attr('disabled', true);

此外,如果您想确保表单不提交(假设启用了 javascript),我通常会在提交处理程序的最开始添加这一行:

event.preventDefault();

这应该确保您的表单不会提交.您还可以删除处理程序末尾的 return false,因为这不再需要.

I am making a Rails App that allows users to become subscribing users for $X/yr and I am stuck on the subscriptions page where whatever I do the stripeToken doesn't get attached to the request and CreateSubscription.rb says "This customer has no attached payment source". My turbolinks is disabled.

My Stripe Logs say that it is getting a request with the POST body: email: "raf6000@gmail.com" plan: "praducks-yearly" but the error is thrown as follows - as there is no source object attached to request - error: type: "invalid_request_error" message: "This customer has no attached payment source"

CreateSubscription.rb

class CreateSubscription
  def self.call(plan, email_address, token)
    user, raw_token = CreateUser.call(email_address)

    subscription = Subscription.new(
      plan: plan,
      user: user
    )

    begin
      stripe_sub = nil
      if user.stripe_customer_id.blank?
        puts "Customer is new"
        puts token.nil?
        customer = Stripe::Customer.create(
          source: token,
          email: user.email,
          plan: plan.stripe_id,
        )
        user.stripe_customer_id = customer.id
        user.save!
        stripe_sub = customer.subscriptions.first
      else
        puts "Customer exists"
        customer = Stripe::Customer.retrieve(user.stripe_customer_id)
        # Check if the customer was a stripe customer, but had no source added
        # If no source then update customer here:-
        # if customer.sources.total_count == 0
        #   customer.source = token
        #   customer.save
        # end
        stripe_sub = customer.subscriptions.create(
          plan: plan.stripe_id
        )
      end

      subscription.stripe_id = stripe_sub.id

      subscription.save!
    rescue Stripe::StripeError => e
      subscription.errors[:base] << e.message
    end

    subscription
  end 
end

CreateUser.rb

class CreateUser
  def self.call(email_address)

    user = User.find_by(email: email_address)

    return user if user.present?

    raw_token, enc_token = Devise.token_generator.generate(
      User, :reset_password_token)
    password = SecureRandom.hex(32)

    user = User.create!(
      email: email_address,
      password: password,
      password_confirmation: password,
      reset_password_token: enc_token,
      reset_password_sent_at: Time.now
    )

    return user, raw_token
  end
end

subscription.js

jQuery(function($) {
  $('#payment-form').submit(function(event) {
    var $form = $(this);
    alert('CLICKED');
    $form.find('button').prop('disabled', true);

    Stripe.card.createToken($form, stripeResponseHandler);

    return false;
  });
});

function stripeResponseHandler(status, response) {
  var $form = $('#payment-form');

  if (response.error) {
    // Show the errors on the form
    $form.find('.payment-errors').text(response.error.message);
    $form.find('button').prop('disabled', false);
  } else {
    // response contains id and card, which contains additional card details
    var token = response.id;
    // Insert the token into the form so it gets submitted to the server
    $form.append($('<input type="hidden" name="stripeToken" />').val(token));
    // and submit
    $form.get(0).submit();
  }
};

SubscriptionsController

class SubscriptionsController < ApplicationController
  before_filter :authenticate_user!
  before_filter :load_plans

  def index
    # if !current_user.subscription.nil?
    #   redirect_to edit_subscription_path
    # end
  end

  def new
    @subscription = Subscription.new
    @plan = Plan.find_by_id(params[:plan_id])
    if @plan.nil?
      redirect_to subscriptions_path, :notice => "Please select a plan first."
    end
  end

  def create
    @plan = Plan.find(params[:plan_id])
    puts params[:stripeToken]
    @subscription = CreateSubscription.call(
      @plan,
      params[:email_address],
      params[:stripeToken]
    )
    if @subscription.errors.blank?
      flash[:notice] = 'Thank you for your upgrade! ' +
        'Enjoy your premium membership at Praducks.com. ' +
        'We also sent you an email with the details of your purchase.'
      redirect_to '/'
    else
      render :new
    end
  end

  def edit
    @subscription = current_user.subscription
    if @subscription.nil?
      redirect_to subscriptions_path, :notice => "Please join a membership before making changes"
    end
  end

  def update
    @subscription = current_user.subscription
    @subscription = ChangeSubscriptionCard.call(
      @subscription,
      params[:stripeToken]
      )
    if @subscription.errors.blank?
      flash[:notice] = 'Account updated!'
      redirect_to '/'
    else
      render :edit
    end
  end

  protected

  def load_plans
    @plans = Plan.where(published: true).order('amount')
  end

  private

  # Never trust parameters from the scary internet, only allow the white list through.
  def subscriptions_params
    params.require(:subscription).permit(:email_address, :stripeToken)
  end


end

new.html.erb

<!--<link href="//netdna.bootstrapcdn.com/twitter-bootstrap/2.3.2/css/bootstrap-combined.min.css" rel="stylesheet">-->

<div class="col2">
  <div class="shoppingcart">
    <% unless @subscription.errors.blank? %>
      <%= @subscription.errors.full_messages.to_sentence %>
    <% end %>
    <h4 class="heading colr">Joining <%= @plan.name %></h4>
    <div class="clear"></div>
    <div class="cart_form">
      <div class="form_cont">
        <%= form_for @subscription, url: subscription_path, html: { id: 'payment-form' } do |f| %>
          <input type="hidden" name="plan_id" value="<%= @plan.id %>" />
          <input type="hidden" name="stripeEmail" value="<%= current_user.email %>" />
          <input type="hidden" name="email_address" value="<%= current_user.email %>" />
          <span class="payment-errors"></span>

          <%= f.label :Email_Address %>: <%= current_user.email %>
          <div class="clear"></div>

          <%= f.label :Card_Number %>
          <div class="clear"></div>
          <input type="text" size="20" data-stripe="number"/>*
          <div class="clear"></div>
          <%= f.label :CVC %>
          <div class="clear"></div>
          <input type="text" size="4" data-stripe="cvc"/>*
          <div class="clear"></div>
          <%= f.label :"Expiration (MM/YYYY)" %>
          <div class="clear"></div>
          <input type="text" data-stripe="exp-month" placeholder="mm" id="exp" limit="2"/>
          <input type="text" data-stripe="exp-year" placeholder="yyyy" id="exp" limit="4"/>*
          <div class="clear"></div>
          <button type="submit">Join</button>
        <% end %>
      </div>
    </div>
  </div>
</div>

application.html.erb

  <title><%=  full_title(yield(:title)) %></title>
  <% if params[:beta] == "1" %>
    <% session[:beta] = "1" %>
  <% end %>
  <!--CSS-->
  <%= stylesheet_link_tag    'application', media: 'all'  %>

  <!--<%= javascript_include_tag 'application', type: 'text/javascript'%>-->

  <script type="text/javascript" src="https://s3-us-west-2.amazonaws.com/praducks-uploads/jquery.min.js"></script>

  <link rel="stylesheet" href="//maxcdn.bootstrapcdn.com/font-awesome/4.3.0/css/font-awesome.min.css">
  <%= csrf_meta_tags %>
  <meta name="viewport" content="width=device-width, initial-scale=1"/><!-- Prelang: Analytics / Google Analytics -->
  <%= analytics_init if Rails.env.production? or Rails.env.development? %>

  <!--Javascript-->
  <script type="text/javascript" src="https://js.stripe.com/v2/"></script>
  <script type="text/javascript">
    $(function(){
    Stripe.setPublishableKey('<%= Rails.configuration.stripe[:publishable_key] %>');
    });
  </script>
  <script type="text/javascript" src="/js/subscriptions.js"></script>

</head>
<body data-no-turbolink>
<div id ="wrapper_sec">

  <% if Rails.env.production? %>
    <% if session[:beta] == "1" %>
      <%= render partial: "elements/navbar" %>
      <%= bootstrap_flash %>
      <!-- Bread Crumb Section -->
      <%= render partial: "elements/crumbs" unless current_page?(root_url) %>
      <div class="clear"></div>
      <%= yield %>
      <%= render partial: "elements/footer" %>
    <% else %>
      <%= render "layouts/comingsoon" %>
    <% end %>
  <% else %>
    <%= render partial: "elements/navbar" %>
    <%= bootstrap_flash %>
    <!-- Banner -->
    <%= render "elements/banner" if current_page?(root_url) %>
    <!-- Bread Crumb Section -->
    <%= render partial: "elements/crumbs" %>
    <div class="clear"></div>
    <div id="content_sec">
      <%= render "elements/leftnav" %>
      <%= yield %>
    </div>
    <%= render partial: "elements/footer" %>
  <% end %>

</div>
</body>

解决方案

After running this code locally I saw a couple of things:

I noticed that subscriptions.js isn't being included using the rails helper method javascript_include_tag. Unless you've placed your script in your app's public/js folder than your script probably isn't on the page.

Assuming that you do have it in public/js and it is on the page, I noticed this error when submitting the form:

Uncaught TypeError: $form.find(...).prop is not a function

Because of this error, your submit handler never reaches the return false to prevent the form from submitting thus it submits without the stripe token.

The version of jquery that's on the page is 1.3.2 which .prop isn't available for which is the reason for this error.

If you don't want to upgrade your version of jquery you can replace .prop with .attr:

$form.find('button').prop('disabled', true);

becomes:

$form.find('button').attr('disabled', true);

Also, if you want to ensure that the form doesn't submit (assuming javascript is enabled) I typically add this line at the very beginning of my submit handler:

event.preventDefault();

This should ensure that your form doesn't submit. You can also remove the return false at the end of your handler as that would no longer be required.

这篇关于条纹令牌未附加到 Rails 应用程序的请求正文的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
其他开发最新文章
热门教程
热门工具
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆