Failed to execute 'postMessage' on 'DOMWindow' using Stripe on rails 7 - ruby-on-rails

I have integrated Stripe payment in my rails 7 app and the stripe form does not show.
when i check inspect element in browser, this error shows:
Failed to execute 'postMessage' on 'DOMWindow': The target origin provided ('https://js.stripe.com') does not match the recipient window's origin ('http://localhost:3000').
purchases/show.html.erb
<h1>Purchase <%= #product.name %></h1>
<%= form_with url: product_purchase_path(#product), local: true, id: "payment-form", data: { payment_intent_id: #payment_intent.client_secret} do |form| %>
<div class="form-group">
<label for="card-element">Credit or debit card</label>
</div>
<div id="card-element" class: "form-control">
</div>
<div id="card-errors" role="alert"></div>
</div>
<div class="form-group">
<label>Name on Card</label>
<%= form.text_field :name_on_card, placeholder: "Full Name", class: "form-control" %>
</div>
<div class="form-group">
<%= form.hidden_field :payment_intent_id, value: #payment_intent.id %>
<button class="btn btn-primary">Submit Payment</button>
</div>
<% end %>
Application.js
document.addEventListener("turbo:load", () => {
const public_key = document.querySelector("meta[name= 'stripe-key']").getAttribute("content")
const stripe = Stripe(public_key)
const elements = stripe.elements()
const card = elements.create('card')
card.amount('#card-element')
card.addEventListener("change", (event) => {
var displayError = document.getElementById('card-errors')
if (event.error) {
displayError.textContent = event.error.message
} else {
displayError.textContent = ''
}
})
})
This there any solution for this?

That's because Stripe only allows https connections for security reasons. To resolve this issue you either serve your app over https or you can use a Tool such as ngrok
Download and install ngrok from the official website (https://ngrok.com/)
Start your rails app rails serve
Start ngrok by running the following command in a seperate window
ngrok http 3000
This will start a secure public url (e.g. https://your-unique-subdomain.ngrok.io ) that you can use to access your local development environment. Use this URL in your Stripe form and try accessing the page again.

Related

Why google storage don't accept direct uploads from Rails Active Storage?

I'm using google cloud storage in my application. Until last week everything were working fine, i've change nothing and now my files aren't beeing sent to storage.
The following message is displayed when I submit the form with the file.
and in the console has a link that display this
One curious thing is that i can normally sent the images from Rails Console
config.logo.attach(io:File.open(Rails.root.join('public/images/default.png')), filename: 'default.png', content_type:'application/png');
If using local storage everything works fine too.
Using Ruby 2.5.1, Rails 5.2.2 and Active Storage with Direct Uploads.
UPDATE
My form
<%= form_for #config, multipart: true do |f| %>
<div class="row border-bottom white-bg dashboard-header">
<div class="col-lg-12">
<h2>Configs</h2>
</div>
<div class="col-lg-12 mb-lg-5">
<%= image_tag f.object.logo, clas: 'img-fluid' if f.object.logo.attached? %>
<div class="form-group">
<%= f.label :logo %>
<%= f.file_field :logo, direct_upload: true, class:"form-control form-resource" %>
</div>
<button type="submit" class="btn btn-block btn-primary">Salvar</button>
</div>
</div>
<% end %>
When I remove direct_upload: true, works fine, but I don't want remove this functionality
Solved by configuring CORS (Cross-Origin Resource Sharing)
https://cloud.google.com/storage/docs/cross-origin

Integrating Stripe in Rails app

I am trying to create a custom form with stripe, and while it all appears to be submitting, when I check my dashboard in Stripe, although I do see a record of the transaction - I do not see the amount or any reference to the cc coming through. With that said, I am not quite sure what I SHOULD be seeing in the dashboard. But I am pretty sure I am doing something wrong. Here is the code to my form:
<div class="container">
<div class="row Row one">
<div class="col-sm-12 col-md-10">
<%= form_for #project, url: project_charges_path, :html => {:id => "payment-form"}, method: 'post' do |f| %>
<%= f.hidden_field :user_id, :value => current_user.id %>
<%= f.hidden_field :#project_id, :value => #project.id %>
<div class= "field">
<%= label_tag :card_number, "Credit Card Number" %><br>
<%= text_field_tag :card_number, nil, name: nil %><br>
</div>
<div class= "field">
<%= label_tag :card_code, "Security Code (cvc)" %><br>
<%= text_field_tag :card_code, nil, name: nil %><br>
</div>
<div class= "field">
<%= label_tag :card_month, "Expiration" %>
<%= select_month nil, {add_month_numbers: true}, {name: nil, id: "card_month"} %>
<%= select_year nil, {start_year: Date.today.year, end_year: Date.today.year+15}, {name: nil, id: "card_year"}%>
</div>
<div class= "actions">
<%= f.submit("Submit") %>
</div>
<div id="stipe-error">
<%= flash[:error] %>
</div>
<% end %>
</div>
</div>
<!-- <div class="row"></div> -->
and here is my charges controller:
class ChargesController < ApplicationController
def new
#project = Project.find(params[:project_id])
end
def create
#project = Project.find(params[:project_id])
binding.pry
# Amount in cents, this is being read and recorded in stripe dashboard
#amount = 500
customer = Stripe::Customer.create(
:email => 'helloWorld#stripe.com',
:card => params[:stripeToken]
)
charge = Stripe::Charge.create(
:customer => customer.id,
:amount => #amount,
:description => 'Rails Stripe customer',
:currency => 'usd'
)
#payment = Payment.create({
user_id: current_user.id,
project_id: #project,
amount: #amount
})
#payment.save
rescue Stripe::CardError => e
flash[:error] = e.message
end
# private
# def charges_params
# params.require(:payment).permit(:comments, :user_id, :project_id)
# end
end
Per a tutorial I have also included some javascript in my application.js:
$('#payment-form').submit(function(event) {
var $form = $(this);
alert('you clicked submit');
// Disable the submit button to prevent repeated clicks
$form.find('button').prop('disabled', true);
Stripe.card.createToken($form, stripeResponseHandler);
// Prevent the form from submitting with the default action
return false;
});
function stripeResponseHandler(status, response) {
var $form = $('#payment-form');
if (response.error) {
// Show the errors on the form
$form.find('.payment-errors').text(response.error.message);
$form.find('button').prop('disabled', false);
} else {
// response contains id and card, which contains additional card details
var token = response.id;
// Insert the token into the form so it gets submitted to the server
$form.append($('<input type="hidden" name="stripeToken" />').val(token));
// and submit
$form.get(0).submit();
}
}
Inside the striped dashboard I see:
the email comes through, but nothing concerning the amount or card. I don't expect to see the card number persay, but some reference to it, maybe just the type, or last four digits? Also in the front page of the dashboard (the area what gives a graph, I think I should be seeing the sum of the payments, even test payments, and the sum is still $0 despite having made over a dozen test payments of $5 each.
What am I missing here?
Also most of the tutorials I have come across are either really old, or PHP, which I am not familiar with. If anybody can recommend a great resource, that would really be helpful as well. I plan to use stripe for multiple projects, and would really like to UNDERSTAND it...
I might be very late in replying and you must have already done this but just in case this might help some else. I have just integrated stripe in my app. I am not sure what you are asking but i think a working example might help. This is very similar to what you have done and i can't find what's going wrong.
What i'm doing is saving customer_id returned by stripe in my user table. When the user saves the credit card, a certain amount according to the subscription plan is deducted. You will see the customer_id in your plan details under the subscribers in the dashboard. Also, in the customers, When you refer that customer_id, you'll see what plan he's subscribed to.
View: (creditcard.html.erb)
<div class="row">
<% if flash[:error].present? %>
<div class="col-lg-12 alert alert-danger">
<%= flash[:error] %>
</div>
<% else %>
<div class="col-lg-12" id = "payment-errors">
<span class="payment-errors"></span>
</div>
<% end %>
</div>
<div>
<%= form_tag plans_billings_chargecreditcard_path, id: "payment-form" do%>
<div class="row">
<div class="col-lg-3">
<div class="form-group">
<label>Card Number</label>
<%= text_field_tag nil, nil, size: 20, "data-stripe": "number", class: "form-control" %>
</div>
</div>
<div class="col-lg-2">
<div class="form-group">
<label>CVC</label>
<%= text_field_tag nil, nil, size: 4, "data-stripe": "cvc", class: "form-control" %>
</div>
</div>
</div>
<div class="row">
<div class="col-lg-12">
<div class="form-group">
<label>Expiration Date(MM/YY)</label>
<select class="selectpicker set-width" data-live-search="true" data-stripe = "exp_month">
<option>- Month -</option>
<option>1</option>
<option>2</option>
<option>3</option>
<option>4</option>
<option>5</option>
<option>6</option>
<option>7</option>
<option>8</option>
<option>9</option>
<option>10</option>
<option>11</option>
<option>12</option>
</select>
<select class="selectpicker set-width" data-live-search="true" data-stripe = "exp_year"> <!-- form-control input-lg -->
<option>- Year -</option>
<option>16</option>
<option>17</option>
<option>18</option>
<option>19</option>
<option>20</option>
<option>21</option>
<option>22</option>
<option>23</option>
<option>24</option>
<option>25</option>
<option>26</option>
</select>
</div>
</div>
</div>
<div class="row">
<div class="col-lg-12">
<div class="form-group">
<%= submit_tag "Save Card", class: "btn btn-primary" %>
</div>
</div>
</div>
<% end %>
</div>
CofeeScript: (plan_billings.coffee)
stripeResponseHandler = (status, response) ->
# Grab the form:
$form = $('#payment-form')
if response.error
# Problem!
# Show the errors on the form:
$('#payment-errors').addClass 'alert'
$('#payment-errors').addClass 'alert-danger'
$('.payment-errors').text response.error.message
$('.submit').prop 'disabled', false
# Re-enable submission
else
# Token was created!
# Get the token ID:
token = response.id
# Insert the token ID into the form so it gets submitted to the server:
$form.append $('<input type="hidden" name="stripeToken">').val(token)
# Submit the form:
$form.get(0).submit()
return
$ ->
$form = $('#payment-form')
$form.submit (event) ->
# Disable the submit button to prevent repeated clicks:
$form.find('.submit').prop 'disabled', true
# Request a token from Stripe:
Stripe.card.createToken $form, stripeResponseHandler
# Prevent the form from being submitted:
false
return
Controller: (in PlanBilling controller, chargecreditcard action)
#plan_and_billing = current_user.plan_billing
#current_plan = DataPlan.find_by(id: #plan_and_billing.data_plan_id)
token = params[:stripeToken]
if current_user.customer_id.present?
customer = Stripe::Customer.retrieve(current_user.customer_id)
customer.sources.create(source: token)
redirect_to plans_billings_planbilling_path
else
customer = Stripe::Customer.create( :source => token, plan: YOUR_PLAN_ID_YOU_HAVE_INYOUR__DASHBOARD )
#credit_card = current_user.update(customer_id: customer.id)
redirect_to plans_billings_planbilling_path
end
rescue Stripe::CardError => e
flash[:error] = e.message
redirect_to plans_billings_creditcard_path
What's happening in controller is that when a user has no card and he saves the card details, the card is saved and the Price of the plan you have mentioned is deducted. And if he already has a credit card saved, and saving another one, the card will only be saved as you'll see in his details in the dashboard. The new card will not be charged. Its just for saving new credit card to that customer.
I still have a long way to go in this, and of course this might not be a very good code, but this is just very basic thing you might find helpful. In case someone tries it out and faces some prob, i'll be glad to help. Also, I'll be grateful if someone can guide me to make this code better. Cheers :)

