Rails / Stripe - 付款不会处理

Posted

技术标签:

【中文标题】Rails / Stripe - 付款不会处理【英文标题】:Rails / Stripe - Payment won't process 【发布时间】:2017-01-28 08:18:28 【问题描述】:

我正在使用 Rails 和 Stripe 构建一个事件应用程序来处理付款。我在 Booking 模型中设置了一个预留方法来处理付款流程。

代码必须能够允许用户一次预订多个空间。

我没有收到任何错误,但是,每次我尝试处理任何类型的预订时,我都会从我的代码中收到错误消息“预订不成功”。我似乎不明白为什么它直接跳到这里而不是完成付款和预订。

这是我的预订模型中的预订方法 -

    def reserve
    # Don't process this booking if it isn't valid
    return unless valid?

    # We can always set this, even for free events because their price will be 0.
    self.total_amount = quantity * event.price

    # Free events don't need to do anything special
    if event.is_free?
      save

    # Paid events should charge the customer's card
    else
      begin
        charge = Stripe::Charge.create(amount: total_amount, currency: "gbp", card: stripe_token, description: "Booking number #Booking.id", items: [quantity: quantity])
        self.stripe_charge_id = charge.id
        save
      rescue Stripe::CardError => e
        errors.add(:base, e.message)
        false
      end
     end 
  end
end

在我的 bookings_controller 我有以下新的和创建的操作 -

    def new

        @event = Event.find(params[:event_id])
        @booking = @event.bookings.new(quantity: params[:quantity])
        @booking.user = current_user

    end

    def create
    @event = Event.find(params[:event_id])
    @booking = @event.bookings.new(booking_params)
    @booking.user = current_user

        if @booking.reserve
            flash[:success] = "Your place on our event has been booked"
            redirect_to event_path(@event)
        else
            flash[:error] = "Booking unsuccessful"
            render "new"
        end
    end


    private

    def booking_params
        params.require(:booking).permit(:stripe_token, :quantity)
    end

是什么导致@booking.reserve 失败并且代码只是默认为 Flash 错误消息?

这是我认为的代码。我需要在我的 Stripe javascript 代码中添加任何内容吗?

booking.new.html.erb

<div class="col-md-6 col-md-offset-3" id="eventshow">
  <div class="row">
    <div class="panel panel-default">
        <div class="panel-heading">
            <h2>Confirm Your Booking</h2>
        </div>
                  <div class="calculate-total">
                              <p>
                                  Confirm number of spaces you wish to book here:
                                    <input type="number" placeholder="1"  min="1" value="1" class="num-spaces">
                              </p>
                                <p>
                                    Total Amount
                                    £<span class="total" data-unit-cost="<%= @event.price %>">0</span>
                                </p>
                          </div>





                <%= simple_form_for [@event, @booking], id: "new_booking" do |form| %>



                 <span class="payment-errors"></span>

                <div class="form-row">
                    <label>
                      <span>Card Number</span>
                      <input type="text" size="20" data-stripe="number"/>
                    </label>
                </div>

                <div class="form-row">
                  <label>
                  <span>CVC</span>
                  <input type="text" size="4" data-stripe="cvc"/>
                  </label>
                </div>

                <div class="form-row">
                    <label>
                        <span>Expiration (MM/YYYY)</span>
                        <input type="text" size="2" data-stripe="exp-month"/>
                    </label>
                    <span> / </span>
                    <input type="text" size="4" data-stripe="exp-year"/>
                </div>
            </div>
            <div class="panel-footer">    

               <%= form.button :submit %>


            </div> 

<% end %>
<% end %>

      </div>
  </div>
</div>  

<script type="text/javascript">
    $('.calculate-total input').on('keyup change', calculateBookingPrice);

function calculateBookingPrice() 
  var unitCost = parseFloat($('.calculate-total .total').data('unit-cost')),
      numSpaces = parseInt($('.calculate-total .num-spaces').val()),
      total = (numSpaces * unitCost).toFixed(2);

  if (isNaN(total)) 
    total = 0;
  

  $('.calculate-total span.total').text(total);


  $(document).ready(calculateBookingPrice)

</script>



<script type="text/javascript" src="https://js.stripe.com/v2/"></script>

<script type="text/javascript">
  Stripe.setPublishableKey('<%= STRIPE_PUBLIC_KEY %>');
  var stripeResponseHandler = function(status, response) 
    var $form = $('#new_booking');

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

  // jQuery(function($)   - changed to the line below
  $(document).on("ready page:load", function () 

    $('#new_booking').submit(function(event) 
      var $form = $(this);

      // Disable the submit button to prevent repeated clicks
      $form.find('input[type=submit]').prop('disabled', true);

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

      // Prevent the form from submitting with the default action
      return false;
    );
  );
