Stripe iFrame being blocked - rails and stripe - ruby-on-rails

I am making a checkout form with stripe and rails. I have a shop_controller that serves a list of products in the shop#index. Then that leads to the shop#show where the stripe form is located, and users can purchase a product.
Right now when clicking the button to make a purchase (using the fake card stripe gives you), all that happens is the button endlessly spins, and I get the following errors in the console:
GET https://checkout.stripe.com/api/account/lookup?email=MYEMAILADDRESS&key=&locale=en-US 400 (Bad Request)
and
Uncaught SecurityError: Failed to read the 'contentDocument' property from 'HTMLIFrameElement': Blocked a frame with origin "http://localhost:3000" from accessing a frame with origin "https://checkout.stripe.com". The frame requesting access has a protocol of "http", the frame being accessed has a protocol of "https". Protocols must match.
When I am adding my email to the form, I am also getting this error:
The specified value "MYEMAILADDRESS" is not a valid email address.
Here is my set up
routes.rb
resources :shop
shop_controller
class ShopController < ApplicationController
def index
#products = Product.all
end
def show
#product = Product.find(params[:id])
end
def new
end
# the create happens in the show action
def create
#product = Product.find(params[:id])
customer = Stripe::Customer.create(
:email => params[:stripeEmail],
:source => params[:stripeToken]
)
charge = Stripe::Charge.create(
:customer => customer.id,
:amount => #product.price * 100,
:description => #product.description,
:currency => 'usd'
)
rescue Stripe::CardError => e
flash[:error] = e.message
redirect_to new_charge_path
end
end
show.html.erb (where the form is rendered to pay)
<div class='shop-show'>
<div class="container">
<div class="row text-center">
<div class="col-lg-12 col-xs-12">
<h2><%= #product.name %></h2>
<hr class="generic">
</div>
</div>
<div class="row">
<div class="col-md-6 col-md-offset-3">
<div class="white_panel">
<%= form_for #product, url: url_for(controller: 'shop', action: 'create' ) do %>
<% if flash[:error].present? %>
<div id="error_explanation">
<p><%= flash[:error] %></p>
</div>
<% end %>
<script src="http://checkout.stripe.com/checkout.js" class="stripe-button"
data-key="<%= Rails.configuration.stripe[:publishable_key] %>"
data-description="<%= #product.description %>"
data-amount="<%= #product.price * 100 %>"
data-locale="auto"
data-shipping-address=true>
</script>
<% end %>
<img class="img-responsive" width='400' height='250' src="<%= #product.pictures.first.image.url %>">
<h2><%= #product.description %></h2>
</div>
</div>
</div>
</div>
</div>
Has anyone set up this kind of functionality before? This was closely followed using the link provided by stripe: https://stripe.com/docs/checkout/rails. Any help with this set up would be very appreciated. Thanks.

The Checkout ctript tag's URL there needs to be retrieved over HTTPS. Try swapping this:
<script src="http://checkout.stripe.com/checkout.js"
for this:
<script src="https://checkout.stripe.com/checkout.js"

Related

Form isn't submitting data to my Model. How to create data on submit?