Confused about how to properly use secret keys

So in my quest to get Stripe integrated, I find myself confused about how to properly use secret keys and environmental variables. To my understanding, I do NOT want to explicitly include my secret key in any public place and should be using a environmental variable instead. But it does not seem to work when I substitute the ENV in place of the actual hardcoded key. I am doing something wrong, but what? Here is what I have. In my secret.yml file:
development:
secret_key_base: xxxxxxxxxxxxxxx
secret_key: sk_test_JlKC4V7nmCQ0sE4iNAVyoAxA
publishable_key: pk_test_KfCg1YmVXwBYyEdPEWnfibF8
stripe_live_publishable_key: pk_live_pxxxxxxxxxxxxxx
stripe_live_secret_key: sk_live_jxxxxxxxxxxxxx
test:
secret_key_base: a38exxxxxxxxxxxxxxxx
# Do not keep production secrets in the repository,
# instead read values from the environment.
production:
secret_key_base: <%= ENV["SECRET_KEY_BASE"] %>
#test
secret_key: <%= ENV["SECRET_KEY"] %>
publishable_key: <%= ENV["PUBLISHABLE_KEY"] %>
# live
stripe_live_publishable_key: <%= ENV["STRIPE_LIVE_PRODUCTION_KEY"] %>
stripe_live_secret_key: <%= ENV["STRIPE_LIVE_SECRET_KEY"] %>
and in /initialize/stripe.rb I have:
Rails.configuration.stripe = {
:publishable_key => ENV['PUBLISHABLE_KEY'],
:secret_key => ENV['SECRET_KEY']
}
Stripe.api_key = Rails.configuration.stripe[:secret_key]
and in my payment form, I have the line:
Stripe.setPublishableKey('<%= 'sk_test_JlKC4V7nmCQ0sE4iNAVyoAxA'%>');
It works like this, but unless I am misunderstanding, is insecure (well, right now it is just a test key, but I need to know this when I use live keys for production). Yet when I try to use:
Stripe.setPublishableKey('<%= ENV['PUBLISHABLE_KEY'] %>');
I get the error:
Uncaught Error: You did not set a valid publishable key. Call Stripe.setPublishableKey() with your publishable key.
or when I try:
Stripe.setPublishableKey('<%= :publishable_key %>');
I get an error 401 (Unauthorized) in console.
How am I supposed yo be using the ENV[KEY] so that I do not need my key written out in plain sight?
UPDATE:
Here is my form where the key would be most public:
<!DOCTYPE html>
<html lang="en">
<head>
<meta http-equiv="Content-type" content="text/html; charset=utf-8" />
<title>Contribution Form</title>
<!-- The required Stripe lib -->
<script type="text/javascript" src="https://js.stripe.com/v2/"></script>
<!-- jQuery is used only for this example; it isn't required to use Stripe -->
<script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<script type="text/javascript">
// This identifies your website in the createToken call below
Stripe.setPublishableKey('STRIPE_TEST_PUBLISHABLE_KEY'); //<====How should this line look?
var stripeResponseHandler = function(status, response) {
var $form = $('#payment-form');
if (response.error) {
// Show the errors on the form
$form.find('.payment-errors').text(response.error.message);
$form.find('button').prop('disabled', false);
} else {
// token contains id, last4, and card type
var token = response.id;
// Insert the token into the form so it gets submitted to the server
$form.append($('<input type="hidden" name="stripeToken" />').val(token));
// and re-submit
$form.get(0).submit();
}
};
jQuery(function($) {
$('#payment-form').submit(function(e) {
var $form = $(this);
// Disable the submit button to prevent repeated clicks
$form.find('button').prop('disabled', true);
Stripe.card.createToken({
number: $('.card-number').val(),
cvc: $('.card-cvc').val(),
exp_month: $('.card-expiry-month').val(),
exp_year: $('.card-expiry-year').val()}, stripeResponseHandler);
// Prevent the form from submitting with the default action
return false;
});
});
</script>
</head>
<body>
<!-- form -->
<div class="container">
<div class="row Row one">
<div class="col-sm-12 col-md-10">
<h1>Make your contribution</h1>
<%= form_for #project, url: project_charges_path, :html => {:id => "payment-form"}, method: 'post' do |f| %>
<%= f.hidden_field :user_id, :value => current_user.id %>
<%= f.hidden_field :#project_id, :value => #project.id %>
<div class= "field">
<%= label_tag :card_number, "Credit Card Number" %><br>
<%= text_field_tag :card_number, nil, name: nil, class: ' card-number form-control', :required => true %><br>
</div>
<div class= "field">
<%= label_tag :card_code, "Security Code (cvc)" %><br>
<%= text_field_tag :card_code, nil, name: nil, class: 'card-cvc form-control', :required => true %><br>
</div>
<div class= "field">
<%= label_tag :card_month, "Expiration" %>
<%= select_month nil, {add_month_numbers: true}, {name: nil, class: "card-expiry-month"} %>
<%= select_year nil, {start_year: Date.today.year, end_year: Date.today.year+15}, {name: nil, class: "card-expiry-year"}%>
</div>
<div class= "field">
<%= label_tag :amount, "Amount" %><br>
<%= text_field_tag :amount %>
</div>
<div class= "field">
<%= label_tag :comments, "Add a comment?" %><br>
<%= text_area_tag :comments %>
</div>
<div class= "actions">
<%= f.submit 'Submit', :class => 'contribution-submit' %>
</div>
<div id="stripe_error">
<noscript>JavaScript is not enabled and is required for this form. First enable it in your web browser settings.</noscript>
</div>
<% end %>
</div>
</div>
<!-- <div class="row"></div> -->
</div>
</body>
</html>
Environment variables in production have more to do with the application server than with your rails app. To me it looks like everything you've done seems correct , just need to set the variables in production mode.
For Heroku:
heroku config:set STRIPE_PERISHABLE_KEY=<your key here>
heroku config:set STRIPE_SECRET_KEY=<your key here>
For Passenger (nginx or apache):
In your server/site definition with passenger you can add passenger environment variables.
passenger_env_var STRIPE_PERISHABLE_KEY '<your key here>';
passenger_env_var STRIPE_SECRET_KEY '<your key here>';
*Note that with Apache you use an = sign between the key and the value and there are no quotes around the value.
ENV variables are set via terminal. This isn't the 'best practice' but I set my keys in my .bash_profile. There are also gems that manage your env-vars for you.
Here is a popular one that implements yaml:
https://github.com/laserlemon/figaro
Here is an example of adding keys to your .bash_profile
## Work Keys
export STRIPE_KEY="pk_test_somekey"
export STRIPE_SECRET="sk_test_somekey"
Then in ruby you can access the variable like this:
ENV["STRIPE_KEY"]
ENV["STRIPE_SECRET"]
You need to refresh your environment after doing this by making a new terminal instance. So quit terminal and restart your server!

