Выбор правильного платежного решения для вашего приложения может быть сложным, особенно если вы работаете на глобальном рынке. Перспектива работы с нормативными актами по конкретной стране — это не то, чего я жду, когда приступлю к новому проекту. Кроме того, есть много шаблонов, с которыми вы должны справиться, чтобы заставить работать регулярный биллинг. Stripe, кажется, понимает боль, с которой сталкиваются тысячи разработчиков каждый день, и хорошо ее решает. В этой статье я покажу, как интегрировать Stripe в ваше приложение Rails. Читай дальше.
Настройка
Прежде чем мы начнем, вам понадобится ключ API Stripe. Вы можете получить его, зарегистрировавшись в Stripe, указав свои банковские реквизиты. Есть два разных набора ключей, один для вашего теста и один для производства.
Давайте начнем с настройки клиента Stripe. Добавьте это в свой Gemfile :
gem 'stripe', :git => 'https://github.com/stripe/stripe-ruby'
и bundle install
.
Как только вы закончите установку своих зависимостей, вам нужно настроить ключи API. В производстве вы должны хранить эти ключи в переменной окружения и извлекать их из базы кода. Но для краткости я собираюсь установить их в инициализаторе. Пожалуйста, воздержитесь от бросать в меня вилами… 🙂
# config/initializers/stripe.rb #todo remove the key info from this file and have env variable #todo recreate new API keys when do that if Rails.env == 'production' Rails.configuration.stripe = { :publishable_key => MY_PUBLISHABLE_KEY, :secret_key => MY_SECRET_KEY } else Rails.configuration.stripe = { :publishable_key => TEST_MY_PUBLISHABLE_KEY, :secret_key => TEST_MY_SECRET_KEY } end Stripe.api_key = Rails.configuration.stripe[:secret_key]
После этого давайте настроим нашу страницу оплаты.
Создание вашего первого заряда
Формы оплаты сложны до смешного. Есть множество сценариев, которые нужно рассмотреть, и один неверный шаг может вывести вас из бизнеса. У Stripe есть простое решение этой проблемы. Все, что вам нужно сделать, это скопировать следующий фрагмент на свою страницу оплаты, и Stripe позаботится обо всем, начиная от получения данных кредитной карты пользователя и заканчивая платежом:
# views/stripe_checkout.haml = form_tag('/stripe_checkout',{method: :post}) do %script{src: "https://checkout.stripe.com/checkout.js", class: "stripe-button", 'data-key'=> "#{Rails.configuration.stripe[:publishable_key]}", 'data-amount'=> 10.0, 'data-email' => "[email protected]", 'data-currency' => 'USD'}
ПРИМЕЧАНИЕ: вы должны использовать тестовую карту в режиме разработки. Вы можете найти более подробную информацию здесь .
Запустите этот вид в браузере, и вы увидите кнопку «Pay with Stripe». При щелчке открывается модальный способ получения информации о кредитной карте пользователя и авторизуется. Карта пользователя еще не была списана, Stripe просто авторизовала карту и сказала, что карта действительна. Это происходит в фоновом режиме, и когда Stripe завершит необходимые проверки, он отправит сообщение в /stripe_checkout
точку /stripe_checkout
, указанную в форме.
Полосовой обратный вызов к контроллеру:
def stripe_checkout @amount = 10 #This will create a charge with stripe for $10 #Save this charge in your DB for future reference charge = Stripe::Charge.create( :amount => @amount * 100, :currency => "usd", :source => params[:stripeToken], :description => "Test Charge" ) flash[:notice] = "Successfully created a charge" redirect_to '/subscription' end
и rout.rb,
post 'stripe_checkout' => 'subscription#stripe_checkout'
Когда мы получаем обратный вызов от Stripe, он отправляет с ним stripeToken
. Это хешированная ссылка на кредитную карту пользователя с коротким сроком службы. Мы можем использовать модуль Stripe::Charge
чтобы создать заряд с этим токеном до его истечения. Stripe ни при каких условиях не отправляет нам номер карты. Таким образом, нам не нужно беспокоиться о безопасности данных кредитной карты пользователя.
Поздравляем, вы создали свой первый заряд менее чем за 10 строк кода.
Настройте подписку
Stripe значительно упрощает интеграцию подписок в ваше приложение. Во-первых, вам нужно создать кучу планов на своей панели. Давайте создадим простую форму, которая будет общаться с Stripe и делать это для нас.
# views/index.html.haml %h1 Create a new subscription = form_tag('/subscription',{method: :post}) do .form-group %label Plan name %input{:type => 'text', :name => 'name'} .form-group %label Plan interval = select_tag 'interval', options_for_select(['month', 'year']), multiple: false, :include_blank => true, class: "form-control" .form-group %label Plan Value %input{:type => 'text', :name => 'amount'} %button{:type => "submit"} Submit to Stripe
,# views/index.html.haml %h1 Create a new subscription = form_tag('/subscription',{method: :post}) do .form-group %label Plan name %input{:type => 'text', :name => 'name'} .form-group %label Plan interval = select_tag 'interval', options_for_select(['month', 'year']), multiple: false, :include_blank => true, class: "form-control" .form-group %label Plan Value %input{:type => 'text', :name => 'amount'} %button{:type => "submit"} Submit to Stripe
,# views/index.html.haml %h1 Create a new subscription = form_tag('/subscription',{method: :post}) do .form-group %label Plan name %input{:type => 'text', :name => 'name'} .form-group %label Plan interval = select_tag 'interval', options_for_select(['month', 'year']), multiple: false, :include_blank => true, class: "form-control" .form-group %label Plan Value %input{:type => 'text', :name => 'amount'} %button{:type => "submit"} Submit to Stripe
,# views/index.html.haml %h1 Create a new subscription = form_tag('/subscription',{method: :post}) do .form-group %label Plan name %input{:type => 'text', :name => 'name'} .form-group %label Plan interval = select_tag 'interval', options_for_select(['month', 'year']), multiple: false, :include_blank => true, class: "form-control" .form-group %label Plan Value %input{:type => 'text', :name => 'amount'} %button{:type => "submit"} Submit to Stripe
и контроллер:
# controllers/subscriptions_controller.rb class SubscriptionController < ApplicationController require "stripe" def create subscription = Stripe::Plan.create( :amount => (params[:amount].to_i)*100, :interval => params[:interval], :name => params[:name], :currency => 'usd', :trial_plan => null :id => SecureRandom.uuid # This ensures that the plan is unique in stripe ) #Save the response to your DB flash[:notice] = "Plan successfully created" redirect_to '/subscription' end end
Здесь мы используем клиент Stripe для создания плана для нас. Параметры включают сумму, интервал, валюту и название плана. Stripe сэкономит сумму в центах, поэтому обязательно умножьте ввод пользователя на 100. Если вы хотите предложить пробный период до фактической trial_plan
клиенту, отправьте trial_plan
вместе с запросом. Помните, что эти планы не могут быть изменены, поэтому, если вам нужно изменить сумму или пробный период, создайте новый план.
Как только план создан в Stripe, он вернет объект плана:
{ interval: "month" name: "Pro" created: 1429342808 amount: 1500 currency: "usd" id: fb2488b5-5e83-49b5-9071-781ca04489c4 object: "plan" livemode: false interval_count: 1 trial_period_days: null metadata: statement_descriptor: null }
В идеале вы должны сохранить это в базе данных, чтобы избежать ненужных циклических переходов с помощью Stripe. Но для этой статьи мы собираемся обойти это и получить планы напрямую.
Создание страницы с ценами
Мы можем использовать модуль плана в Stripe, чтобы получить все планы:
#controllers/subscription_controller.rb #...... def plans @stripe_list = Stripe::Plan.all @plans = @stripe_list[:data] end #......
и по вашему мнению:
.plan-container %ul - @plans.each do |plan| %li.plan .header =plan[:name] .price =(plan[:amount]/100) = form_tag('/subscription_checkout', {method: :post, plan: plan}) do %input{type: "hidden", name: "plan_id", value: plan[:id]} %script{src: "https://checkout.stripe.com/checkout.js", class: "stripe-button", 'data-key'=> "#{Rails.configuration.stripe[:publishable_key]}", 'data-amount'=> (plan[:amount]), 'data-email' => "[email protected]", 'data-currency' => plan[:currency], 'data-image' => '/assets/sitepoint.png'}
и в маршрутах:
post 'subscription_checkout' => 'subscription#subscription_checkout'
Как мы уже говорили ранее, Stripe не заряжает карту в этот момент. Он отправляет данные клиента с stripeToken
на нашу конечную точку.
#controllers/subscription_controller.rb #...... def plans @stripe_list = Stripe::Plan.all @plans = @stripe_list[:data] end # This is the callback from stripe def subscription_checkout plan_id = params[:plan_id] plan = Stripe::Plan.retrieve(plan_id) #This should be created on signup. customer = Stripe::Customer.create( :description => "Customer for [email protected]", :source => params[:stripeToken], :email => "[email protected]" ) # Save this in your DB and associate with the user;s email stripe_subscription = customer.subscriptions.create(:plan => plan.id) flash[:notice] = "Successfully created a charge" redirect_to '/plans' end #......
Полосные подписки обычно связаны с клиентом, поэтому он может взимать их рекурсивно. Stripe::Customer
является эквивалентом нашей модели User
. Это нормальная практика, особенно если вы запускаете службу подписки, чтобы создать клиента с Stripe прямо при регистрации и связать его с пользователем. Но для краткости мы создаем клиента во время подписки.
Веб-хуки
В то время как Stripe автоматически позаботится о выставлении счетов, это происходит асинхронно, и наше приложение не будет знать, была ли успешна зарядка или нет. В случае рекурсивных платежей Stripe взаимодействует с нашим приложением через веб-хуки. Давайте посмотрим, как настроить веб-хуки в нашем приложении Rails.
Сначала откройте панель мониторинга Stripe и добавьте эту конечную точку на вкладку webhook:
И добавьте это в ваши маршруты .
post 'webhooks' => 'subscriptions#webhooks'
и добавьте это в контроллер:
# controllers/subscription_controller.rb # Method responsbile for handling stripe webhooks # reference https://stripe.com/docs/webhooks def webhook begin event_json = JSON.parse(request.body.read) event_object = event_json['data']['object'] #refer event types here https://stripe.com/docs/api#event_types case event_json['type'] when 'invoice.payment_succeeded' handle_success_invoice event_object when 'invoice.payment_failed' handle_failure_invoice event_object when 'charge.failed' handle_failure_charge event_object when 'customer.subscription.deleted' when 'customer.subscription.updated' end rescue Exception => ex render :json => {:status => 422, :error => "Webhook call failed"} return end render :json => {:status => 200} end
Stripe теперь готов к трансляции событий в наше приложение Rails. Приведенный выше код получает событие Stripe и организует его для правильных методов. Вы можете увидеть каждый конкретный тип события здесь .
ПРИМЕЧАНИЕ. В процессе работы вы, вероятно, захотите замаскировать эту конечную точку случайным хешем, иначе сторонней организации будет легко имитировать события Stripe, чтобы получить несанкционированный доступ к вашему приложению.
Завершение
Полоса это замечательный инструмент. Это экономит время разработчиков и помогает компаниям сосредоточиться на своей основной компетенции. Не стесняйтесь добавлять наши комментарии Stripe в комментариях.
Все фрагменты кода, используемые в этой статье, доступны на Github .