Issue: Form isn't submitting data to Orders Table
I have a form_for that is connected to 2 controllers to connect the data together once submitted. I have recently connected Stripe Elements, which has its own controller. I had a dummy form in place that when i submitted the info, the data would go through and save to the Orders Table. I deleted the form and put the elements form in place, but the way i have it set up isn't submitting to the Table.
Here's the form:
<form id="form-element" action="/charges" method="post" id="payment_form">
<%= form_for([#listing, #order]) do |form| %>
<% if #order.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(#order.errors.count, "error") %> prohibited this order from being saved:</h2>
<ul>
<% order.errors.full_messages.each do |message| %>
<li><%= message %></li>
<% end %>
</ul>
</div>
<% end %>
<script
src="https://js.stripe.com/v3/">
// data-key="pk_test_3vX123456789YKE1f0B8"
// data-amount = {#listing.price}
// data-locale="auto">
</script>
<div class="form-row">
<label for="card-element">
Credit or debit card
</label>
<div id="card-element" class="form-control">
<!-- a Stripe Element will be inserted here. -->
</div>
<!-- Used to display form errors -->
<div id="card-errors" role="alert"></div>
</div>
<br>
<div class="form-group">
<%= form.submit "asdf", class:"ripple-effect", id:"button-element" %>
</div>
<span class="token"></span>
</form>
<% end %>
</div>
<script>
....
</script>
In my OrdersController, here's my create method:
def create
#order = Order.new(order_params)
#listing = Listing.find(params[:listing_id])
#seller = #listing.user
#order.listing_id = #listing.id
#order.buyer_id = current_user.id
#order.seller_id = #seller.id
....
Here's my ChargesController:
def create
#amount = 500
token = params[:stripeToken]
payment_form = params[:payment_form]
charge = Stripe::Charge.create({
:source => 'tok_visa',
:amount => #amount,
:description => 'Rails Stripe customer',
:currency => 'usd'
})
rescue Stripe::CardError => e
flash[:error] = e.message
redirect_to new_charge_path
end
I tried throwing in orderscontroller info to the chargescontroller, and vice versa. Wouldn't work. then figured it's just the way the form is set up. So basically, if that's the solution, how can i make it so when i input the form, the data registers to the orders table.
This information may help so.. here's the dummy form that would successfully forward the information to the order table: https://pastebin.com/th2WC8Lj
I added form.submit to the stripe form, but that didn't do it. I figured it would at least create a blank order.
attempt at using ajax to asynchronously submit forms.. not working.
<script>
...
$('#Orders').on('submit', function(event) {
event.preventDefault();
$.ajax({
type: "POST",
url: "/charges",
data: $('#payment_form').serialize()
}).then(this.submit.bind(this));
});
</script>
At present, the form is posting to the charges endpoint which means only the ChargesController#create code is being called. You need to do the following:
Duplicate the charge creation code into the OrdersController#create method and remove the <form id="form-element" action="/charges" method="post" id="payment_form"> tag at the top of your code block. That will then submit the form to the OrdersController#create method.
The reason I say duplicate the code is because we don't know if charges can be created without an associated order, in which case you'd want to retain the ability to create charges independently.

Rails - How to assign booking numbers to events

I'm building an events app using Ruby on Rails. Events can be either free or paid. In each instance I want to be able to assign a unique booking number for users when they book their places on an event.
What do I need to do to ensure both paid and free events are assigned a number in the server and a booking is then confirmed? Is it as simple as adding a booking_number column in my bookings table?
This is my model and controller code -
booking.rb
class Booking < ActiveRecord::Base
belongs_to :event
belongs_to :user
#validates :quantity, presence: true, numericality: { greater_than: 0 }
validates :total_amount, presence: true, numericality: { greater_than: 0 }
validates :quantity, :total_amount, presence: true
def reserve
# Don't process this booking if it isn't valid
self.valid?
# We can always set this, even for free events because their price will be 0.
#self.total_amount = booking.quantity * event.price
# Free events don't need to do anything special
if event.is_free?
save!
# Paid events should charge the customer's card
else
begin
self.total_amount = event.price_pennies * self.quantity
charge = Stripe::Charge.create(
amount: total_amount,
currency: "gbp",
source: stripe_token,
description: "Booking created for amount #{total_amount}")
self.stripe_charge_id = charge.id
save!
rescue Stripe::CardError => e
errors.add(:base, e.message)
false
end
end
#end
end
end
bookings_controller.rb
class BookingsController < ApplicationController
before_action :authenticate_user!
def new
# booking form
# I need to find the event that we're making a booking on
#event = Event.find(params[:event_id])
# and because the event "has_many :bookings"
#booking = #event.bookings.new(quantity: params[:quantity])
# which person is booking the event?
#booking.user = current_user
##total_amount = #event.price * #booking.quantity
end
def create
puts params
# actually process the booking
#event = Event.find(params[:event_id])
#booking = #event.bookings.new(booking_params)
#booking.user = current_user
if
#booking.reserve
flash[:success] = "Your place on our event has been booked"
redirect_to event_path(#event)
else
flash[:error] = "Booking unsuccessful"
render "new"
end
end
private
def booking_params
params.require(:booking).permit(:stripe_token, :quantity, :event_id, :stripe_charge_id, :total_amount)
end
end
This is my views code. There's an if/else statement here depending on whether its a paid event or not. The free events 'booking_id' simply shows as blank at the moment - not sure why.
booking.new.html.erb
<% if #event.is_free? %>
<div class="col-md-6 col-md-offset-3" id="eventshow">
<div class="row">
<div class="panel panel-default">
<div class="panel-heading">
<h2>Your Booking Confirmation</h2>
</div>
<div class="panel-body">
<h1>Hi there</h1>
<p>You have placed a booking on <%= #event.title %></p>
<p>Your order number is <%= #booking.booking_id %></p>
<p>We hope you have a wonderful time. Enjoy!</p>
<p>Love from Mama Knows Best</p>
</div>
<div class="panel-footer">
<%= link_to "Home", root_path %>
</div>
</div>
</div>
</div>
<% else %>
<div class="col-md-6 col-md-offset-3" id="eventshow">
<div class="row">
<div class="panel panel-default">
<div class="panel-heading">
<h2>Confirm Your Booking</h2>
</div>
<%= simple_form_for [#event, #booking], id: "new_booking" do |form| %>
<div class="calculate-total">
<p>
Confirm number of spaces you wish to book here:
<input type="number" placeholder="1" name="booking[quantity]" min="1" value="1" class="num-spaces">
</p>
<p>
Total Amount
£<span class="total" data-unit-cost="<%= #event.price %>">0</span>
</p>
</div>
<span class="payment-errors"></span>
<div class="form-row">
<label>
<span>Card Number</span>
<input type="text" size="20" data-stripe="number"/>
</label>
</div>
<div class="form-row">
<label>
<span>CVC</span>
<input type="text" size="4" data-stripe="cvc"/>
</label>
</div>
<div class="form-row">
<label>
<span>Expiration (MM/YYYY)</span>
<input type="text" size="2" data-stripe="exp-month"/>
</label>
<span> / </span>
<input type="text" size="4" data-stripe="exp-year"/>
</div>
</div>
<div class="panel-footer">
<%= form.button :submit %>
</div>
<% end %>
<% end %>
</div>
</div>
</div>
So you can use the SecureRandom Generator like this, and assuming your model is named Booking
### Add this in your model
before_create :add_booking_number
validates_uniqueness_of :add_booking_number
def add_booking_number
begin
self.booking_number = SecureRandom.hex(2).upcase
other_booking = booking_number.find_by(booking_number: self.booking_number)
end while other_booking
end
To use the Moniker "MAMA" you can do
def add_event_ident
self.booking_number = "MAMA" + '- ' + SecureRandom.hex(2).upcase
...
end
the (2) at the end of the .hex controls the length of the generated string (2) will produce 4 random letters. You can find the best length that works for you by going into rails console and playing with it ie.
SecureRandom.hex(4) ...
You can create a new column like booking_id in your booking table and assign a unique random before the booking object is created.
Ref: Source
If you want the random to be human readable, you can try this

NoMethodError/Undefined Method While Trying To Use Stripe In Partial

I'm implemented Stripe into my app but I'm attempting to move my "Upgrade Membership" option into a partial. I put the code within a partial and attempted to use the partial in my users#show view and the page won't load correctly and it gives me the error listed below. When I visit my charges#new view (which was the default view I set up prior to attempting to move everything over to my users#show view), the view loads and with no problem. But when I throw it in the partial and try to use the partial in my users#show, I get a NoMethodError/Undefined Method and I can't seem to figure out why.
Below is the error and my code (I added a comment on the line that's highlighted in the error message). Please let me know if any other code/info needs to be added. Thank you in advance for any help!
Error
NoMethodError in Users#show
undefined method `[]' for nil:NilClass
<h4>Upgrade To Premium</h4>
<script class='stripe-button' src="https://checkout.stripe.com/checkout.js"
data-key="<%= #stripe_btn_data[:key] %>" #highlighted line in the error
data-amount=<%= #stripe_btn_data[:amount] %>
data-description="<%= #stripe_btn_data[:description] %>"
data-email="<%= current_user.email %>" >
_form Partial
<% if current_user.premium? %>
<%= render partial: "charges/downgrade" %>
<% else %>
<%= form_tag charges_path do %>
<h4>Upgrade To Premium</h4>
<script class='stripe-button' src="https://checkout.stripe.com/checkout.js"
data-key="<%= #stripe_btn_data[:key] %>"
data-amount=<%= #stripe_btn_data[:amount] %>
data-description="<%= #stripe_btn_data[:description] %>"
data-email="<%= current_user.email %>" >
</script>
<% end %>
<% end %>
Users#show
<div class="container">
<h2><%= #user.email %></h2>
<% #wikis.each do |wiki| %>
<ul>
<li><%= link_to wiki.title, #wiki %></li>
</ul>
<% end %>
</div>
<br />
<div class="container">
<%= render partial: "charges/form" %>
</div>
I have another partial that I'm using within the partial that I'm having an error with, not sure if it's related but here it is just in case.
Downgrade Partial
<%= button_to 'Downgrade Membership', user_downgrade_path(current_user), class: 'btn' %>
Charges Controller
class ChargesController < ApplicationController
def create
# Creates a Stripe Customer object, for associating with the charge
customer = Stripe::Customer.create(
email: current_user.email,
card: params[:stripeToken]
)
charge = Stripe::Charge.create(
customer: customer.id, # Note -- this is NOT the user_id in your app
amount: 15_00,
description: "Premium Membership - #{current_user.email}",
currency: 'usd'
)
current_user.update_attributes!(role: 'premium')
flash[:notice] = "Thank you for upgrading to a Premium Membership, #{current_user.email}!"
redirect_to root_path # or wherever
# Stripe will send back CardErrors, with friendly messages
# when something goes wrong.
# This 'rescue block' catches and displays those errors.
rescue Stripe::CardError => e
flash[:alert] = e.message
redirect_to new_charge_path
end
def new
if user_signed_in?
#amount = 15_00
#stripe_btn_data = {
key: "#{ Rails.configuration.stripe[:publishable_key] }",
description: "BigMoney Membership - #{current_user.email}",
amount: #amount
}
else
redirect_to root_path
flash[:notice] = "You must be signed in to do that."
end
end
end
Ended up being something stupid and easy. I needed to define #stripe_btn_data within my user_controller since I'm using the partial in a user view.

Getting Stripe working in Rails 4

I am trying to set up stripe in rails and I can enter in the credit card info but when it redirects I get the following error:
No route matches [POST] "/enrollment/1"
I am confused because when I rake routes I get:
enrollment_index GET /enrollment(.:format) enrollment#index
POST /enrollment(.:format) enrollment#create
new_enrollment GET /enrollment/new(.:format) enrollment#new
edit_enrollment GET /enrollment/:id/edit(.:format) enrollment#edit
enrollment GET /enrollment/:id(.:format) enrollment#show
PATCH /enrollment/:id(.:format) enrollment#update
PUT /enrollment/:id(.:format) enrollment#update
DELETE /enrollment/:id(.:format) enrollment#destroy
So I am confused why it is trying to post because in my view, I specify that the method should be put:
<div class='container'>
<div class='jumbotron enroll-page'>
<div class='row'>
<h1>Enroll Here</h1>
<%= form_tag enrollment_path(1), :method => :put do %>
<article>
<label class="amount">
<span>Amount: $5.00</span>
</label>
</article>
<script src="https://checkout.stripe.com/checkout.js" class="stripe-button"
data-key="<%= Rails.configuration.stripe[:publishable_key] %>"
data-description="A month's subscription"
data-amount="500"></script>
<% end %>
</div>
</div>
</div>
My controller looks like this:
class EnrollmentController < ApplicationController
before_filter :authenticate_user!, unless: :admin_signed_in?
def new
end
def create
#get credit card details submitted by form
token = params[:stripeToken]
customer = Stripe::Customer.create(
:card => token,
:plan => 3455,
:email => current_user.email
)
current_user.paid = true
current_user.stripeid = customer.id
current_user.save
redirect_to courses_path, :notice => 'Your enrollment is complete!'
end
end
Thanks so much for any help that you can give!
EDIT: I think I have it. Ajay was totally right that this works better if I name the controller "enrollments" instead of enrollment. In the new.html.erb view, it should look like this instead:
<div class='container'>
<div class='jumbotron enroll-page'>
<div class='row'>
<h1>Enroll Here</h1>
<%= form_tag enrollments_path do %>
<article>
<label class="amount">
<span>Amount: $5.00</span>
</label>
</article>
<script src="https://checkout.stripe.com/checkout.js" class="stripe-button"
data-key="<%= Rails.configuration.stripe[:publishable_key] %>"
data-description="A month's subscription"
data-amount="500"></script>
<% end %>
</div>
</div>
</div>
check in routes the resource must be enrollments not enrollment
#routes.rb
resources :enrollments
Now when you run
rake routes | grep 'enrollment'
new_enrollment GET /enrollments/new(.:format) enrollments#new
#app/controller/enrollments_controller.rb
class EnrollmentsController < ApplicationController
def new
#enrollment = Enrollment.new
end
def edit
#enrollment = Enrollment.where(id: params[:id]).first
end
def create
#catch your params and do whatever.
end
def update
# catch your params and do your operation.
end
end
Now comes the View :
app/views/enrollments/new.html.erb
<%= render 'form %>
app/views/enrollments/edit.html.erb
<%= render 'form' %>
now in your app/views/enrollments/_form.html.erb
<%= form_tag(#enrollment)do %>
<%= label_tag :amount %>
<%= text_field_tag :amount, 50.00 %>
<%= submit_tag %>
<% end %>
In your console, the log should be something like this :
Started GET "/enrollments/new" for 127.0.0.1 at 2015-01-10 06:18:08 +0530
Processing by EnrollmentsController#new as HTML
This confirms you are hitting the new page not the edit. Check it !
Inspect your form, this should look like this, check it.

Creating Subscription with stripe

I'm trying to create a subscription package using Stripe..
Here what I have so far
My controller method.
def subscription_one
session[:tab] = "$1.99/Month"
#subscription = Subscription.where(user_id:current_user.id)
end
def create
#subscription = Subscription.new(params[:subscription])
if #subscription.save_with_payment
redirect_to #subscription, :notice => "Thank you for subscribing!"
else
render :new
end
end
subscription_one.html.erb
<% if #subscription.present? %>
CREDIT CARD DETAILS PRESENT
<% else %>
<form action="/membership/apply" method="POST" id="payment-form">
<article>
<label class="amount"> <span>Amount: $5.00</span> </label>
</article>
<script src="https://checkout.stripe.com/checkout.js" class="stripe-button"
data-key="<%= Rails.configuration.stripe[:publishable_key] %>"
data-description="A month's subscription"
data-amount="500"></script>
<% end %>
After I give all values in fields that appear, when I submit I get an error
ActionController::InvalidAuthenticityToken in MembershipController#create
Any ideas?
Several issues:
--
Form
The form you've included is hard coded
The problem you have is, as stated by Philidor Green, this form won't have the correct authenticity token provided by Rails. As a rule of thumb, Rails provides helpers for most HTML elements, allowing you to create consistent code for your app:
<%= form_tag path do %>
<% end %>
You should use form_tag for this
--
Subscription
Subscription.new(params[:subscription])
Should be:
def subscribed_one
Subscription.new(subscription_params)
end
private
def subscription_params
params.require(:subscription).permit(:params, :attributes)
end
--
Update
To handle this, I'd do this:
#view
<% if #subscription.present? %>
Credit Card Details Present
<% else %>
<%= form_tag membership_apply_path, id: "payment-form" do %>
<%= content_tag :article do %>
<%= label_tag class: "amount" %>
<%= content_tag :span, "Amount: $5.00" %>
<% end %>
<% submit_tag "Susbcribe" %>
<% end %>
<% end %>
#app/views/layouts/application.html.erb
<script src="https://checkout.stripe.com/checkout.js" class="stripe-button"
data-key="<%= Rails.configuration.stripe[:publishable_key] %>"
data-description="A month's subscription"
data-amount="500">
</script>
#app/controllers/subscriptions_controller.rb
def subscription_one
session[:tab] = "$1.99/Month"
#subscription = Subscription.where(user_id:current_user.id)
end
def create
#subscription = Subscription.new(params[:subscription])
if #subscription.save_with_payment
redirect_to #subscription, :notice => "Thank you for subscribing!"
else
render :new
end
end
I found a workaround, maybe to simple to be honest, it's the standard stripe checkout, replacing standart Form element by for_path. It seems working :
<%= form_tag stripe_user_standart_charge_checkout_path do %>
<script
src="https://checkout.stripe.com/checkout.js" class="stripe-button"
data-key="..."
data-amount="999"
data-name="Grégoire Mulliez"
data-description="Timee"
data-zip-code="true"
data-image="https://stripe.com/img/documentation/checkout/marketplace.png"
data-locale="auto"
data-currency="eur">
</script>
<% end %>
stripe_user_standart_charge_checkout_path is whatever route you want, don't forget to define it as POST (not get) in your routes.rb
Edit : you can retrieve hour transaction token using this method, also I added some html hidden fields to revrieve and the same time my transaction details , it's working like a charme

Resources