Javascript doesn't work on heroku in production

I have a javascript code that should display image (loading gif) when you click to create a comment. It works in development, but not when I deploy it to heroku. I am able to make the most js/css files work properly, but not in this case.
<%= nested_form_for([#post, #comment], validate: true, html: {multipart: true}, 'data-update-target' => 'comments', class: 'comments') do |f| %>
...
<div class="actions">
<%= f.submit " Submit ", :class => "btn btn-default", :id => "submit" %>
</div><br>
<div id="loading2" class="loadinggif" style="display:none;"><img src="/assets/othericons/uploading.gif" alt="" /></div>
<script type="text/javascript">
(function (d) {
d.getElementById('new_comment').onsubmit = function () {
d.getElementById('submit').style.display = 'block';
d.getElementById('loading2').style.display = 'block';
};
}(document));
</script>
solution
I changed
<div id="loading2" class="loadinggif" style="display:none;"><img src="/assets/othericons/uploading.gif" alt="" /></div>
to
<div id="loading2" class="loadinggif" style="display:none;">
<%= image_tag("othericons/uploading.gif", alt: "") %>
</div>
With Heroku, I've only had success pre-compiling assets and adding those assets to git before deploying. When I start working on any assets in my dev environment, I run rake assets:clean and then when I'm done, rake assets:precompile; git add --all public/assets.

Sending POST request in Rails

How would I go about sending an HTTP POST request in the following format in a Rails setup:
curl https://api.venmo.com/v1/payments -d access_token=4e4sw1111111111t8an8dektggtcbb45 -d email="someemail#gmail.com" -d amount=5 -d note="Delivery."
I'd like to have users input the email/amount/note parameters into a form on a webpage, then pass that data (when the user clicks the submit button) into a Controller where the access_token parameter is stored to then fire off the POST request.
So far I've tried setting up the Controller with this method (and calling it from the view html.erb):
def make_payment
if !params[:access_token].nil?
form_data = {
"email" => #email_to,
"amount" => #amount_to,
"note" => #note_to,
"access_token" => :access_token
}
url = "https://api.venmo.com/v1/payments"
request = Net::HTTP::Post.new(url, form_data)
response = http.request(request)
end
end
Here's my current view setup:
<div class="box box-warning">
<div class="box-header">
<h3 class="box-title">Pay Bill using Venmo Account</h3>
<div id="payment_note_input">
<input id="payment_note" type="text" class="form-control" required placeholder="add a note to your payment">
</div>
<div id="payment_target_input" >
<input id="payment_target" type="text" class="form-control" required placeholder="pay an email address">
</div>
<div id="payment_amount_input">
<input id="payment_amount" type="text" class="form-control" required placeholder="enter the payment amount! ">
</div>
</br>
<button class="btn btn-danger" type="button" onClick= <%=make_payment%> > Make payment</button>
</div>
I feel like I'm close to a solution here...
You can use httpparty gem to achieve that, its easy to use in only 1 line:
response = HTTParty.post("https://example.com?param1=value1",
:body => {:text => data}.to_json,
:headers => {'Content-Type' => 'application/json'}
)
You can remove Body and Header if you don't have specific Body or Header,
and if you want to achieve Get request its even easier:
responce = HTTParty.get('http://example.com.json')
json=JSON.parse(responce.body) # in case you expect json responce
You need to use a form in order to generate a POST request from the web page. Rails provides you with Form helpers that would help you achieve this.
<div class="box box-warning">
<div class="box-header">
<%= form_tag make_payment_path do %>
<%= hidden_field_tag "access_token", #access_token %>
<h3 class="box-title">Pay Bill using Venmo Account</h3>
<div id="payment_note_input">
<%= text_field_tag "payment_note", nil, class: "form-control", placeholder: "add a note to your payment" %>
</div>
<div id="payment_target_input" >
<%= text_field_tag "payment_target", nil, class: "form-control", placeholder: "pay an email address" %>
</div>
<div id="payment_amount_input">
<%= text_field_tag "payment_amount",nil, class:"form-control", placeholder: "enter the payment amount! ">
</div>
</br>
<%= sumbit_tag "Make payment", class:"btn btn-danger" %>
<% end %>
</div>
And then you can access the form variables in your controller by...
def make_payment
access_token = params[:access_token]
note = params[:payment_note]
target = params[:payment_target]
...
end

Resources