Отправка формы с помощью Stripe и Rails

У меня возникла проблема с отправкой новой формы клиента в Stripe. Если я заполню форму сверху вниз, адрес электронной почты, информацию о кредитной карте и нажму «Отправить», форма не будет заполнена («Возникла проблема с вашей кредитной картой»). По окончании полос электронное письмо отправляется, но информация о карте пуста.

Однако, если я сначала заполню информацию о кредитной карте, нажму «Отправить», А ЗАТЕМ заполню адрес электронной почты, все будет работать как надо. В приложении оформляется новая подписка, а в полосе создается новый клиент.

Я уверен, что я что-то делаю не так. Вот код:

новый.html.erb

<h1>Signing up for <%= @subscription.plan.name %></h1>
 <strong><%= @subscription.plan.price %></strong> per month!</p>

 <%= form_for @subscription do |f| %>
   <% if @subscription.errors.any? %>
     <div class="error_messages">
       <h2><%= pluralize(@subscription.errors.count, "error") %> prohibited this subscription from being saved:</h2>
       <ul>
       <% @subscription.errors.full_messages.each do |msg| %>
         <li><%= msg %></li>
       <% end %>
       </ul>
     </div>
   <% end %>

   <%= f.hidden_field :plan_id %>

   <%= f.hidden_field :stripe_card_token %>

   <div class="field">
     <%= f.label :email %>
     <%= f.text_field :email, "data-stripe" => "email" %>
   </div>

   <% if @subscription.stripe_card_token.present? %>
     <p>Credit card has been provided.</p>
   <% else %>
     <div class="field">
       <%= label_tag :card_number, "Credit Card Number" %>
       <%= text_field_tag :card_number, nil, name: nil, "data-stripe" => "number" %>
     </div>
     <div class="field">
       <%= label_tag :card_code, "Security Code on Card (CVV)" %>
       <%= text_field_tag :card_code, nil, name: nil, "data-stripe" => "cvc" %>
     </div>
     <div class="field">
       <%= label_tag :card_month, "Card Expiration" %>
       <%= text_field_tag :card_month, nil, name: nil, "data-stripe" => "exp-month", class: "input-mini", "placeholder" => "MM" %>
      <%= text_field_tag :card_year, nil, name: nil, "data-stripe" => "exp-year", class: "input-mini", "placeholder" => "YYYY" %>
     </div>
   <% end %>
   <div id="stripe_error">
     <noscript>JavaScript is not enabled and is required for this form. First enable it in your web browser settings.</noscript>
   </div>
   <div class="actions">
     <%= f.submit "Subscribe", class: "btn btn-primary" %>
   </div>
 <% end %>

subcriptions_controller.rb

    class SubscriptionsController < ApplicationController

  def index
    @subscriptions = Subscription.all
  end

  def show
    @subscription = Subscription.find(params[:id])
  end

  def new
    plan = Plan.find(params[:plan_id])
    @subscription = plan.subscriptions.build
  end

  def create
    @subscription = Subscription.new(subscription_params)
    if @subscription.save_with_payment
      redirect_to @subscription, :notice => "Thank you for subscribing!"
    else
      render :new
    end
  end

  private
    def subscription_params
      params.require(:subscription).permit(:plan_id, :email, :stripe_card_token)
    end
end

Модель подписки.рб

class Subscription < ActiveRecord::Base
  before_save { self.email = email.downcase }
  belongs_to :plan
  validates_presence_of :plan_id
  VALID_EMAIL_REGEX = /\A[\w+\-.]+@[a-z\d\-.]+\.[a-z]+\z/i
  validates :email, presence: true, format: { with: VALID_EMAIL_REGEX }

  attr_accessor :stripe_card_token

  def save_with_payment
    if valid?
      customer = Stripe::Customer.create(card: stripe_card_token, email: email, plan: plan_id)
      self.stripe_customer_token = customer.id
      save!
    end
  rescue Stripe::InvalidRequestError => e
    logger.error "Stripe error while creating customer: #{e.message}"
    errors.add :base, "There was a problem with your credit card."
    false
  end
end

И, наконец, javascript (в основном из документации Stripe, но немного модифицированный):

// This identifies your website in the createToken call below
Stripe.setPublishableKey('<%= Rails.configuration.stripe[:publishable_key] %>');

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

  if (response.error) {
    // Show the errors on the form
    $form.find('#stripe_error').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.find($('#subscription_stripe_card_token').val(token));
    // and re-submit
    $form.get(0).submit();
  }
};

jQuery(function($) {
      $('#new_subscription').submit(function(e) {
        var $form = $(this);

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

        Stripe.createToken($form, stripeResponseHandler);

        // Prevent the form from submitting with the default action
        return false;
      });
    });

Спасибо за чтение! Любая помощь будет принята с благодарностью.


person andrewmarkle    schedule 04.11.2013    source источник
comment
Я не знаю, в чем проблема, но это не может быть связано с порядком заполнения полей.   -  person woz    schedule 04.11.2013
comment
Да, что-то еще происходит. Еще одна подсказка, если это поможет, заключается в том, что если я заполню какие-либо данные кредитной карты, скажем, номер карты, но без даты истечения срока действия или CVC, и нажму «Отправить», Stripe отправит сообщение об ошибке, например, отсутствующая дата истечения срока действия или что-то еще. Если я затем заполню форму и нажму «Отправить», она пройдет и заработает. Это похоже на то, что элементы полосы не видны или каким-то образом не инициализируются, когда вы отправляете форму целиком.   -  person andrewmarkle    schedule 04.11.2013


Ответы (1)


Итак, я понял, что здесь происходит. После еще большего количества тестов я понял, что если я нажму кнопку «Обновить» на странице, а затем заполню форму и отправлю ее, это сработает каждый раз. Но если бы я перешел на путь к подписке через приложение, это привело бы к ошибке, если бы вы не обновили страницу вручную после того, как туда попали.

Итак... после долгих поисков я обнаружил, что проблема связана с Turbolinks. Этот пост помог мне понять, как решить проблему: Rails 4: как использовать $(document).ready() с турбо-ссылками. Насколько я могу судить, jQuery не загружал Stripe.js из-за турбо-ссылок.

Есть пара вариантов, как это исправить.

  1. Отключить турбо-ссылки
  2. Добавьте код в свой javascript (см. ссылку выше)
  3. Добавьте гем jquery-turbolinks, который помогает jQuery хорошо работать с турбо-ссылками.

(Я выбрал вариант 3, так как это казалось самым простым решением).

Так или иначе, теперь форма работает!

person andrewmarkle    schedule 10.11.2013
comment
или вы можете указать, что рассматриваемая ссылка не использует Turbolinks - person tommyd456; 11.11.2013