</script>

我想知道关键线是不是这个?

  self.stripe_charge_id = charge.id

我需要在我的预订表中添加任何内容吗?这是架构 -

create_table "bookings", force: :cascade do |t|
t.integer  "event_id"
t.integer  "user_id"
t.string   "stripe_token"
t.datetime "created_at",   null: false
t.datetime "updated_at",   null: false
t.integer  "quantity"
t.integer  "total_amount"
  end

我对 Rails 还很陌生,这是我第一次尝试实现这样的支付流程。我敢肯定,对于有经验的人来说,这可能是直截了当的。任何援助将不胜感激。

问题更新 - 25/09/16

我对我的问题做了一些工作,我发现这条线正在阻止整个“保留”方法继续进行(正如它所暗示的那样)-

  # Don't process this booking if it isn't valid
    return unless valid?

然后我在这一行遇到了一个'undefined method '*' for nil:class' -

 # We can always set this, even for free events because their price will be 0.
    self.total_amount = booking.quantity * event.price

所以,我已经注释掉了这两行,因为我不知道它们为什么不起作用。我希望至少能够进入可以处理付款的阶段,但现在我收到此错误 -

我很确定 source 是我的应用程序的正确选项,我已经尝试为此添加代码,但它没有接受它。什么是正确的选择?

【问题讨论】:

您将card: stripe_token 传递给Stripe::Charge.create。应该是source: stripe_token 试过了。不起作用 - 得到同样的错误。 改成source后的错误信息是什么? 完全一样。它没有改变任何东西。在 "" 和 as self.stripe_token 之间尝试过,但还是一样。 【参考方案1】:

在您的 bookings_controller::create 操作中,您正在使用

访问事件
@event = Event.find(params[:event_id])

我已经检查了 new.html.erb,并且我认为您没有传递事件 id 来创建操作。请检查一下。

使用 javascript 传递 event_id:

var eventID = ""

在您启动 javascript 的视图中添加上述行。

还有

$form.append($('<input type="hidden" name="event_id">').val(eventID));

在 $('#new_booking').submit 函数中添加上述行。

【讨论】:

我会把它放在哪里? 使用隐藏字段将其添加到表单中。然后在控制器操作中,检查 puts 参数和 puts @event。 我该怎么做? 尝试在 行之前添加这个 . 我还需要将 event_id 作为 booking_params 的一部分吗?【参考方案2】:

我在你的后备模型中看到了你这样做

 self.stripe_charge_id = charge.id

但是,根据您的迁移,您没有该字段。所以我建议您在迁移中创建该字段。

我还建议使用save! 而不是save,这样它会引发可以通过rescue 语句来挽救的错误

 begin
   charge = Stripe::Charge.create(
     :amount => total_amount,
     :currency => "gbp",
     :source => stripe_token, # obtained with Stripe.js
     :description => "Booking created for amount #total_amount"
    )
   self.stripe_charge_id = charge.id
   save!
 rescue Stripe::CardError => e
   errors.add(:base, e.message)
   false
end

根据您的错误,您错误地调用了条带 API。您必须提供您没有提供的 source 参数。你可以在https://stripe.com/docs/api/ruby#create_charge阅读更多内容

【讨论】:

那么,我不使用stripe_token 我使用stripe_charge(两者有什么区别)?当我将它添加到我的预订表时,我使用什么作为输入类型 - 字符串? 我已经按照上述方式进行了迁移,但仍然无法处理付款。 这是否像我的 Booking 模型中的 Reserve 方法的引用问题一样简单?我在控制器的创建操作中有@booking.reserve,但在其他任何地方都没有引用它 - 我的新操作是否也需要引用它?是否需要在我的视图中引用它以便调用它?我的视图页面是否需要命名为 booking.create?认为这一定是一件简单的事情,但我想念它。 不,这与轨道对流非常相反。尝试在您的控制器中调试以查看错误。在控制器中的if @booking.reserve 之后,放置一个调试语句puts @booking.errors.inspect。让我知道返回的内容,以便我弄清楚发生了什么 我已经在这方面做了一些工作,它的第一行 - 除非有效,否则返回? - 这阻止了其余的代码。我该如何修改它以便其余代码可以运行?

以上是关于Rails / Stripe - 付款不会处理的主要内容,如果未能解决你的问题,请参考以下文章

在家庭服务器上处理 Stripe 付款时出现禁止 (403) 错误

Stripe 取消 url 不会取消付款,因此 Stripe 不会发送取消付款意图

Rails Stripe - 您必须提供有效卡

Stripe:重复付款失败

使用 ActiveMerchant + Stripe 进行定期付款

Firebase 扩展:使用 Stripe 运行订阅付款不会返回 sessionId