Integration von Stripe- und PayPal-Zahlungsmethoden in Ruby on Rails
Veröffentlicht: 2022-03-11Ein Schlüsselmerkmal für große E-Commerce-Unternehmen wie AliExpress, Ebay und Amazon ist eine sichere Art der Zahlungsabwicklung, die für ihr Geschäft unerlässlich ist. Fällt diese Funktion aus, wären die Folgen verheerend. Dies gilt für Branchenführer und Ruby on Rails-Entwickler, die an E-Commerce-Apps arbeiten.
Cybersicherheit ist unerlässlich, um Angriffe zu verhindern, und eine Möglichkeit, den Transaktionsprozess sicherer zu machen, besteht darin, einen Drittanbieterdienst damit zu beauftragen. Das Einbinden von Zahlungs-Gateways in Ihre Anwendung ist eine Möglichkeit, dieses Ziel zu erreichen, da sie Benutzerautorisierung, Datenverschlüsselung und ein Dashboard bieten, damit Sie den Transaktionsstatus im Handumdrehen verfolgen können.
Es gibt eine Vielzahl von Zahlungs-Gateway-Diensten im Internet, aber in diesem Artikel werde ich mich auf die Integration von Stripe und PayPal in eine Rails-Anwendung konzentrieren. Um nur einige andere zu nennen: Amazon Payments, Square, SecurePay, WorldPay, Authorize.Net, 2Checkout.com, Braintree, Amazon oder BlueSnap.
Funktionsweise der Payment Gateway-Integration

