I'm quite new to Ruby on Rails and I have been following this tutorial on how to implement an online marketplace by using Stripe's Connect API. This tutorial guides you on how to make single item purchases, I have tried to advance myself past this tutorial and create a marketplace where a user can purchase multiple items and put them in a basket and checkout, a nice challenge as the tutorial is focused on one item. However, I am stuck on the checkout _form.html.erb
.
Before, to fetch the publishable_key
,
<%= form_with model: current_user, local: true, url: subscription_url, method: :post, html: { id: "payment-form", class: "stripe-form" }, **data: { stripe_key: product.user.publishable_key }** do |form| %>
but now because I am submitting a cart full of products instead of one single item the data: { stripe_key: }
is now dysfunctional. Instead, I thought it might be a good idea to do data: { stripe_key: @account.publishable_key }
to fetch the publishable_key
from the database but it is not working.
I am most likely forgetting something important. Any help would be sound!
http://localhost:3000/subscription/new?account=4&amount=17
The Error
NoMethodError in Subscriptions#new
Showing /Users/kaneandrewgibson/Desktop/Charlie/WOP/app/views/subscriptions/_form.html.erb where line #1 raised:
undefined method `publishable_key' for nil:NilClass
Subscriptions/_form.html.erb
<%= form_with model: current_user, local: true, url: subscription_url, method: :post, html: { id: "payment-form", class: "stripe-form" }, data: { stripe_key: @account.publishable_key } do |form| %>
<div>
<label for="card-element" class="label">
Credit or debit card
</label>
<div id="card-element">
<!-- A Stripe Element will be inserted here. -->
</div>
<!-- Used to display Element errors. -->
<div id="card-errors" role="alert" class="text-sm text-red-400"></div>
</div>
<input type="hidden" name="account" value="<%= params[:account] %>">
<button>Back <%= number_to_currency(params[:amount]) %> /mo toward <em><%= %></em></button>
<% end %>
SubscriptionsController
class SubscriptionsController < ApplicationController
before_action :authenticate_user!
def new
@account = User.find_by_id(params[:id])
end
# Reference:
# https://stripe.com/docs/connect/subscriptions
def create
@account = User.find_by_id(params[:id])
key = @account.user.access_code
Stripe.api_key = key
plan_id = params[:plan]
plan = Stripe::Plan.retrieve(plan_id)
token = params[:stripeToken]
customer = if current_user.stripe_id?
Stripe::Customer.retrieve(current_user.stripe_id)
else
Stripe::Customer.create(email: current_user.email, source: token)
end
Stripe::PaymentIntent.create({
customer: customer,
amount: @cart.total_price * 100,
confirm: true,
currency: 'gbp',
payment_method_types: ['card'],
application_fee_percent: 3,
}, {
stripe_account: 'key',
})
options = {
stripe_id: customer.id,
subscribed: true,
}
options.merge!(
card_last4: params[:user][:card_last4],
card_exp_month: params[:user][:card_exp_month],
card_exp_year: params[:user][:card_exp_year],
card_type: params[:user][:card_brand]
)
current_user.perk_subscriptions << plan_id
current_user.update(options)
# Update project attributes
project_updates = {
backings_count: @project.backings_count.next,
current_donation_amount: @project.current_donation_amount + (plan.amount/100).to_i,
}
@project.update(project_updates)
redirect_to root_path, notice: "Your subscription was setup successfully!"
end
def destroy
subscription_to_remove = params[:id]
plan_to_remove = params[:plan_id]
customer = Stripe::Customer.retrieve(current_user.stripe_id)
customer.subscriptions.retrieve(subscription_to_remove).delete
current_user.subscribed = false
current_user.perk_subscriptions.delete(plan_to_remove)
current_user.save
redirect_to root_path, notice: "Your subscription has been cancelled."
end
end
Kane.
It looks like your account ID isn't getting into your controller. I would expect the URL to look something like this (account_id
instead of account
):
http://localhost:3000/subscription/new?account_id=4&amount=17
And I would expect the SubscriptionsController#new
to be looking in the Account
model rather than the User
model, and to be using the same account_id
param:
@account = Account.find_by_id(params[:account_id])