Payments are going through stripe but customers are not being created in the Stripe dashboard. There is already code to create customer that is called, but the API to create customer is not listed in the Stripe dashboard logs:
def create_customer(stripe_token, email)
customer = Stripe::Customer.create(source: stripe_token, email: email)
customer.save
end
Am I missing anything? It was working fine before Nov 2022.
Related
I want Stripe to check if the customer already exists and if yes associate it to the checkout session.
class OrdersController < ApplicationController
#session = Stripe::Checkout::Session.create(
payment_method_types: ['card'],
shipping_address_collection: {
allowed_countries: ['GB']
},
customer_email: current_user.email,
line_items: line_items_order,
success_url: new_order_message_url(#order),
cancel_url: order_url(#order)
)
if #user.stripe_id != nil
Stripe::Customer.retrieve(#user.stripe_id)
#session.customer = customer.id
#session.customer_email =customer.email
else
customer = Stripe::Customer.create({
email: current_user.email,
name: current_user.username,
metadata: {
},
})
#user.stripe_id = customer.id
#user.save
end
#order.checkout_session_id = #session.id
#order.save
end
I checked with byebug and saw that Stripe::Customer.retrieve(#user.stripe_id) is working, Stripe API is able to find te right customer, but still create a new customer for each checkout session. I have read the documentation about the sessions objetc and found that about the customer attribute:
customer attribute:
The ID of the customer for this Session. For Checkout Sessions in payment or subscription mode, Checkout will create a new customer object based on information provided during the payment flow unless an existing customer was provided when the Session was created.
What do I miss here?
The issue is that you are calling Stripe::Checkout::Session.create without passing in the customer. As mentioned in the doc for customer, it should be passed when creating the session if you want to use an existing customer
customer string EXPANDABLE
The ID of the customer for this Session. For Checkout Sessions in
payment or subscription mode, Checkout will create a new customer
object based on information provided during the payment flow unless an
existing customer was provided when the Session was created.
So just make sure you have the customer in the create method
#session = Stripe::Checkout::Session.create(
customer: customer.id
...
)
I have been following the https://medium.com/ruby-on-rails-development/google-places-gem-21e9e1aac491 tutorial and am having trouble integrating the Google Places gem with my code to fetch Google reviews for my application.
I have enabled Google places and got the respective API key. I have also enabled the business account and subscribed to 1-month free trial. However, I am getting this message now.
You must enable Billing on the Google Cloud Project at console.cloud.google.com/project/_/billing/enable Learn more at developers.google.com/maps/gmp-get-started.
doctors_controller.rb
def show
#doctor = Doctor.find(params[:id])
authorize #doctor, :manage?
#doctor = #location = #doctor.decorate
#tring out google reviews
api_key = "My_key"
#client = GooglePlaces::Client.new(api_key)
end
show.html.erb
<h1><%= #client.spots(-33.8670522, 151.1957362, :name => 'italian') %></h1>
thanks in advance, cheers
I want customers to be able to update their credit card details in my Rails app. Stripe has documentation on how to achieve this, but the article is showing an example in PHP, but I need an example for Rails: https://stripe.com/docs/recipes/updating-customer-cards
Basically, I need to save a customer's credit card without charging it.
This is subscribers_controller.rb:
class SubscribersController < ApplicationController
before_filter :authenticate_user!
def new
end
def update
token = params[:stripeToken]
customer = Stripe::Customer.create(
card: token,
plan: 1212,
email: current_user.email
)
current_user.subscribed = true
current_user.stripeid = customer.id
current_user.save
redirect_to profiles_user_path
end
end
You might also want to check out this SO answer How to create a charge and a customer in Stripe ( Rails) for more details on using Stripe in a Rails application.
For Ruby documentation, you can find great examples at on the Stripe Ruby API. In Stripe terminology, a card is called a source for the customer. You can create a source from a token, but once it's created, you deal with source and default_source elements on the Customer object, and retrieve card objects from the customer's source. Also note that you should never try to use the token beyond creating the source (or for one-time charges).
The Stripe Ruby API for Customers shows that you can create a customer and assign the source at the same time:
customer = Stripe::Customer.create(
source: token,
email: current_user.email
)
You do not have to assign a source to create a customer. However, if you set the customer up on a subscription, they will require a source to be available, and the charges will be made to the customer's default_source. If a customer has only one source, it is automatically the default_source.
The Stripe Ruby API for Cards, shows that you can also add a new card to an existing customer, using a token:
customer = Stripe::Customer.retrieve(customer_id)
customer.sources.create({source: token_id})
Once you have a card assigned to the customer, you can make it the default_source, using this:
customer.default_source = customer.sources.retrieve(card_id)
And that's what it takes to get setup and ready to start charging customers. Happy billing!
To update the card for an existing customer, the relevant snippet from the PHP recipe you mentioned is:
$cu = \Stripe\Customer::retrieve($customer_id); // stored in your application
$cu->source = $_POST['stripeToken']; // obtained with Checkout
$cu->save();
In Ruby, this would be:
cu = Stripe::Customer.retrieve(customer_id)
cu.source = params[:stripeToken]
cu.save
This will update the existing customer with the card from the token contained in the stripeToken parameter.
I've been following railstutorial.org. In this tutorial we a.o. learn how to create a token/digest together with a mailer for account activation. It saves a digest to the db and sends an email with a link that contains a token + email address. An authentication controller method then checks the email-token combination against the digest in the db.
Now I have a similar situation but with a complicating factor: There are users and organizations. My use case is that an organization can invite a user to become a member of that organization. The user will need to confirm this using an authentication link, before the user actually becomes a member of that organization.
Below is my current setup, which consists of a digest being saved to the User table and a link with the user's email address and token. The problem is that if the user clicks the authentication link, the authentication method still does not know to which organization it should add the user. It only has an email address and token.
How can I achieve that it is known which organization sent the invitation? Also, we of course don't want the user to be able to manipulate the link in such a way that the user can add himself to a different organization than the one the user was invited for.
Controller method:
def request
#organization = current_organization
#user = User.find(email: params[:user][:email])
#user.send_invitation(#organization)
end
Model method:
def send_invitation(organization)
create_invite_digest # Uses other model method to create digest and token.
update_columns(invite_digest: self.invite_digest)
UserMailer.add_user(self, organization).deliver_now
end
Mailer method:
def add_user(user, organization)
#user = user
#organization = organization
mail to: user.email, subject: "Please confirm"
end
Mailer View:
<%= adduser_url(#user.invite_token, email: #user.email) %>
Controller method to authenticate:
def adduser
user = User.find_by(email: params[:email])
if user && user.authenticated?(:invite, params[:id])
user.add_role(organization) # Should add user to organization, but then it needs to know which organization
flash[:success] = "User added"
redirect_to root_path
end
end
Model method to add user: requires information about the organization to add the user to.
def add_role(organization)
end
For a project I had that was similar, I had an invitation model and participant model (a membership is also a good name for this).
The invitation had a user_email, organization_id, and token. It had a related mailer that was created when the invitation was created.
The user then would receive the invitation by email and click to see it on the site, using the token for the invitation as the find parameter. The invitation had the opportunity to "accept", which was really the ability to create a participant record (user_id, organization_id). The user would have to be logged in for this, which may be a new registration or sign in. The participant would be created only if the invitation token was valid (exists and not yet used). I have a date on the invitation "accepted_at" which is used to know its state and if it can be used to create a participant or not. Users are not required to use a particular email address for registration, they just have to have access to the invitation to be able to accept it. Users can be a participant only once in an organization. The role on the participant is determined by the controller.
This all works really well for me. I am also planning to add a participant_request model that will allow the logged in user to request to be a participant of an organization. The organization would then have the option to view requests and "accept" or "deny" them - create the participant or decline the request. Datetimes will be on the request to know its state.
If you want more model details, I can give those. This may be enough to work from.
Probably the easiest thing to do would be to create an Invitation model of some sort that contains the token, user_id and organization_id. This will help you keep track of the references, and allow for flexibility in the future.
You could also add extra meta that way too (e.g. accepted_at), and possibly add the ability for the invite to only be valid for a certain amount of time (by using the invitation created_at, for example).
So I have an e commerce type rails app where users are able to list spaces to be booked, and other users are able to book these spaces for a specified amount of time.
I used this tutorial, http://www.gotealeaf.com/blog/basic-paypal-checkout-processing-in-rails, to set up my system.
Once a user submits a form to create a new booking, they are redirected to the PayPal website where they log in to paypal, confirm they are paying, and once they have paid they have an option to return to my website and see their booking invoice.
My issue is that when a user clicks submit on their new booking form and they are taken to the paypal website, they may press back on their browser, taking them back to my website, but their booking is now recorded.
How do I stop a booking from being recorded unless it has been paid for through paypal?
Here is my create action from my bookings controller:
def create
#booking = Booking.new(params[:booking].permit(booking_params)
#booking.space = #space
Space.find(#space.id).update_attributes( :balance => #space.balance + (#booking.length * #space.hourly_rate))
if #booking.save
redirect_to #booking.paypal_url(space_booking_path(#space, #booking))
else
render 'new'
end
end
Also my app/models/booking.rb:
class Booking < ActiveRecord::Base
include Bookable
def paypal_url(return_path)
values = {
business: "nikia.i-facilitator#peerparking.ca",
cmd: "_xclick",
upload: 1,
return: "#{Rails.application.secrets.app_host}#{return_path}",
invoice: id * rand(19284),
amount: space.hourly_rate * length,
item_name: space.address,
item_number: space.id,
quantity: '1',
notify_url: "#{Rails.application.secrets.app_host}/hook"
}
"#{Rails.application.secrets.paypal_host}/cgi-bin/webscr?" + values.to_query
end
end
And the relevant route in my routes.rb
post "spaces/:space_id/bookings/:id" => "bookings#show"
A browser back-arrow should return to the URL at your site that the user was already at. This URL should not consider payment complete (and booking in order). Would hitting browser reload on your page that precedes the redirect to PayPal also allow the user to complete the booking?
Assuming you are using Website Payments Stnadard, you would normally process a booking only upon the user reaching the return_url that you provide to PayPal, and then your code successfully processing the result variables that PayPal will include in the post back to you. (Or for customers who pay but do not return to your site directly, you would use IPN to associate the payment to the customer's account so that their order can be fulfilled asynchronously.)