How to save customer card updates in Stripe, Rails? - ruby-on-rails

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.

Related

How to save the return customer data with stripe

I am using payola which is a rails engine for stripe payment. am using the subscriptions method to make subscription. currently users are able to make subscription and can save the data on stripe. how do i save the return data to my database.
on my subscription controller i have it set like this
def create
# do any required setup here, including finding or creating the owner object
owner = current_user # this is just an example for Devise
# set your plan in the params hash
params[:plan] = SubscriptionPlan.find_by(id: params[:plan_id])
# call Payola::CreateSubscription
subscription = Payola::CreateSubscription.call(params, owner)
# Render the status json that Payola's javascript expects
render_payola_status(subscription)
subscriptions = Subscription.new
subscriptions.stripeid = subscription.id
subscriptions.customer = subscription.customer
subscriptions.plan = subscription.plan.name
subscriptions.subscriptiondate = subscription.current_period_start
subscriptions.subscriptionenddate = subscription.current_period_end
subscriptions.save
end
but when i check in my database its empty

Rails twitter-api get acces token without "sign-in" and store it in a different model than user

I have a rails app and I want to use the twitter api with the account of a user (to make favs, tweets, etc ...).
Here is my problem, I want the user to be able to create several "Project" with one different twitter account by project.
That is why I want to get the access_token and the access_token_secret but store them in my Project model and not in my User model.
I don't understand how I can do that. All the stuffs I found explain every time the way to do it with Omniauth and a "sign up"/"Sign in" of the User.
I'm very new to this Oauth / callback / API stuff so I'm a bit lost.
Is there an easy way to just get the access_token and the access_token_secret and store it where I want ?
I managed to do it with saving information i needed in the session.
def ask_twitter_authorisation
session[:info] = #project
redirect_to "/auth/twitter"
end
and then use it in my callback
def twitter_callback
session_hash = session[:info]
#project = Project.find(session_hash["id"])
#project.t_access_token = auth_hash.credentials.token
#project.t_access_token_secret = auth_hash.credentials.secret
#project.save
end

Stripe - not updating User's information in database

I'm working on my first project using stripe. I've got a subscription product and I've got the basic stripe funcationality working, but I need to update my user's record in the database as being "subscribed" so that I may use it as a validation later on in development. I've seen several tutorials online which show adding a column to your model called subscribed or something along those lines and updating it during the stripe customer creation process. I've got that working, except it is not updating my user model (in this case, supplier). Here's my controller for the stripe processs:
class ChargesController < ApplicationController
before_filter :authenticate_supplier!
def new
end
def create
# Amount in cents
token = params[:stripeToken]
customer = Stripe::Customer.create(
:source => token, # obtained from Stripe.js
:plan => "Free_month_annual",
:email => current_supplier.email,
#:coupon => "coupon_ID"
)
current_supplier.subscribed = true
#current_supplier.stripe_id = token
redirect_to orders_path
rescue Stripe::CardError => e
flash[:error] = e.message
redirect_to charges_path
end
end
As you can see, there are two things commented out - a coupon, which I plan to work on later, and stripe_id update because I ran into an error for having already used the token once (can't use it twice). I've updated my supplier model, there is an appropriate column in the database, the params have been updated to allow supplier.subscribed. I'm sure this is a quick answer for many, but I need help spotting my problem.
Edit:
subscribed is a boolean field - fyi
It seems you forgot to save the current_supplier record.
The solution should be adding something like:
current_supplier.subscribed = true
#current_supplier.stripe_id = token
current_supplier.save!
redirect_to orders_path

How to create authentication (email-token/digest) link when two models are involved?

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).

Rails 4 - Users are able to book spaces even if they back out of PayPal payment

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.)

Resources