Статьи

Полосные подписки в Rails

Бизнес-модель подписки

Выбор правильного платежного решения для вашего приложения может быть сложным, особенно если вы работаете на глобальном рынке. Перспектива работы с нормативными актами по конкретной стране — это не то, чего я жду, когда приступлю к новому проекту. Кроме того, есть много шаблонов, с которыми вы должны справиться, чтобы заставить работать регулярный биллинг. 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'} 

ПРИМЕЧАНИЕ: вы должны использовать тестовую карту в режиме разработки. Вы можете найти более подробную информацию здесь .

stripe_form

Запустите этот вид в браузере, и вы увидите кнопку «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:

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 .