Im Allgemeinen wird es in Ihrer Anwendung ein Formular/eine Schaltfläche geben, wo sich der Benutzer anmelden/Kreditkartendaten eingeben kann. PayPal und Stripe machen diesen ersten Schritt bereits sicherer, indem sie iframe
-Formulare oder popups
verwenden, die verhindern, dass Ihre Anwendung sensible Kreditkarteninformationen des Benutzers speichert, da sie ein Token zurückgeben, das diese Transaktion darstellt. Einige Benutzer fühlen sich möglicherweise auch sicherer, Zahlungen zu verarbeiten, wenn sie wissen, dass ein Drittanbieter den Transaktionsprozess abwickelt, sodass dies auch ein Anreiz für Ihre Anwendung sein kann.
Nach der Authentifizierung der Benutzerinformationen bestätigt ein Zahlungs-Gateway die Zahlung, indem es einen Zahlungsabwickler kontaktiert, der mit Banken kommuniziert, um Zahlungen abzuwickeln. Dadurch wird sichergestellt, dass die Transaktion ordnungsgemäß belastet/gutgeschrieben wird.
Stripe verwendet ein Kreditkartenformular, in dem Kreditkartennummer, CVV und Ablaufdatum abgefragt werden. Der Benutzer muss also Kreditkarteninformationen in die gesicherten Stripe-Eingaben eingeben. Nachdem Sie diese Informationen bereitgestellt haben, verarbeitet Ihr Anwendungs-Back-End diese Zahlung über ein Token.
Im Gegensatz zu Stripe leitet PayPal den Benutzer auf die PayPal-Anmeldeseite weiter. Der Benutzer autorisiert und wählt die Zahlungsmethode über PayPal aus, und auch hier verarbeitet Ihr Backend Token anstelle von sensiblen Benutzerdaten.
Es ist wichtig zu erwähnen, dass Ihr Back-End für diese beiden Zahlungs-Gateways die Fortsetzung der Transaktionsausführung über Stripe- oder PayPal-APIs anfordern sollte, die eine OK/NOK-Antwort geben, sodass Ihre Anwendung den Benutzer entsprechend auf eine Erfolgs- oder Fehlerseite umleiten sollte.
Die Absicht dieses Artikels ist es, eine Kurzanleitung für die Integration dieser beiden Zahlungs-Gateways in einer einzigen Anwendung bereitzustellen. Für alle Tests verwenden wir Sandboxes und Testkonten, die von Stripe und PayPal bereitgestellt werden, um Zahlungen zu simulieren.
Aufstellen
Vor der Integration von Zahlungs-Gateways führen wir ein Setup zum Initialisieren der Anwendung durch Hinzufügen von Edelsteinen, Datenbanktabellen und einer Indexseite durch. Dieses Projekt wurde mit Rails Version 5.2.3 und Ruby 2.6.3 erstellt.
Hinweis: Sie können sich die neuen Rails 6-Funktionen in unserem letzten Artikel ansehen.
Schritt 1: Initialisieren Sie eine Rails-Anwendung.
Initialisieren Sie das Projekt, indem Sie die Projektinitialisierung mit dem Befehl rails
mit Ihrem App-Namen ausführen:
rails new YOUR_APP_NAME
Und cd
in Ihrem Bewerbungsordner.
Schritt 2: Installieren Sie Edelsteine.
Neben Stripe- und PayPal-Edelsteinen wurden einige weitere Edelsteine hinzugefügt:
-
devise
: Wird für die Benutzerauthentifizierung und -autorisierung verwendet -
haml
: Templating-Tool zum Rendern von Benutzerseiten -
jquery-rails
: fürjquery
in den Front-End-Skripten -
money-rails
: zum Anzeigen von formatierten Geldwerten
Zu Ihrem Gemfile
:
gem "devise", ">= 4.7.1" gem "haml" gem "jquery-rails" gem "money-rails"
Führen Sie nach dem Hinzufügen in Ihrer CLI Folgendes aus:
bundle install
Schritt 3: Edelsteine initialisieren.
Einige dieser Gems erfordern neben der Installation über bundle
eine Initialisierung.
Gerät installieren:
rails g devise:install
money-rails
initialisieren :
rails g money_rails:initializer
Initialisieren jquery-rails
indem Sie am Ende von app/assets/javascripts/application.js
Folgendes anhängen:
//= require jquery //= require jquery_ujs
Schritt 4: Tabellen und Migrationen
In diesem Projekt werden drei Tabellen verwendet: Benutzer , Produkte und Bestellungen .
-
Users
: Wird durch devise generiert -
Products
:-
name
-
price_cents
-
Stripe_plan_name
: Eine ID, die einen in Stripe erstellten Abonnementplan darstellt, damit Benutzer ihn abonnieren können. Dieses Feld ist nur für Produkte erforderlich, die einem Stripe-Plan zugeordnet sind. -
paypal_plan_name
: Dasselbe wiestripe_plan_name
, aber für PayPal
-
-
Orders
:-
product_id
-
user_id
-
status
: Dies informiert, ob die Bestellung aussteht, fehlgeschlagen oder bezahlt ist. -
token
: Dies ist ein Token, das von den APIs (entweder Stripe oder PayPal) generiert wird, um eine Transaktion zu initialisieren. -
price_cents
: Ähnlich wie das Produkt, aber verwendet, um diesen Wert im Bestelldatensatz dauerhaft zu machen -
payment_gateway
: Speichert welches Payment Gateway für die Bestellung PayPal oder Stripe verwendet wird -
customer_id
: Diese wird für Stripe verwendet, um den Stripe-Kunden für ein Abonnement zu speichern, und wird in einem späteren Abschnitt ausführlicher erläutert.
-
Um diese Tabellen zu generieren, müssen einige Migrationen generiert werden:
Zum Erstellen der Benutzertabelle . Laufen:
rails g devise User
Zum Erstellen der Produkttabelle . Generieren Sie eine Migration, indem Sie Folgendes ausführen:
rails generate migration CreateProducts name:string stripe_plan_name:string paypal_plan_name:string
Öffnen Sie Ihre erstellte Migrationsdatei, die sich unter db/migrate/
befinden sollte, und nehmen Sie Änderungen vor, damit Ihre Migration ungefähr so aussieht:
class CreateProducts < ActiveRecord::Migration[5.2] def change create_table :products do |t| t.string :name t.string :stripe_plan_name t.string :paypal_plan_name end add_money :products, :price, currency: { present: true } end end
Zum Erstellen der Orders-Tabelle . Generieren Sie eine Migration, indem Sie Folgendes ausführen:
rails generate migration CreateOrders product_id:integer user_id:integer status:integer token:string charge_id:string error_message:string customer_id:string payment_gateway:integer
Öffnen Sie erneut Ihre erstellte Migrationsdatei, die sich unter db/migrate/
befinden sollte, und nehmen Sie Änderungen an dieser Datei vor, damit sie ungefähr so aussieht:
class CreateOrders < ActiveRecord::Migration[5.2] def change create_table :orders do |t| t.integer :product_id t.integer :user_id t.integer :status, default: 0 t.string :token t.string :charge_id t.string :error_message t.string :customer_id t.integer :payment_gateway t.timestamps end add_money :orders, :price, currency: { present: false } end end
Führen Sie Datenbankmigrationen durch, indem Sie Folgendes ausführen:
rails db:migrate
Schritt 5: Erstellen Sie Modelle.
Das Benutzermodell wurde bereits bei der Geräteinstallation erstellt, und es sind keine Änderungen daran erforderlich. Außerdem werden zwei Modelle für Product und Order erstellt.
Produkt. Fügen Sie eine neue Datei hinzu, app/models/product.rb
, mit:
class Product < ActiveRecord::Base monetize :price_cents has_many :orders end
Befehl. Fügen Sie eine neue Datei hinzu, app/models/order.rb
, mit:
class Order < ApplicationRecord enum status: { pending: 0, failed: 1, paid: 2, paypal_executed: 3} enum payment_gateway: { stripe: 0, paypal: 1 } belongs_to :product belongs_to :user scope :recently_created, -> { where(created_at: 1.minutes.ago..DateTime.now) } def set_paid self.status = Order.statuses[:paid] end def set_failed self.status = Order.statuses[:failed] end def set_paypal_executed self.status = Order.statuses[:paypal_executed] end end
Schritt 6: Befüllen Sie die Datenbank.
In der Konsole werden ein Benutzer und zwei Produkte erstellt. Bestelldatensätze werden gemäß Zahlungstests erstellt.
-
rails s
- Rufen Sie in Ihrem Browser
http://localhost:3000
auf - Sie werden auf eine Anmeldeseite weitergeleitet.
- Registrieren Sie einen Benutzer, indem Sie seine E-Mail-Adresse und sein Passwort eingeben.
- In Ihrem Terminal werden die folgenden Protokolle angezeigt, die zeigen, dass ein Benutzer in Ihrer Datenbank erstellt wurde:
User Create (0.1ms) INSERT INTO "users" ("email", "encrypted_password", "created_at", "updated_at") VALUES (?, ?, ?, ?) …
- Erstellen Sie zwei Produkte ohne Abonnements, indem Sie
rails c
und Folgendes hinzufügen:-
Product.create(name: "Awesome T-Shirt", price_cents: 3000)
-
Product.create(name: "Awesome Sneakers", price_cents: 5000)
-
Schritt 7: Erstellen Sie eine Indexseite
Die Hauptseite für das Projekt enthält eine Produktauswahl für Käufe oder Abonnements. Darüber hinaus gibt es einen Abschnitt zur Auswahl der Zahlungsmethode (Stripe oder PayPal). Für jeden Zahlungs-Gateway-Typ wird auch eine Senden-Schaltfläche verwendet, da wir für PayPal ein eigenes Schaltflächendesign über seine JavaScript-Bibliothek hinzufügen werden.
Erstellen Sie zuerst die Routen für den index
und submit
Sie sie in config/routes.rb
.
Rails.application.routes.draw do devise_for :users get '/', to: 'orders#index' post '/orders/submit', to: 'orders#submit' end
index
erstellen und hinzufügen und im Auftragscontroller app/controllers/orders_controller.rb
submit
Die Aktion „ orders#index
“ speichert zwei Variablen, die im Front-End verwendet werden sollen: @products_purchase
mit einer Liste von Produkten ohne Pläne und @products_subscription
mit Produkten mit PayPal- und Stripe-Plänen.
class OrdersController < ApplicationController before_action :authenticate_user! def index products = Product.all @products_purchase = products.where(stripe_plan_name:nil, paypal_plan_name:nil) @products_subscription = products - @products_purchase end def submit end end
Erstellen Sie eine Datei in app/views/orders/index.html.haml
. Diese Datei enthält alle Eingaben, die wir über die Übermittlungsmethode an unser Backend senden, sowie die Interaktion für Zahlungsgateways und Produktauswahl. Hier sind einige Eingabenamensattribute:
-
Orders[product_id]
speichert die Produkt-ID. -
Orders[payment_gateway]
enthält das Zahlungsgateway mit entweder Stripe- oder PayPal-Werten für das andere.
%div %h1 List of products = form_tag({:controller => "orders", :action => "submit" }, {:id => 'order-details'}) do %input{id:'order-type', :type=>"hidden", :value=>"stripe", :name=>'orders[payment_gateway]'} .form_row %h4 Charges/Payments - @products_purchase.each do |product| %div{'data-charges-and-payments-section': true} = radio_button_tag 'orders[product_id]', product.id, @products_purchase.first == product %span{id: "radioButtonName#{product.id}"} #{product.name} %span{id: "radioButtonPrice#{product.id}", :'data-price' => "#{product.price_cents}"} #{humanized_money_with_symbol product.price} %br %h4 Subscriptions - @products_subscription.each do |product| %div = radio_button_tag 'orders[product_id]', product.id, false %span{id: "radioButtonName#{product.id}"} #{product.name} %span{id: "radioButtonPrice#{product.id}", :'data-price' => "#{product.price_cents}"} #{humanized_money_with_symbol product.price} %br %hr %h1 Payment Method .form_row %div = radio_button_tag 'payment-selection', 'stripe', true, onclick: "changeTab();" %span Stripe %br %div = radio_button_tag 'payment-selection', 'paypal', false, onclick: "changeTab();" %span Paypal %br %br %div{id:'tab-stripe', class:'paymentSelectionTab active'} %div{id:'card-element'} %div{id:'card-errors', role:"alert"} %br %br = submit_tag "Buy it!", id: "submit-stripe" %div{id:'tab-paypal', class:'paymentSelectionTab'} %div{id: "submit-paypal"} %br %br %hr :javascript function changeTab() { var newActiveTabID = $('input[name="payment-selection"]:checked').val(); $('.paymentSelectionTab').removeClass('active'); $('#tab-' + newActiveTabID).addClass('active'); } :css #card-element { width:500px; } .paymentSelectionTab { display: none; } .paymentSelectionTab.active { display: block !important; }
Wenn Sie Ihre Anwendung mit rails s
ausführen und Ihre Seite in http://localhost:3000
besuchen. Sie sollten die Seite wie folgt sehen können:

