【发布时间】:2020-11-04 06:47:19
【问题描述】:
我已经在我的 Ruby on Rails 网站中集成了 Stripe。如果我用 ngrok 测试它,一切正常,但是当我使用我的 heroku 网站地址作为条带 webhook 时,它会引发 400 bad request 错误。如果我查看文档,它会说缺少必需的参数。这可能是因为我没有 ssl 证书吗?我在 Heroku 上的免费层,但 Heroku 网址以 https 开头......这不安全吗?我已经在 heroku 网站上输入了可发布密钥、秘密密钥和签名密钥。
Routes.rb
Rails.application.routes.draw do
mount StripeEvent::Engine, at: '/stripe-webhooks'
devise_for :users, controllers: {
sessions: 'users/sessions',
passwords: 'users/passwords',
registrations: 'users/registrations'
}
scope '(:locale)', locale: /en|de/ do
root to: 'pages#home'
get '/about', to: 'pages#about', as: 'about'
get '/shipping', to: 'pages#shipping', as: 'shipping'
get '/privacypolicy', to: 'pages#privacypolicy', as: 'privacypolicy'
get '/termsandconditions', to: 'pages#termsandconditions', as: 'termsandconditions'
get '/success', to: 'pages#success'
get 'contact', to: 'contacts#new', as: 'contact'
resources :contacts, only: [:new, :create]
get 'cart', to: 'carts#show', as: 'cart'
delete 'carts', to: 'carts#destroy'
delete 'cart_items/:id', to: 'cart_items#destroy', as: 'cart_items'
resources :cart_items, only: [:create, :destroy] do
member do
get :add_quantity
get :reduce_quantity
end
end
post 'without-login', to: 'orders#without_login'
resources :users
resources :products do
resources :cart_items, only: [:create]
end
resources :categories
resources :orders, only: [:new, :show, :create] do
resources :payments, only: :new
end
end
end
架构:
create_table "orders", force: :cascade do |t|
t.string "product_sku"
t.integer "amount_cents", default: 0, null: false
t.string "checkout_session_id"
t.bigint "user_id"
t.datetime "created_at", precision: 6, null: false
t.datetime "updated_at", precision: 6, null: false
t.string "first_name"
t.string "last_name"
t.string "street_name"
t.string "house_number"
t.string "postal_code"
t.string "city"
t.string "country"
t.string "email"
t.text "comment"
t.integer "price_cents", default: 0, null: false
t.boolean "termsandconditions"
t.string "status", default: "pending"
t.index ["user_id"], name: "index_orders_on_user_id"
end
class PaymentsController < ApplicationController
skip_before_action :authenticate_user!
def new
if current_user
@order = current_user.orders.where(status: 'pending').find(params[:order_id])
else
@order = Order.find(params[:order_id])
end
gon.order_amount = @order.amount_cents.to_f/100
gon.order_id = @order.id
end
end
class OrdersController < ApplicationController
skip_before_action :authenticate_user!
def new
@order = Order.new
@cart = current_cart
# Storing the two constants in a gon variable to send data to the JS file
gon.ceilings = Product::ORDER_CEILINGS
gon.prices = Product::SHIPPING_PRICES
end
def create
@order = Order.new(order_params)
@cart = current_cart
@cart.cart_items.each { |item| @order.cart_items << item }
@order.amount = @cart.total_price
shipping_costs = calculate_shipping_costs(params[:order][:country], @order.amount)
@order.amount += Monetize.parse(shipping_costs)
@order.user = current_user if current_user
@order.email = current_user.email if current_user
if @order.save
save_user_address if params[:save_address].to_i == 1
trigger_stripe(shipping_costs)
cleanup_cart
redirect_to new_order_payment_path(@order)
else
@cart = @current_cart
render :new
end
end
def show
if current_user
@order = current_user.orders.find(params[:id])
else
@order = Order.find(params[:id])
end
mail = OrderMailer.with(order: @order).confirmation
mail.deliver_now
# may need to change this for guest users- must check that their email address is saved to the database
end
def index
@orders = current_user.orders
end
def without_login
session[:without_login] = true
redirect_to new_order_path
end
def submit
end
private
def order_params
params.require(:order).permit(:first_name, :last_name, :email, :street_name, :house_number, :postal_code, :city, :country, :comment)
end
def trigger_stripe(shipping_costs)
stripe_session = Stripe::Checkout::Session.create(
payment_method_types: ['card'],
customer_email: customer_email,
locale: I18n.locale.to_s,
line_items: stripe_line_items(@order.cart_items, shipping_costs),
success_url: order_url(@order),
cancel_url: order_url(@order)
)
@order.update(checkout_session_id: stripe_session.id)
end
def cleanup_cart
@cart.cart_items.each { |item| item.update(cart_id: nil) }
Cart.destroy(session[:cart_id])
session[:cart_id] = nil
end
def stripe_line_items(order_items, shipping_costs)
all_items = []
order_items.each do |item|
item_hash = {
name: item.product.title,
amount: (item.total_price.amount * 100).to_i / item.quantity,
quantity: item.quantity,
currency: 'eur'
}
all_items.push(item_hash)
end
shipping_item_hash = {
name: "Delivery",
amount: (shipping_costs * 100).to_i,
quantity: 1,
currency: 'eur'
}
all_items.push(shipping_item_hash)
return all_items
end
def customer_email
current_user ? current_user.email : nil
end
def save_user_address
if @order.user != nil
current_user.attributes = @order.attributes.except("id", "email", "status", "comment", "amount_cents", "amount_currency", "checkout_session_id", "user_id", "updated_at", "created_at")
current_user.save
end
end
class StripeCheckoutSessionService
def call(event)
order = Order.find_by(checkout_session_id: event.data.object.id)
order.update(status: 'paid')
end
end
付款 new.html.erb:
<script src="https://js.stripe.com/v3/"></script>
<script>
const paymentButton = document.getElementById('pay-stripe');
paymentButton.addEventListener('click', () => {
const stripe = Stripe('<%= ENV['STRIPE_PUBLISHABLE_KEY'] %>');
stripe.redirectToCheckout({
sessionId: '<%= @order.checkout_session_id %>'
});
});
</script>
初始化条带
Rails.configuration.stripe = {
publishable_key: ENV['STRIPE_PUBLISHABLE_KEY'],
secret_key: ENV['STRIPE_SECRET_KEY'],
signing_secret: ENV['STRIPE_WEBHOOK_SECRET_KEY']
}
Stripe.api_key = Rails.configuration.stripe[:secret_key]
StripeEvent.signing_secret = Rails.configuration.stripe[:signing_secret]
StripeEvent.configure do |events|
events.subscribe 'checkout.session.completed', StripeCheckoutSessionService.new
end
【问题讨论】:
-
能否包含您的 webhook 的代码以及您看到的错误消息?