Confused about how to properly use secret keys - ruby-on-rails

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!

Related

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

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.

Render partial through js.erb

Im trying to render a form to add a comment via jquery, but i keep getting this error:
undefined method `render' for #<#<Class:0x007fc8aaa18860>:0x007fc8a0fddfc0>
Here is the js.erb file:
$(document).on('turbolinks:load', function(){
console.log('test');
$('.reply-comment-form').on('click', function(e) {
e.preventDefault();
body = this.id;
$('.nest-' + body).append( "<%= escape_javascript(render partial: 'comment_reply_form')%>");
});
});
Ive tried multiple different iterations of the code but still the same error.
When i try say, this for example:
$('.nest-' + body).append( " This is a test");
It does as it should do.
Ive checked the other questions here and i cant see anything different to what i'm doing so i'm a little stuck.
Here is what im trying to render:
<div class="body">
<span class="tip tip-left"></span>
<div class="message font-medium">
<%= form_for #message do |form| %>
<%= form.label :Reply_to_comment %> <br />
<%= form.text_area :content, :rows => 5, :cols => 80, autofocus: true %> <br />
<%= form.hidden_field :entry_id, value: params[:entry_id] %>
<%= form.hidden_field :parent_id, :value => params[:parent_id] %>
<%= form.submit "Submit"%>
<% end %>
</div>
<div class="flerowspb">
<span class="font-small">
</span>
</span>
</div>
</div>
Thanks
Ok so I've come across the answer, I cant call render from the assets folder.
Here is the link
Try to the following
$('.nest-' + body).append( "<%= escape_javascript(render("messages/comment_reply_form"))%>");
or
$('.nest-' + body).html("<%= escape_javascript(render("messages/comment_reply_form")) %>");
Try using j render:
$('.nest-' + body).append( "<%= j render 'comment_reply_form' %>");
and i think that path for partial view should be more accurate, like 'controller_name/view/partial' , or whatever you have in your code.

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

Rails simple form does not submit

I have a form builded using simple_form_for helper in rails that won't submit, when I add these two fields:
<%=f.input :startDate, :as => :datetime_picker%>
<%=f.input :endDate, :as => :datetime_picker%>
And this javascript:
<script type="text/javascript">
$(function() {
$('#datetimepicker1').datetimepicker({
language: 'en'
});
$('#actioncustom_timezone').set_timezone({format: 'city'});
$("#actioncustom_timezone").select2({ width: "300px" });
});
</script>
When I have these two fields in my form an click submit, the view does not render with failures. When I remove these two fields the form submits perfectly and even shows error.
What is so special about the date field that they break my form when I add them?
EDIT: All the form code:
<h1>New Custom Action</h1>
<div class="row">
<div class="span6 offset3">
<%= simple_form_for(#actionCustom) do |f|%>
<%= render 'shared/error_messages' %>
<%=f.label :action_name%>
<%=f.text_field :action_name%></br>
<%=f.label :contentURL, "Content URL"%>
<%=f.text_field :contentURL%></br>
<%=f.label :callBackURL, "Callback URL"%>
<%=f.text_field :callBackURL%></br>
<%=f.label :customcallbackURL, "Callback URL with custom conent URL"%>
<%=f.text_field :customcallbackURL%></br>
<%=f.label :previewImageURL, "Preview image URL"%>
<%=f.text_field :previewImageURL%></br>
<%=f.date_ :startDate, :as => :datetime_picker%>
<%=f.input :endDate, :as => :datetime_picker%>
<%=f.label :timezone, "Timezone"%>
<%=f.time_zone_select :timezone%>
<%=f.label :message%>
<%=f.text_area :message%></br>
<%=f.label :maxSend, "Max number of all sendings"%>
<%=f.number_field :maxSend, options = {:min=>0,:value=>0}%></br>
<%=f.label :maxSendToday, "Max number of sendings per day"%>
<%=f.number_field :maxSendToday, options = {:min=>0,:value=>0}%></br>
<%=f.label :maxSendDevice, "Max number of sendings per device"%>
<%=f.number_field :maxSendDevice, options = {:min=>0,:value=>0}%></br>
<%=f.label :maxSendDeviceToday,"Max number of sendings per device per day"%>
<%=f.number_field :maxSendDeviceToday, options = {:min=>0,:value=>0}%></br>
<%=f.hidden_field :clientID, :value => current_client.id%>
<%= f.submit "Create Action", class: "btn btn-large btn-primary" %>
<%end%>
</div>
</div>
<script type="text/javascript">
$(function() {
$('#datetimepicker1').datetimepicker({
language: 'en'
});
$('#actioncustom_timezone').set_timezone({format: 'city'});
$("#actioncustom_timezone").select2({ width: "300px" });
});
</script>
Are you using this gem https://github.com/zpaulovics/datetimepicker-rails ?
If you are on rails4 you can use the new date_field which is using new HTML5 pickers.
With this solution you don't need to use jQuery datetimepicker.
If you are not using rails4 you can just set the input type as date or datetime like
<input id="user_born_on" name="user[born_on]" type="datetime" />
and you will get a picker on HTML5 browsers.
I have created an example code for you here: http://jsfiddle.net/2NAL5/
More on this here: http://blog.remarkablelabs.com/2012/12/new-html5-form-input-helpers-rails-4-countdown-to-2013
So I solved my problem. I found out that in the HTML code the date time input was set as required. So when the field was empty I could not submit the form. But after modifying the date time line to this:
<%=f.input :startDate,:as => :datetime_picker,:required => false%>
It Works!!!!!

How to use jquery-addresspicker jquery with rails 3.1

I am trying to use jquery-addresspicker with rails 3.1 but I am not able to make it run.
Here is the link https://github.com/sgruhier/jquery-addresspicker and the documentation does not mention much.
Can anyone suggest how should I use it in my rails app?
did you include google maps
<script src="http://maps.google.com/maps/api/js?sensor=false"></script>
and jquery-ui ?
place the script code in the html, or in separate js file
<script>
$(function() {
var addresspicker = $( "#addresspicker" ).addresspicker();
var addresspickerMap = $( "#addresspicker_map" ).addresspicker({
regionBias: "fr",
elements: {
map: "#map",
lat: "#lat",
lng: "#lng",
locality: '#locality',
country: '#country'
}
});
var gmarker = addresspickerMap.addresspicker( "marker");
gmarker.setVisible(true);
addresspickerMap.addresspicker( "updatePosition");
});
</script>
<div>
<div class='input'>
<%= f.label :address %><br />
<%= f.text_field :address, :id => "addresspicker_map" %>
<%= f.label :locality %><br />
<%= f.text_field :locality, :id => "locality", :disabled => "true" %>
<%= f.label :country %><br />
<%= f.text_field :country, :id => "country", :disabled => "true" %>
...
</div>
<div id="map"></div>
<div id="legend">You can drag and drop the marker to the correct location</div>
</div>
this is a piece of tutorial I made. I haven't tried it, but this is a start for you.
you'll have to style it with css from here:
https://github.com/sgruhier/jquery-addresspicker/blob/master/demos/demo.css
include the js file in the app from here:
https://github.com/sgruhier/jquery-addresspicker/tree/master/src
and images:
https://github.com/sgruhier/jquery-addresspicker/tree/master/demos/images
This has been ported to rails here at this repo https://github.com/ddidier/address_picker-rails

Resources