Speicherung von Anmeldeinformationen für das Zahlungsgateway
PayPal- und Stripe-Schlüssel werden in einer Datei gespeichert, die nicht von Git verfolgt wird. In dieser Datei sind für jedes Zahlungs-Gateway zwei Arten von Schlüsseln gespeichert, für die wir vorerst einen Dummy-Wert verwenden. Weitere Anweisungen zum Erstellen dieser Schlüssel werden in weiteren Abschnitten vorgestellt.
Schritt 1: Fügen Sie dies in .gitignore
.
/config/application.yml
Schritt 2: Erstellen Sie eine Datei mit Ihren Anmeldeinformationen in config/application.yml
. Es sollte alle Ihre PayPal- und Stripe-Sandbox-/Testschlüssel für den Zugriff auf diese APIs enthalten.
test: &default PAYPAL_ENV: sandbox PAYPAL_CLIENT_ID: YOUR_CREDENTIAL_HERE PAYPAL_CLIENT_SECRET: YOUR_CREDENTIAL_HERE STRIPE_PUBLISHABLE_KEY: YOUR_CREDENTIAL_HERE STRIPE_SECRET_KEY: YOUR_CREDENTIAL_HERE development: <<: *default
Schritt 3: Um die Variablen aus der Datei config/application.yml
beim Start der Anwendung zu speichern, fügen Sie diese Zeilen in config/application.rb
innerhalb der Application
-Klasse hinzu, damit sie in ENV
verfügbar sind.
config_file = Rails.application.config_for(:application) config_file.each do |key,value| ENV[key] = value end unless config_file.nil?
Stripe-Konfiguration
Wir werden ein Juwel für die Verwendung der Stripe-API hinzufügen: stripe-rails
. Das Erstellen eines Stripe-Kontos ist ebenfalls erforderlich, damit Gebühren und Abonnements verarbeitet werden können. Wenn Sie müssen, können Sie die API-Methoden für die Stripe-API in der offiziellen Dokumentation einsehen.
Schritt 1: Fügen Sie Ihrem Projekt das Stripe-Rails-Juwel hinzu.
Das Stripe-Rails-Gem wird eine Schnittstelle für alle in diesem Projekt verwendeten API-Anforderungen bereitstellen.
Fügen Sie dies in die Gemfile
:
gem 'stripe-rails'
Laufen:
bundle install
Schritt 2: Generieren Sie Ihre API-Schlüssel.
Um die API-Schlüssel für die Kommunikation mit Stripe zu haben, müssen Sie ein Konto in Stripe erstellen. Um die Anwendung zu testen, ist es möglich, den Testmodus zu verwenden, sodass bei der Erstellung eines Stripe-Kontos keine echten Geschäftsinformationen ausgefüllt werden müssen.
- Erstellen Sie ein Konto in Stripe, falls Sie noch keines haben (https://dashboard.stripe.com/).
- Schalten Sie, während Sie sich noch im Stripe-Dashboard befinden, nach der Anmeldung Testdaten anzeigen ein.
- Ersetzen Sie unter https://dashboard.stripe.com/test/apikeys
YOUR_CREDENTIAL_HERE
für die WerteSTRIPE_PUBLISHABLE_KEY
undSTRIPE_SECRET_KEY
in/config/application.yml
durch den Inhalt vonPublishable Key
undSecret key
.
Schritt 3: Stripe-Modul initialisieren
Zusätzlich zum Ersetzen der Schlüssel müssen wir das Stripe-Modul noch initialisieren, damit es die bereits in unserem ENV
festgelegten Schlüssel verwendet.
Erstellen Sie eine Datei in config/initializers/stripe.rb
mit:
Rails.application.configure do config.stripe.secret_key = ENV["STRIPE_SECRET_KEY"] config.stripe.publishable_key = ENV["STRIPE_PUBLISHABLE_KEY"] end
Schritt 4: Integrieren Sie Stripe in das Frontend.
Wir werden die Stripe-JavaScript-Bibliothek und die Logik zum Senden eines Tokens hinzufügen, das die Kreditkarteninformationen des Benutzers darstellt und in unserem Backend verarbeitet wird.
Fügen Sie dies in der Datei index.html.haml
am Anfang Ihrer Datei hinzu. Dadurch wird das Stripe-Modul (vom Gem bereitgestellt) verwendet, um die Stripe-Javascript-Bibliothek zur Seite des Benutzers hinzuzufügen.
= stripe_javascript_tag
Stripe verwendet sichere Eingabefelder, die über ihre API erstellt werden. Da sie in einem über diese API erstellten iframe
erstellt werden, müssen Sie sich keine Gedanken über mögliche Schwachstellen bei der Verarbeitung von Kreditkarteninformationen von Benutzern machen. Darüber hinaus kann Ihr Back-End keine sensiblen Benutzerdaten verarbeiten/speichern und erhält nur ein Token, das diese Informationen darstellt.
Diese Eingabefelder werden durch Aufrufen von stripe.elements().create('card')
erstellt. Danach muss nur noch das zurückgegebene Objekt mit mount()
aufgerufen werden, indem als Argument das HTML-Element id/class übergeben wird, in das diese Eingaben gemountet werden sollen. Weitere Informationen finden Sie bei Stripe.
Wenn der Benutzer mit der Stripe-Zahlungsmethode auf die Schaltfläche „Senden“ klickt, wird ein weiterer API-Aufruf, der ein Versprechen zurückgibt, für das erstellte Stripe-Kartenelement ausgeführt:
stripe.createToken(card).then(function(result)
Die result
dieser Funktion hat, wenn ihr kein Eigenschaftsfehler zugewiesen ist, ein Token, das durch Zugriff auf das Attribut result.token.id
abgerufen werden kann. Dieses Token wird an das Backend gesendet.
Um diese Änderungen vorzunehmen, ersetzen Sie den kommentierten Code // YOUR STRIPE AND PAYPAL CODE WILL BE HERE
in index.html.haml
durch:
(function setupStripe() { //Initialize stripe with publishable key var stripe = Stripe("#{ENV['STRIPE_PUBLISHABLE_KEY']}"); //Create Stripe credit card elements. var elements = stripe.elements(); var card = elements.create('card'); //Add a listener in order to check if card.addEventListener('change', function(event) { //the div card-errors contains error details if any var displayError = document.getElementById('card-errors'); document.getElementById('submit-stripe').disabled = false; if (event.error) { // Display error displayError.textContent = event.error.message; } else { // Clear error displayError.textContent = ''; } }); // Mount Stripe card element in the #card-element div. card.mount('#card-element'); var form = document.getElementById('order-details'); // This will be called when the #submit-stripe button is clicked by the user. form.addEventListener('submit', function(event) { $('#submit-stripe').prop('disabled', true); event.preventDefault(); stripe.createToken(card).then(function(result) { if (result.error) { // Inform that there was an error. var errorElement = document.getElementById('card-errors'); errorElement.textContent = result.error.message; } else { // Now we submit the form. We also add a hidden input storing // the token. So our back-end can consume it. var $form = $("#order-details"); // Add a hidden input orders[token] $form.append($('<input type="hidden" name="orders[token]"/>').val(result.token.id)); // Set order type $('#order-type').val('stripe'); $form.submit(); } }); return false; }); }()); //YOUR PAYPAL CODE WILL BE HERE
Wenn Sie Ihre Seite besuchen, sollte sie mit den neuen sicheren Stripe-Eingabefeldern wie folgt aussehen:

Schritt 5: Testen Sie Ihre Anwendung.
Füllen Sie das Kreditkartenformular mit einer Testkarte aus (https://stripe.com/docs/testing) und senden Sie die Seite ab. Überprüfen Sie, ob die submit
-Aktion mit allen Parametern ( product_id , payment_gateway und token ) in Ihrer Serverausgabe aufgerufen wird.
Stripe-Gebühren
Stripe-Gebühren stellen einmalige Transaktionen dar. Daher würden Sie nach einer Stripe-Aufladungstransaktion direkt Geld vom Kunden erhalten. Dies ist ideal für den Verkauf von Produkten, die nicht mit Plänen verbunden sind. In einem späteren Abschnitt werde ich zeigen, wie man denselben Transaktionstyp mit PayPal durchführt, aber der Name von PayPal für diesen Transaktionstyp ist Payment .
In diesem Abschnitt werde ich auch das gesamte Skelett für die Bearbeitung und Übermittlung einer Bestellung bereitstellen. Wir erstellen eine Bestellung in der submit
, wenn das Stripe-Formular gesendet wird. Diese Bestellung hat zunächst den Status „ ausstehend “. Wenn also bei der Bearbeitung dieser Bestellung etwas schief geht, bleibt die Bestellung noch ausstehend .
Wenn bei Stripe-API-Aufrufen ein Fehler auftritt, setzen wir die Bestellung in einen fehlgeschlagenen Zustand, und wenn die Belastung erfolgreich abgeschlossen wurde, befindet sie sich im bezahlten Zustand. Der Benutzer wird auch gemäß der Stripe-API-Antwort umgeleitet, wie in der folgenden Grafik dargestellt:

Wenn eine Stripe-Gebühr durchgeführt wird, wird außerdem eine ID zurückgegeben. Wir speichern diese ID, damit Sie später bei Bedarf in Ihrem Stripe-Dashboard danach suchen können. Diese ID kann auch verwendet werden, wenn die Bestellung zurückerstattet werden muss. So etwas wird in diesem Artikel nicht untersucht.
Schritt 1: Erstellen Sie den Stripe-Dienst.
Wir werden eine Singleton-Klasse verwenden, um Stripe-Operationen mit der Stripe-API darzustellen. Um eine Gebühr zu erstellen, wird die Methode Stripe::Charge.create
aufgerufen, und das zurückgegebene Objekt-ID-Attribut wird im Auftragsdatensatz charge_id
gespeichert. Diese create
wird aufgerufen, indem das aus dem Frontend stammende Token, der Bestellpreis und eine Beschreibung übergeben werden.
Erstellen Sie also einen neuen Ordner app/services/orders
und fügen Sie einen Stripe-Dienst hinzu: app/services/orders/stripe.rb
, der die Singleton-Klasse Orders::Stripe
enthält, die einen Eintrag in der Methode execute
hat.
class Orders::Stripe INVALID_STRIPE_OPERATION = 'Invalid Stripe Operation' def self.execute(order:, user:) product = order.product # Check if the order is a plan if product.stripe_plan_name.blank? charge = self.execute_charge(price_cents: product.price_cents, description: product.name, card_token: order.token) else #SUBSCRIPTIONS WILL BE HANDLED HERE end unless charge&.id.blank? # If there is a charge with id, set order paid. order.charge_id = charge.id order.set_paid end rescue Stripe::StripeError => e # If a Stripe error is raised from the API, # set status failed and an error message order.error_message = INVALID_STRIPE_OPERATION order.set_failed end private def self.execute_charge(price_cents:, description:, card_token:) Stripe::Charge.create({ amount: price_cents.to_s, currency: "usd", description: description, source: card_token }) end end
Schritt 2: Implementieren Sie die Submit-Aktion und rufen Sie den Stripe-Dienst auf.
Fügen Sie in orders_controller.rb
Folgendes in der submit
-Aktion hinzu, die im Grunde den Dienst Orders::Stripe.execute
. Beachten Sie, dass auch zwei neue private Funktionen hinzugefügt wurden: prepare_new_order
und order_params
.
def submit @order = nil #Check which type of order it is if order_params[:payment_gateway] == "stripe" prepare_new_order Orders::Stripe.execute(order: @order, user: current_user) elsif order_params[:payment_gateway] == "paypal" #PAYPAL WILL BE HANDLED HERE end ensure if @order&.save if @order.paid? # Success is rendered when order is paid and saved return render html: SUCCESS_MESSAGE elsif @order.failed? && [email protected]_message.blank? # Render error only if order failed and there is an error_message return render html: @order.error_message end end render html: FAILURE_MESSAGE end private # Initialize a new order and and set its user, product and price. def prepare_new_order @order = Order.new(order_params) @order.user_id = current_user.id @product = Product.find(@order.product_id) @order.price_cents = @product.price_cents end def order_params params.require(:orders).permit(:product_id, :token, :payment_gateway, :charge_id) end
Schritt 3: Testen Sie Ihre Anwendung.
Überprüfen Sie, ob die Submit-Aktion, wenn sie mit einer gültigen Testkarte aufgerufen wird, eine Umleitung zu einer erfolgreichen Nachricht durchführt. Überprüfen Sie außerdem in Ihrem Stripe-Dashboard, ob die Bestellung ebenfalls angezeigt wird.
Stripe-Abonnements
Abonnements oder Pläne können für wiederkehrende Zahlungen erstellt werden. Bei dieser Art von Produkt wird dem Benutzer je nach Plankonfiguration täglich, wöchentlich, monatlich oder jährlich automatisch eine Rechnung gestellt. In diesem Abschnitt verwenden wir das Feld für das Produkt stripe_plan_name
, um die Plan-ID zu speichern – eigentlich ist es uns möglich, die ID auszuwählen, und wir nennen sie premium-plan
–, die verwendet wird, um die zu erstellen Beziehung customer <-> subscription
.
Wir werden auch eine neue Spalte für die Benutzertabelle namens stripe_customer_id
erstellen, die mit der ID-Eigenschaft eines Stripe-Kundenobjekts gefüllt wird. Ein Stripe-Kunde wird erstellt, wenn die Funktion Stripe::Customer.create
aufgerufen wird, und Sie können die erstellten und mit Ihrem Konto verknüpften Kunden auch unter (https://dashboard.stripe.com/test/customers) überprüfen. Kunden werden erstellt, indem ein source
übergeben wird, der in unserem Fall das im Frontend generierte Token ist, das beim Absenden des Formulars gesendet wird.
Das vom zuletzt erwähnten Stripe-API-Aufruf erhaltene Kundenobjekt wird auch zum Erstellen eines Abonnements verwendet, was durch Aufrufen von customer.subscriptions.create
und Übergeben der Plan-ID als Parameter erfolgt.
Darüber hinaus bietet das stripe-rails
Gem die Schnittstelle zum Abrufen und Aktualisieren eines Kunden von Stripe, was durch Aufrufen von Stripe::Customer.retrieve
bzw. Stripe::Customer.update
erfolgt.
Wenn also ein Benutzerdatensatz bereits eine stripe_customer_id
hat, rufen wir Stripe::Customer.retrieve
auf, anstatt einen neuen Kunden mit Stripe::Customer.create
zu erstellen, indem wir die stripe_customer_id
als Parameter übergeben, gefolgt von einem Stripe::Customer.update
, und in diesem Fall wird dem Token ein Parameter übergeben.

Zuerst erstellen wir einen Plan mit der Stripe-API, damit wir ein neues Abonnementprodukt mit dem Feld stripe_plan_name
können. Anschließend werden wir Änderungen orders_controller
und im Stripe-Dienst vornehmen, damit die Erstellung und Ausführung von Stripe-Abonnements gehandhabt wird.
Schritt 1: Erstellen Sie einen Plan mit der Stripe-API.
Öffnen Sie Ihre Konsole über die Befehlsleiste rails c
. Erstellen Sie ein Abonnement für Ihr Stripe-Konto mit:
Stripe::Plan.create({ amount: 10000, interval: 'month', product: { name: 'Premium plan', }, currency: 'usd', id: 'premium-plan', })
Wenn das zurückgegebene Ergebnis in diesem Schritt wahr ist, bedeutet dies, dass der Plan erfolgreich erstellt wurde und Sie in Ihrem Stripe-Dashboard darauf zugreifen können.
Schritt 2: Erstellen Sie ein Produkt in der Datenbank mit dem stripe_plan_name
.
Erstellen Sie nun ein Produkt mit dem stripe_plan_name
als premium-plan
in der Datenbank:
Product.create(price_cents: 10000, name: 'Premium Plan', stripe_plan_name: 'premium-plan')
Schritt 3: Generieren Sie eine Migration zum Hinzufügen einer Spalte stripe_customer_id
in der users
.
Führen Sie im Terminal Folgendes aus:
rails generate migration AddStripeCustomerIdToUser stripe_customer_id:string rails db:migrate
Schritt 4: Implementieren Sie die Abonnementlogik in der Stripe-Dienstklasse.
Fügen Sie zwei weitere Funktionen in den privaten Methoden von app/services/orders/stripe.rb
: execute_subscription
ist für die Erstellung der Abonnements im Objekt des Kunden verantwortlich. Die Funktion find_or_create_customer
ist dafür verantwortlich, den bereits erstellten Kunden zurückzugeben oder einen neu erstellten Kunden zurückzugeben.
def self.execute_subscription(plan:, token:, customer:) customer.subscriptions.create({ plan: plan }) end def self.find_or_create_customer(card_token:, customer_id:, email:) if customer_id stripe_customer = Stripe::Customer.retrieve({ id: customer_id }) if stripe_customer stripe_customer = Stripe::Customer.update(stripe_customer.id, { source: card_token}) end else stripe_customer = Stripe::Customer.create({ email: email, source: card_token }) end stripe_customer end
Schließlich rufen wir in der execute
in derselben Datei ( app/services/orders/stripe.rb
) zuerst find_or_create_customer
und führen dann das Abonnement aus, indem wir execute_subscription
aufrufen, indem wir den zuvor abgerufenen/erstellten Kunden übergeben. Ersetzen Sie also den Kommentar #SUBSCRIPTIONS WILL BE HANDLED HERE
in der execute
-Methode durch den folgenden Code:
customer = self.find_or_create_customer(card_token: order.token, customer_id: user.stripe_customer_id, email: user.email) if customer user.update(stripe_customer_id: customer.id) order.customer_id = customer.id charge = self.execute_subscription(plan: product.stripe_plan_name, customer: customer)
Schritt 5: Testen Sie Ihre Anwendung.
Besuchen Sie Ihre Website, wählen Sie das Abonnementprodukt Premium Plan
aus und füllen Sie eine gültige Testkarte aus. Nach dem Absenden sollte es Sie zu einer erfolgreichen Seite weiterleiten. Überprüfen Sie außerdem in Ihrem Stripe-Dashboard, ob das Abonnement erfolgreich erstellt wurde.
PayPal-Konfiguration
Wie wir es in Stripe getan haben, werden wir auch ein Juwel für die Verwendung der PayPal-API hinzufügen: paypal-sdk-rest
, und die Erstellung eines PayPal-Kontos ist ebenfalls erforderlich. Ein beschreibender Workflow für PayPal, der dieses Juwel verwendet, kann in der offiziellen PayPal-API-Dokumentation eingesehen werden.
Schritt 1: Fügen Sie Ihrem Projekt das Juwel paypal-sdk-rest
.
Fügen Sie dies in die Gemfile
:
gem 'paypal-sdk-rest'
Laufen:
bundle install
Schritt 2: Generieren Sie Ihre API-Schlüssel.
Um die API-Schlüssel für die Kommunikation mit PayPal zu erhalten, müssen Sie ein PayPal-Konto erstellen. Damit:
- Erstellen Sie ein Konto (oder verwenden Sie Ihr PayPal-Konto) unter https://developer.paypal.com/.
- Immer noch in Ihrem Konto angemeldet, erstellen Sie zwei Sandbox-Konten unter https://developer.paypal.com/developer/accounts/:
- Persönlich (Käuferkonto) – Dies wird in Ihren Tests für Zahlungen und Abonnements verwendet.
- Geschäftlich (Händlerkonto) – Dies wird mit der Anwendung verknüpft, die die gesuchten API-Schlüssel enthält. Außerdem können alle Transaktionen in diesem Konto verfolgt werden.
- Erstellen Sie eine App unter https://developer.paypal.com/developer/applications mit dem vorherigen Business-Sandbox-Konto.
- Nach diesem Schritt erhalten Sie zwei Schlüssel für PayPal:
Client ID
undSecret
. - Ersetzen Sie in
config/application.yml
YOUR_CREDENTIAL_HERE
vonPAYPAL_CLIENT_ID
undPAYPAL_CLIENT_SECRET
durch die Schlüssel, die Sie gerade erhalten haben.
Schritt 3: Initialisieren Sie das PayPal-Modul.
Ähnlich wie bei Stripe müssen wir neben dem Ersetzen der Schlüssel in application.yml
noch das PayPal-Modul initialisieren, damit es die bereits in unserer ENV
-Variablen festgelegten Schlüssel verwenden kann. Erstellen Sie dazu eine Datei in config/initializers/paypal.rb
mit:
PayPal::SDK.configure( mode: ENV['PAYPAL_ENV'], client_id: ENV['PAYPAL_CLIENT_ID'], client_secret: ENV['PAYPAL_CLIENT_SECRET'], ) PayPal::SDK.logger.level = Logger::INFO
Schritt 4: PayPal im Frontend integrieren.
Fügen Sie in index.html.haml
dies am Anfang der Datei hinzu:
%script(src="https://www.paypal.com/sdk/js?client-id=#{ENV['PAYPAL_CLIENT_ID']}")
Im Gegensatz zu Stripe verwendet PayPal nur eine Schaltfläche, die, wenn sie angeklickt wird, ein sicheres Popup öffnet, in dem sich der Benutzer anmelden und mit der Zahlung/dem Abonnement fortfahren kann. Dieser Button kann durch Aufrufen der Methode paypal.Button(PARAM1).render(PARAM2)
werden.
-
PARAM1
ist ein Objekt mit der Umgebungskonfiguration und zwei Callback-Funktionen als Eigenschaften:createOrder
undonApprove
. -
PARAM2
gibt die HTML-Elementkennung an, an die die PayPal-Schaltfläche angehängt werden soll.
Ersetzen Sie also immer noch in derselben Datei den kommentierten Code YOUR PAYPAL CODE WILL BE HERE
durch:
(function setupPaypal() { function isPayment() { return $('[data-charges-and-payments-section] input[name="orders[product_id]"]:checked').length } function submitOrderPaypal(chargeID) { var $form = $("#order-details"); // Add a hidden input orders[charge_id] $form.append($('<input type="hidden" name="orders[charge_id]"/>').val(chargeID)); // Set order type $('#order-type').val('paypal'); $form.submit(); } paypal.Buttons({ env: "#{ENV['PAYPAL_ENV']}", createOrder: function() { }, onApprove: function(data) { } }).render('#submit-paypal'); }());
Schritt 5: Testen Sie Ihre Anwendung.
Besuchen Sie Ihre Seite und überprüfen Sie, ob die PayPal-Schaltfläche angezeigt wird, wenn Sie PayPal als Zahlungsmethode auswählen.
PayPal-Transaktionen
Die Logik für PayPal-Transaktionen ist im Gegensatz zu Stripe etwas komplexer, da mehr Anfragen vom Front-End zum Back-End gehören. Deshalb gibt es diese Rubrik. Ich werde mehr oder weniger (ohne Code) erklären, wie die in den createOrder
und onApprove
Methoden beschriebenen Funktionen implementiert werden und was auch in den Backend-Prozessen erwartet wird.
Schritt 1: Wenn der Benutzer auf die PayPal-Senden-Schaltfläche klickt, ist ein PayPal-Popup geöffnet, das nach Benutzerdaten fragt, aber in einem Ladezustand. Der Funktionsrückruf createOrder
wird aufgerufen.

Schritt 2: In dieser Funktion führen wir eine Anfrage an unser Backend durch, die eine Zahlung/ein Abonnement erstellt. Dies ist der allererste Beginn einer Transaktion, und es werden noch keine Gebühren erhoben, sodass sich die Transaktion tatsächlich in einem ausstehenden Zustand befindet. Unser Back-End sollte uns ein Token zurückgeben, das mit dem PayPal-Modul generiert wird (bereitgestellt durch das Juwel paypal-rest-sdk
).
Schritt 3: Immer noch im createOrder
Callback geben wir dieses Token zurück, das in unserem Back-End generiert wurde, und wenn alles in Ordnung ist, zeigt das PayPal-Popup Folgendes an und fragt nach Benutzerdaten:

Schritt 4: Nachdem sich der Benutzer angemeldet und die Zahlungsmethode ausgewählt hat, ändert das Popup seinen Status wie folgt:

Schritt 5: Der Callback der Funktion onApprove
wird nun aufgerufen. Wir haben es wie folgt definiert: onApprove: function(data)
. Das data
wird die Zahlungsinformationen haben, um es auszuführen. Bei diesem Rückruf wird eine weitere Anfrage an unsere Backend-Funktion durchgeführt, diesmal unter Weitergabe des Datenobjekts, um die PayPal-Bestellung auszuführen.
Schritt 6: Unser Backend führt diese Transaktion aus und gibt 200 zurück (falls erfolgreich).
Schritt 7: Wenn unser Backend zurückkehrt, senden wir das Formular ab. Dies ist die dritte Anfrage, die wir an unser Backend stellen.
Beachten Sie, dass im Gegensatz zu Stripe in diesem Prozess drei Anfragen an unser Back-End gestellt werden. Und wir werden unseren Bestellstatus entsprechend synchronisieren:
-
createOrder
Callback: Eine Transaktion wird erstellt und ein Bestelldatensatz wird ebenfalls erstellt; daher befindet es sich standardmäßig in einem ausstehenden Zustand. -
onApprove
Callback: Die Transaktion wird ausgeführt und unsere Bestellung wird als paypal_executed gesetzt. - Die Bestellseite wird übermittelt: Die Transaktion wurde bereits ausgeführt, es ändert sich also nichts. Der Bestelldatensatz ändert seinen Status in bezahlt .
Dieser gesamte Prozess wird in der folgenden Grafik beschrieben:

PayPal-Zahlungen
PayPal-Zahlungen folgen derselben Logik wie Stripe-Gebühren, stellen also einmalige Transaktionen dar, aber wie im vorherigen Abschnitt erwähnt, haben sie eine andere Ablauflogik. Dies sind die Änderungen, die für die Abwicklung von PayPal-Zahlungen vorgenommen werden müssen:
Schritt 1: Erstellen Sie neue Routen für PayPal und führen Sie Zahlungen aus.
Add the following routes in config/routes.rb
:
post 'orders/paypal/create_payment' => 'orders#paypal_create_payment', as: :paypal_create_payment post 'orders/paypal/execute_payment' => 'orders#paypal_execute_payment', as: :paypal_execute_payment
This will create two new routes for creating and executing payments which will be handled in the paypal_create_payment
and paypal_execute_payment
orders controller methods.
Step 2: Create the PayPal service.
Add the singleton class Orders::Paypal
at: app/services/orders/paypal.rb
.
This service will initially have three responsibilities:
- The
create_payment
method creates a payment by callingPayPal::SDK::REST::Payment.new
. A token is generated and returned to the front-end. - The
execute_payment
method executes the payment by first finding the previous created payment object throughPayPal::SDK::REST::Payment.find(payment_id)
which uses the payment_id as an argument which has the same value as the charge_id stored in the previous step in the order object. After that, we callexecute
in the payment object with a given payer as the parameter. This payer is given by the front end after the user has provided credentials and selected a payment method in the popup. - The
finish
method finds an order by a specific charge_id querying for recently created orders in the paypal_executed state. If a record is found, it is marked as paid.
class Orders::Paypal def self.finish(charge_id) order = Order.paypal_executed.recently_created.find_by(charge_id: charge_id) return nil if order.nil? order.set_paid order end def self.create_payment(order:, product:) payment_price = (product.price_cents/100.0).to_s currency = "USD" payment = PayPal::SDK::REST::Payment.new({ intent: "sale", payer: { payment_method: "paypal" }, redirect_urls: { return_url: "/", cancel_url: "/" }, transactions: [{ item_list: { items: [{ name: product.name, sku: product.name, price: payment_price, currency: currency, quantity: 1 } ] }, amount: { total: payment_price, currency: currency }, description: "Payment for: #{product.name}" }] }) if payment.create order.token = payment.token order.charge_id = payment.id return payment.token if order.save end end def self.execute_payment(payment_id:, payer_id:) order = Order.recently_created.find_by(charge_id: payment_id) return false unless order payment = PayPal::SDK::REST::Payment.find(payment_id) if payment.execute( payer_id: payer_id ) order.set_paypal_executed return order.save end end
Step 3: Call the PayPal service in the controller in the submit action.
Add a callback for prepare_new_order
before the action paypal_create_payment
(which will be added in the next step) is requested by adding the following in the file app/controllers/orders_controller.rb
:
class OrdersController < ApplicationController before_action :authenticate_user! before_action :prepare_new_order, only: [:paypal_create_payment] ...
Again, in the same file, call PayPal service in the submit action by replacing the commented code #PAYPAL WILL BE HANDLED HERE.
mit den folgenden:
... elsif order_params[:payment_gateway] == "paypal" @order = Orders::Paypal.finish(order_params[:token]) end ...
Step 4: Create the actions for handling requests.
Still, in the app/controllers/orders_controller.rb
file, create two new actions (which should be public) for handling requests to paypal_create_payment
and paypal_execute_payment
routes:
- The
paypal_create_payment
method: Will call our service methodcreate_payment
. If that returns successfully, it will return the order token created byOrders::Paypal.create_payment
. - The
paypal_execute_payment
method: Will call our service methodexecute_payment
(which executes our payments). If the payment is performed successfully, it returns 200.
... def paypal_create_payment result = Orders::Paypal.create_payment(order: @order, product: @product) if result render json: { token: result }, status: :ok else render json: {error: FAILURE_MESSAGE}, status: :unprocessable_entity end end def paypal_execute_payment if Orders::Paypal.execute_payment(payment_id: params[:paymentID], payer_id: params[:payerID]) render json: {}, status: :ok else render json: {error: FAILURE_MESSAGE}, status: :unprocessable_entity end end ...
Step 5: Implement the front-end callback functions for createOrder
and onApprove
.
Make your paypal.Button.render
call look like this:
paypal.Buttons({ env: "#{ENV['PAYPAL_ENV']}", createOrder: function() { $('#order-type').val("paypal"); if (isPayment()) { return $.post("#{paypal_create_payment_url}", $('#order-details').serialize()).then(function(data) { return data.token; }); } else { } }, onApprove: function(data) { if (isPayment()) { return $.post("#{paypal_execute_payment_url}", { paymentID: data.paymentID, payerID: data.payerID }).then(function() { submitOrderPaypal(data.paymentID) }); } else { } } }).render('#submit-paypal');
As mentioned in the previous section, we call paypal_create_payment_url
for the createOrder
callback and paypal_execute_payment_url
for the onApprove
callback. Notice that if the last request returns success, we submit the order, which is the third request made to the server.
In the createOrder
function handler, we return a token (obtained from the back end). In the onApprove
callback, we have two properties passed down to our back-end paymentID
and payerID
. These will be used in order to execute the payment.
Finally, notice that we have two empty else
clauses as I'm leaving room for the next section where we will be adding PayPal subscriptions.
If you visit your page after integrating the front-end JavaScript section and select PayPal as the payment method, it should look like the following:

Step 6: Test your application.
- Besuchen Sie die Indexseite.
- Wählen Sie ein Zahlungs-/Aufladeprodukt und PayPal als Zahlungsmethode aus.
- Klicken Sie auf die Schaltfläche „PayPal senden“.
- Im PayPal-Popup:
- Verwenden Sie die Anmeldeinformationen für das von Ihnen erstellte Käuferkonto.
- Melden Sie sich an und bestätigen Sie Ihre Bestellung.
- Das Popup sollte sich schließen.
- Überprüfen Sie, ob Sie auf eine Erfolgsseite weitergeleitet werden.
- Überprüfen Sie abschließend, ob die Bestellung im PayPal-Konto durchgeführt wurde, indem Sie sich mit Ihrem Geschäftskonto unter https://www.sandbox.paypal.com/signin anmelden und das Dashboard https://www.sandbox.paypal.com/listing überprüfen /transaktionen.
PayPal-Abonnements
PayPal-Pläne/Verträge/Abonnements folgen derselben Logik wie Stripe-Abonnements und werden für wiederkehrende Zahlungen erstellt. Bei diesem Produkttyp wird dem Benutzer je nach Konfiguration täglich, wöchentlich, monatlich oder jährlich automatisch eine Rechnung gestellt.
Wir werden das Feld für das Produkt paypal_plan_name
verwenden, um die von PayPal bereitgestellte Plan-ID zu speichern. In diesem Fall wählen wir im Gegensatz zu Stripe die ID nicht aus, und PayPal gibt diesen Wert zurück, der verwendet wird, um das zuletzt in unserer Datenbank erstellte Produkt zu aktualisieren.
Für die Erstellung eines Abonnements sind in keinem Schritt customer
erforderlich, da die Methode onApprove
diese Verknüpfung wahrscheinlich in ihrer zugrunde liegenden Implementierung behandelt. Unsere Tische bleiben also gleich.
Schritt 1: Erstellen Sie einen Plan mit der PayPal-API.
Öffnen Sie Ihre Konsole über die Befehlsleiste rails c
. Erstellen Sie ein Abonnement für Ihr PayPal-Konto mit:
plan = PayPal::SDK::REST::Plan.new({ name: 'Premium Plan', description: 'Premium Plan', type: 'fixed', payment_definitions: [{ name: 'Premium Plan', type: 'REGULAR', frequency_interval: '1', frequency: 'MONTH', cycles: '12', amount: { currency: 'USD', value: '100.00' } }], merchant_preferences: { cancel_url: 'http://localhost:3000/', return_url: 'http://localhost:3000/', max_fail_attempts: '0', auto_bill_amount: 'YES', initial_fail_amount_action: 'CONTINUE' } }) plan.create plan_update = { op: 'replace', path: '/', value: { state: 'ACTIVE' } } plan.update(plan_update)
Schritt 2: Aktualisieren Sie das letzte Produkt in der Datenbank paypal_plan_name
mit der zurückgegebenen plan.id
.
Laufen:
Product.last.update(paypal_plan_name: plan.id)
Schritt 3: Fügen Sie Routen für das PayPal-Abonnement hinzu.
Fügen Sie zwei neue Routen in config/routes.rb
:
post 'orders/paypal/create_subscription' => 'orders#paypal_create_subscription', as: :paypal_create_subscription post 'orders/paypal/execute_subscription' => 'orders#paypal_execute_subscription', as: :paypal_execute_subscription
Schritt 4: Behandeln Sie die Erstellung und Ausführung im PayPal-Dienst.
Fügen Sie zwei weitere Funktionen zum Erstellen und Ausführen von Abonnements in Orders::Paypal
von app/services/orders/paypal.rb
:
def self.create_subscription(order:, product:) agreement = PayPal::SDK::REST::Agreement.new({ name: product.name, description: "Subscription for: #{product.name}", start_date: (Time.now.utc + 1.minute).iso8601, payer: { payment_method: "paypal" }, plan: { id: product.paypal_plan_name } }) if agreement.create order.token = agreement.token return agreement.token if order.save end end def self.execute_subscription(token:) order = Order.recently_created.find_by(token: token) return false unless order agreement = PayPal::SDK::REST::Agreement.new agreement.token = token if agreement.execute order.charge_id = agreement.id order.set_paypal_executed return order.charge_id if order.save end end
In create_subscription
initialisieren wir eine Vereinbarung, indem wir die Methode PayPal::SDK::REST::Agreement.new
aufrufen und den product.paypal_plan_name
als eines seiner Attribute übergeben. Danach erstellen wir es, und jetzt wird ein Token für dieses letzte Objekt gesetzt. Wir geben das Token auch an das Frontend zurück.
In execute_subscription
finden wir den order
, der im vorherigen Aufruf erstellt wurde. Danach initialisieren wir eine neue Vereinbarung, setzen das Token dieses vorherigen Objekts und führen es aus. Wenn dieser letzte Schritt erfolgreich durchgeführt wurde, wird der Bestellstatus auf paypal_executed gesetzt. Und jetzt geben wir die Vereinbarungs-ID an das Frontend zurück, die auch in order.chager_id
gespeichert ist.
Schritt 5: Fügen Sie Aktionen zum Erstellen und Ausführen von Abonnements in orders_controller
.
Ändern Sie die app/controllers/orders_controller.rb
. Oben in der Klasse zuerst den Callback prepare_new_order
aktualisieren und dann ausführen, bevor paypal_create_subscription
aufgerufen wird:
class OrdersController < ApplicationController before_action :authenticate_user! before_action :prepare_new_order, only: [:paypal_create_payment, :paypal_create_subscription]
Fügen Sie in derselben Datei auch die beiden öffentlichen Funktionen hinzu, damit sie den Dienst Orders::Paypal
mit einem ähnlichen Ablauf aufrufen, wie wir ihn bereits bei PayPal-Zahlungen haben:
... def paypal_create_subscription result = Orders::Paypal.create_subscription(order: @order, product: @product) if result render json: { token: result }, status: :ok else render json: {error: FAILURE_MESSAGE}, status: :unprocessable_entity end end def paypal_execute_subscription result = Orders::Paypal.execute_subscription(token: params[:subscriptionToken]) if result render json: { id: result}, status: :ok else render json: {error: FAILURE_MESSAGE}, status: :unprocessable_entity end end ...
Schritt 6: Hinzufügen von Abonnement-Handlern für createOrder
und onApprove
Callbacks im Frontend.
Ersetzen Sie schließlich in index.html.haml
die paypal.Buttons
Funktion durch die folgende, die die beiden leeren else
Elemente füllt, die wir zuvor hatten:
paypal.Buttons({ env: "#{ENV['PAYPAL_ENV']}", createOrder: function() { $('#order-type').val("paypal"); if (isPayment()) { return $.post("#{paypal_create_payment_url}", $('#order-details').serialize()).then(function(data) { return data.token; }); } else { return $.post("#{paypal_create_subscription_url}", $('#order-details').serialize()).then(function(data) { return data.token; }); } }, onApprove: function(data) { if (isPayment()) { return $.post("#{paypal_execute_payment_url}", { paymentID: data.paymentID, payerID: data.payerID }).then(function() { submitOrderPaypal(data.paymentID) }); } else { return $.post("#{paypal_execute_subscription_url}", { subscriptionToken: data.orderID }).then(function(executeData) { submitOrderPaypal(executeData.id) }); } } }).render('#submit-paypal');
Die Erstellung und Ausführung für Abonnements hat eine ähnliche Logik wie für Zahlungen. Ein Unterschied besteht darin, dass beim Ausführen von Zahlungen die Daten aus der Callback-Funktion onApprove
bereits eine Zahlungs charge_id
haben, die die paymentID
darstellt, um das Formular über submitOrderPaypal(data.paymentID)
zu übermitteln. Bei Abonnements erhalten wir die charge_id
erst, nachdem wir sie ausgeführt haben, indem wir einen POST
auf paypal_execute_subscription_url
, sodass wir submitOrderPaypal(executeData.id)
.
Schritt 7: Testen Sie Ihre Anwendung.
- Besuchen Sie die Indexseite.
- Wählen Sie ein Abonnementprodukt und PayPal als Zahlungsmethode aus.
- Klicken Sie auf die Schaltfläche „PayPal senden“.
- Im PayPal-Popup:
- Verwenden Sie die Anmeldeinformationen für das von Ihnen erstellte Käuferkonto.
- Melden Sie sich an und bestätigen Sie Ihre Bestellung.
- Das Popup sollte sich schließen.
- Überprüfen Sie, ob Sie auf eine Erfolgsseite weitergeleitet werden.
- Überprüfen Sie abschließend, ob die Bestellung im PayPal-Konto ausgeführt wurde, indem Sie sich mit Ihrem Geschäftskonto unter https://www.sandbox.paypal.com/signin anmelden und das Dashboard https://www.sandbox.paypal.com/listing/ überprüfen. Transaktionen.
Fazit
Nachdem Sie diesen Artikel gelesen haben, sollten Sie in der Lage sein, Zahlungen/Gebühren sowie Abonnementtransaktionen für PayPal und Stripe in Ihre Rails-Anwendung zu integrieren. Es gibt viele Punkte, die verbessert werden könnten, die ich in diesem Artikel der Kürze halber nicht hinzugefügt habe. Ich habe alles basierend auf einer Annahme der Schwierigkeit organisiert:
- Einfacher:
- Verwenden Sie Transport Layer Security (TLS), damit Ihre Anfragen HTTPS verwenden.
- Implementieren Sie Konfigurationen der Produktionsumgebung für PayPal und Stripe.
- Fügen Sie eine neue Seite hinzu, damit Benutzer auf einen Verlauf früherer Bestellungen zugreifen können.
- Mittel:
- Abonnements zurückerstatten oder kündigen.
- Bereitstellung einer Lösung für nicht registrierte Benutzerzahlungen.
- Schwerer:
- Bieten Sie eine Möglichkeit zum Entfernen von Konten und zum Beibehalten ihres Tokens und ihrer Kunden -ID, wenn der Benutzer zurückkehren möchte. Entfernen Sie diese Daten jedoch nach einer bestimmten Anzahl von Tagen, damit Ihre Anwendung PCI-konformer ist.
- Wechseln Sie auf der Serverseite zur PayPal Version 2 API (https://developer.paypal.com/docs/api/payments/v2/). 2, sodass diese mit Vorsicht verwendet werden kann (https://github.com/paypal/PayPal-Ruby-SDK/tree/2.0-beta).
- Schließen Sie idempotente Anfragen ein.
- Streifen: https://stripe.com/docs/api/idempotent_requests
- PayPal: https://developer.paypal.com/docs/api-basics/#api-idempotency
Ich empfehle auch, über das Stripe Checkout-Element zu lesen, das eine weitere Möglichkeit darstellt, Stripe in das Frontend zu integrieren. Im Gegensatz zu Stripe Elements, das wir in diesem Tutorial verwendet haben, öffnet Stripe Checkout nach dem Klicken auf eine Schaltfläche (ähnlich wie bei PayPal) ein Popup, in dem der Benutzer Kreditkarteninformationen eingibt ODER mit Google Pay/Apple Pay https://stripe.com bezahlen möchte /docs/web.
Eine zweite Leseempfehlung sind die Sicherheitsseiten für beide Payment Gateways.
- Für Streifen
- Für Paypal
Abschließend danke, dass Sie diesen Artikel gelesen haben! Sie können auch mein GitHub-Projekt überprüfen, das für dieses Projektbeispiel verwendet wird. Dort habe ich während der Entwicklung auch rspec- Tests hinzugefügt.