Only allow Stripe Purchases on certain model parameters - javascript

Rails newbie here, working with Stripe's API. I have a model in my rails app called pieces. Each piece has an integer called status. I only want people to be able to purchase the piece if the piece has a status of 1. In my current code, I have hid the buy button on the pieces unless the piece of the status is 1. This works most of the time, but, if two people view the piece at the same time, then they can both buy them. This is because the status of the piece on the other page does not update until the page is reloaded.
My request: I want to find a way to check that the piece's status is 1, right before someone buys it. If it is not 1, I want there to be a rails flash message saying that the piece has already been bought. This should prevent the user from being charged and prevent a charge from being created.
Here is my charges controller:
class ChargesController < ApplicationController
def create
piece = Piece.find(params[:piece_id])
customer = Stripe::Customer.create(
:email => params[:stripeEmail],
:source => params[:stripeToken]
)
charge = Stripe::Charge.create(
:customer => customer.id,
:amount => piece.total_price_in_cents,
:description => piece.title,
:currency => 'usd'
)
purchase = Purchase.create(
customer_email: params[:stripeEmail],
total_transaction: piece.total_price,
stripe_fee: piece.stripe_fee,
taxes: piece.taxes,
artist_cut: piece.artist_cut,
charity_cut: piece.charity_cut,
our_cut: piece.our_cut,
currency: charge.currency,
card: params[:stripeToken],
description: charge.description,
customer_id: customer.id,
piece_id: piece.id,
customer_name: params[:stripeShippingName],
customer_address_line_1: params[:stripeShippingAddressLine1],
customer_city: params[:stripeShippingAddressCity],
customer_state: params[:stripeShippingAddressState],
customer_zip_code: params[:stripeShippingAddressZip],
customer_country: params[:stripeShippingAddressCountry],
seller_name: piece.user.name,
seller_email: piece.user.email,
seller_address_line_1: piece.user.address_line_1,
seller_address_line_2: piece.user.address_line_2,
seller_city: piece.user.city,
seller_state: piece.user.state,
seller_zip_code: piece.user.zip_code
)
purchase.ship_by = purchase.created_at + 7.days
purchase.arrive_by = purchase.created_at + 21.days
purchase.save!
piece.status = 3
piece.save!
redirect_to pieces_path, notice: "Thanks for buying #{piece.title} for $#{'%.2f' % piece.total_price}. You should get an email shortly."
rescue Stripe::CardError => e
flash[:error] = e.message
redirect_to new_charge_path
end
end
And here is my show page for the pieces, which has the stripe buy button on it:
<div class="container">
<div class="row">
<div class="col-md-offset-2 col-md-8">
<div class="panel panel-default">
<div class="panel-body">
<!-- Stripe Form -->
<% if current_user != #piece.user && #piece.status == 1 %>
<%= form_tag charges_path, id: 'chargeForm' do %>
<script src="https://checkout.stripe.com/checkout.js"></script>
<%= hidden_field_tag 'stripeToken' %>
<%= hidden_field_tag 'stripeEmail' %>
<button id="btn-buy-show" type="button" class="btn btn-success btn-lg btn-block">Buy for $<%= number_with_precision(#piece.total_price, :precision => 2, :delimiter => ',')%></button>
<script>
var handler = StripeCheckout.configure({
key: '<%= Rails.configuration.stripe[:publishable_key] %>',
shippingAddress: true,
token: function(token, arg) {
document.getElementById("stripeToken").value = token.id;
document.getElementById("stripeEmail").value = token.email;
document.getElementById("chargeForm").submit();
}
});
document.getElementById('btn-buy-show').addEventListener('click', function(e) {
handler.open({
name: 'Metallic Palette',
description: '<%= #piece.title %> ($<%= number_with_precision(#piece.total_price, :precision => 2, :delimiter => ',')%>)',
amount: document.getElementById("amount").value
});
e.preventDefault();
})
</script>
<% end %>
<% end %>
<% if #piece.status == 3 %>
<p>This piece has already been bought.
<% if current_user == #piece.user || admin_user_signed_in? %>
<%= render 'pieces/purchase_details' %>
<% end %>
</p>
<% end %>
</div>
</div>
</div>
Thank you guys so much.

You just need to check it :)
def create
piece = Piece.find(params[:piece_id])
if piece.status != 1
flash[:error] = 'Piece is not available :('
return redirect_to peaces_path # or whatever
end
...
end
However, few suggests for you:
1) Don't use numbers in your code. Make constants (like Piece::AVAILABLE) and methods (piece.available?) or use enum. You will have lots of problems in future, if you will just use your numbers
2) Extract form object - you don't want to have so large methods in your controller. If you extract it to separate service - it will be much more testable, predictable and updatable.
3) Extract Piece.find and piece status check into before_filters.

Related

render follow/unfollow button in rails with ajax

I have implemented follow/unfollow functionality and would like to add AJAX call to it, but I am stuck.
My partial _follow_button.html.erb for follow/unfollow which is rendered on Users->index, looks like:
<% if current_user.id != user.id %>
<% if !current_user.following?(user) %>
<%= form_for(current_user.active_relationships.build, remote: true) do |f| %>
<div><%= hidden_field_tag :followed_id, user.id %></div>
<span class="follow"><%= f.submit "Follow User", class: "btn btn-primary btn-sm" %></span>
<% end %>
<% else %>
<%= form_for(current_user.active_relationships.find_by(followed_id: user.id),
html: { method: :delete }, remote: true) do |f| %>
<span class="unfollow"><%= f.submit "Unfollow User", class: "btn btn-secondary btn-sm" %></span>
<% end %>
<% end %>
<% end %>
Then my controller for relationships looks like:
class RelationshipsController < ApplicationController
respond_to :js, :json, :html
def create
user = User.find(params[:followed_id])
#follow = current_user.follow(user)
end
def destroy
user = Relationship.find(params[:id]).followed
#unfollow = current_user.unfollow(user)
end
end
My view on user profile looks like:
<div class="col-5" style="margin-left: -5px;">
<%= render '/components/follow_button', :user => User.find_by_username(params[:id]) %>
</div>
My routes.rb have the following routes defined:
resources :users do
member do
get :following, :followers
end
end
resources :relationships, only: [:create, :destroy]
My Views folder structure has subfolders Users and Relationships. Both of them have separate controllers, and I have tried adding simple alert function 'alert("Works");' to the create.js.erb in both of those subfolders to try and match them with the controller, but none don't seem to work. This is my first Rails project, and I do not quite understand what the issue could be. Any suggestions?
Calling the partial follow/unfollow
<% if current_user.id != user.id %>
<%= render partial: 'follow_links', locals: { user: user }
<% end %>
Partial follow_links.
<% show_follow_link = current_user.following?(user) ? 'hidden' : '' %>
<% show_unfollow_link = current_user.following?(user) ? '' : 'hidden' %>
<!-- links to follow/unfollow have data-attributes that include the path to make the ajax post and the user to follow, that is used to find the link to show after the ajax call. You should use the path to the controller that will create or destroy the relationship -->
<%= link_to 'Follow', '#', { class: 'follow-user btn-success #{show_follow_link}', "data-url": follow_user_path(user.id), "data-followee": user.id } %>
<%= link_to 'Unfollow', '#', { class: 'unfollow-user btn-danger #{show_unfollow_link}', "data-url": unfollow_user_path(user.id), "data-followee": user.id } %>
Javascript for the partial. Ajax post to follow/unfollow
$('.follow-user').on("click",function() {
follow_unfollow($(this), "follow")
});
$('.unfollow-user').on("click",function() {
follow_unfollow($(this), "unfollow")
});
function follow_unfollow(target, what_to_do)
url = target.attr('data-url')
followee = target.attr('data-followee')
if (what_to_do == "follow") {
other_button = $('.unfollow-user[data-followee="'+followee+'"]')
} else {
other_button = $('.follow-user[data-followee="'+followee+'"]')
}
$.ajax( {
url: url,
type: 'post',
success: function() {
// Hide this link
target.addClass('hidden');
// Show the other link
other_button.removeClass('hidden');
},
error: function(ret) {
alert(ret.responseJSON.error);
}
});
};
Changes in your controller.
class RelationshipsController < ApplicationController
def create
user = User.find(params[:followed_id])
#follow = current_user.follow(user)
respond_to do |format|
if #follow.valid?
format.html
format.json: { render json: #follow }
return
else
format.html
format.json: { render json: { :error => 'Follow failed', :status_code :not_found } }
end
end
end
def destroy
user = Relationship.find(params[:id]).followed
#unfollow = current_user.unfollow(user)
respond_to do |format|
if #unfollow.valid?
format.html
format.json: { render json: #unfollow }
else
format.html
format.json: { render json: { :error => 'Unfollow failed', :status_code :not_found } }
end
end
end
end
An advice
An advice, also regarding your last question: I would recommend - instead of posting questions about debugging code on StackOverflow - create a good debugging environment for yourself.
Byebug or Binding pry is a good place to start, but before you can use those properly you need to understand the code you are using. I would recommend reading Working with Javascript in depth! - it really helped me getting the hang of it and understanding the dataflow of Rails and ajax.
This would, i think, break the unbreakable Stackoverflow-loop, that i myself were tied to for a long time:
loop do
puts "Try code"
sleep 1000
puts "Arrhh! an error!"
sleep 1000
puts "Posting on Stackoverflow"
sleep 1000
puts "Waiting for answer"
sleep 1000
end
I hope you figure it out!

rails chat with private_pub (controller action from other controller, JS to rails)

I'm following this tutorial to create a real-time chat in rails app: http://josephndungu.com/tutorials/gmail-like-chat-application-in-ruby-on-rails
Unlike this example, where you can click on a button that belongs to the user and the chat will pop up and it stays on the user index page(root), I would like to have an "embedded" chat, so when you go to the the user show page with and http request it will be already there and ready for the input.
How could I do that? At the moment if I try to embed the app says there is no conversation.id. I guess the reason is that the JS gets loaded after the site is rendered, so conversation.id is not there yet when it's needed. I tried to call the conversations controller's create action for the users controller, but I haven't been able to pull it off.
Here is the current code:
Button that initializes the conversation:
<%= link_to "Send message", "#", class: "btn btn-success btn-xs start-conversation", "data-sid" => current_user.id, "data-rip" => #user.id %>
users.js (sending data to create action to conversations controller)
$('.start-conversation').click(function (e) {
e.preventDefault();
var sender_id = $(this).data('sid');
var recipient_id = $(this).data('rip');
$.post("/conversations", { sender_id: sender_id, recipient_id: recipient_id }, function (data) {
chatBox.chatWith(data.conversation_id);
});
});
chat.js
chatBox = {
/**
* creates an inline chatbox on the page by calling the
* createChatBox function passing along the unique conversation_id
*
* #param conversation_id
*/
chatWith: function (conversation_id) {
chatBox.createChatBox(conversation_id);
$("#chatbox_" + conversation_id + " .chatboxtextarea").focus();
},
conversations controller
def create
if Conversation.between(params[:sender_id], params[:recipient_id]).present?
#conversation = Conversation.between(params[:sender_id], params[:recipient_id]).first
else
#conversation = Conversation.create!(conversation_params)
end
render json: { conversation_id: #conversation.id }
end
def show
#conversation = Conversation.find(params[:id])
#receiver = interlocutor(#conversation)
#messages = #conversation.messages
#message = Message.new
end
private
def conversation_params
params.permit(:sender_id, :recipient_id)
end
def interlocutor(conversation)
current_user == conversation.recipient ? conversation.sender : conversation.recipient
end
show.html.erb (conversation window that pops up)
<div class="chatboxhead">
<div class="chatboxtitle">
<i class="fa fa-comments"></i>
<h1><%= #receiver.profile.first_name %> <%= #receiver.profile.last_name %></h1>
</div>
<div class="chatboxoptions">
<%= link_to "<i class='fa fa-minus'></i> ".html_safe, "#", class: "toggleChatBox", "data-cid" => #conversation.id %>
<%= link_to "<i class='fa fa-times'></i> ".html_safe, "#", class: "closeChat", "data-cid" => #conversation.id %>
</div>
<br clear="all"/>
</div>
<div class="chatboxcontent">
<% if #messages.any? %>
<%= render #messages %>
<% end %>
</div>
<div class="chatboxinput">
<%= form_for([#conversation, #message], :remote => true, :html => {id: "conversation_form_#{#conversation.id}"}) do |f| %>
<%= f.text_area :body, class: "chatboxtextarea", "data-cid" => #conversation.id %>
<% end %>
</div>
<%= subscribe_to conversation_path(#conversation) %>
(This last line is for private_pub gem)

Sporadic issues with Stripe javascript in Rails app

I have deployed a custom Stripe payment form in our app, and 97% of the time it works just fine. Occasionally, I see Stripe report an error on an attempted payment.
POST /v1/customers
error:
type: "invalid_request_error"
message: "You passed an empty string for 'card'. We assume empty values are an attempt to unset a parameter; however 'card' cannot be unset. You should remove 'card' from your request or supply a non-empty value"
param: "card"
This is raised when creating a customer with the Stripe token that should've been generated from the javascript:
sale = current_user.sales.create(
plan_id: plan.id,
amount: plan.price_in_cents,
stripe_token: params[:stripeToken]
)
After much troubleshooting I've confirmed that this is happening because Stripe is not getting called in the first place to create the token. In other words, this is not an issue of passing params, where the token is generated but simply not passed to the controller. For some reason, something in the javascript is not running, so the form simply submits without it calling Stripe.
Again remember that 97% of the time this issue does not occur. When it does occur it happens to the same user over and over again. I have not found any pattern with browsers (it has happened on Chrome, IE, Firefox). Also, eventually users facing this problem have been able to successfully pay using the same browser and without any settings adjustments. This makes me think there's something potentially with my server environment and not the client.
Here is my full javascript:
subscription.js
var stripeResponseHandler = function(status, response) {
var $form = $('#paid_subscription');
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
$('#stripe_card_token').val(token);
//$form.append($('<input type="hidden" name="stripeToken" />').val(token));
// and submit
$form.get(0).submit();
}
};
jQuery(function($) {
$('#card_number').payment('formatCardNumber')
$('#paid_subscription').submit(function(event) {
// var expiration = $("#card-expiry").payment("cardExpiryVal")
// $('#card-exp-month').val(expiration.month);
// $('#card-exp-year').val(expiration.year);
var $form = $(this);
// 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;
});
});
And here is the controller code, just in case:
charges#create
def create
token = params[:stripeToken]
bundle = Bundle.find_by_id(params[:bundle_id])
if bundle
process_bundle_sale(bundle, token)
else
plan = Plan.find(params[:plan_id])
begin
sale = current_user.sales.create(
plan_id: plan.id,
amount: plan.price_in_cents,
stripe_token: params[:stripeToken]
)
sale.process!
if sale.finished?
if current_user.subscribe_with_referer({plan_id: plan.id}, session[:http_referer])
TrackSubscriptions.track_paid_subscription(cookies, plan, sale)
flash[:success] = "Success! You now have full access to \"#{plan.title}\""
redirect_to plan_path(plan)
else
flash[:alert] = "Oops something went wrong. Please contact support and we'll get to the bottom of it."
redirect_to plan_path(plan)
end
else
flash[:alert] = sale.error
redirect_to new_plan_subscription_path(plan.slug)
#redirect_to plan_path(plan)
end
end
end
end
Finally here's the form code:
<%= simple_form_for #charge = Sale.new, :url => charges_path, :method => :post, html: { id: :paid_subscription } do |f| %>
<fieldset class = "inputWrapper">
<h2 class="sub-header">Payment</h2>
<span class="payment-errors"></span>
<%= hidden_field_tag :plan_id, #plan.id %>
<%= hidden_field_tag :stripeToken, nil,id: :stripe_card_token %>
<div class="payment-fields">
<div class="field card-number-field">
<label class="control-label">Card Number</label>
<%= text_field_tag :card_number, nil, name: nil, placeholder: "4444 1234 1234 1234",:data => {:stripe => 'number' } %>
</div>
<div class="field security-code-field">
<label class="control-label">Security Code</label>
<%= text_field_tag :card_code, nil, name: nil, placeholder: "123", :data => {:stripe => 'cvc' } %>
</div>
<div class="field expiry-field">
<label class="control-label">Exp (MM/YYYY)</label>
<div class="month-field">
<%= text_field_tag :exp_month, nil, name: nil, placeholder: "10", id: "card-exp-month", maxlength: 2, data: { stripe: "exp-month" } %>
<span class="slash"> / </span>
</div>
<div class="year-field">
<%= text_field_tag :exp_year, nil, name: nil, placeholder: "2016", id: "card-exp-year", maxlength: 4, data: { stripe: "exp-year" } %>
</div>
</div>
<div style="clear:both"></div>
</div>
<%= render 'end_form', :plan => #plan %>
<div class="submit-button">
<%= f.submit 'Register for Course', :class => "button greenButton", :error => false %>
</div>
</fieldset>
<% end %>

Multiple stripe payment buttons on one page of rails 4 app

I'm building a payment page that lists three different subscription options and am using Stripe's checkout to manage the payments.
The page is rendering properly, and all 3 subscription options have the "buy now" button that should be linked to Stripe.
My issue is that the first button is the only one that is properly pulling up the Stripe checkout flow. Buttons 2 and 3 throw the following error:
Unknown action
The action 'index' could not be found for ChargesController
The relevant part of my payment page is:
<% #plans.each do |plan| %>
<li class="col-md-3 plan <%= 'plan-primary' if plan.highlight? %>">
<div class="img-thumbnail">
<div class="caption">
<h3><%= plan.name %></h3>
<h4><%= plan_price(plan) %></h4>
<div class="call-to-action">
<% if #subscription.nil? %>
<% if plan.highlight? %>
<%= form_tag main_app.charges_path do %>
<script src="https://checkout.stripe.com/checkout.js"></script>
<button id="customButton" class="btn btn-success">Buy Now</button>
<script>
var handler = StripeCheckout.configure({
key: '<%= 'pk_test_my_pk' %>',
image: '/assets/my_logo.png',
token: function(response) {
var tokenInput = $("<input type=hidden name=stripeToken />").val(response.id);
var emailInput = $("<input type=hidden name=stripeEmail />").val(response.email);
$("form").append(tokenInput).append(emailInput).submit();
}
});
document.getElementById('customButton').addEventListener('click', function(e) {
handler.open({
name: 'My Co',
description: 'Listing subsctiption ($50.00)',
amount: 50*100,
shippingAddress: false
});
e.preventDefault();
});
</script>
<% end %>
<% else %>
<%= form_tag main_app.charges_path do %>
<script src="https://checkout.stripe.com/checkout.js"></script>
<button id="customButton" class="btn btn-large btn-primary">Buy Now</button>
<script>
var handler = StripeCheckout.configure({
key: '<%= 'pk_test_my_pk' %>',
image: '/assets/my_logo.png',
token: function(response) {
var tokenInput = $("<input type=hidden name=stripeToken />").val(response.id);
var emailInput = $("<input type=hidden name=stripeEmail />").val(response.email);
$("form").append(tokenInput).append(emailInput).submit();
}
});
document.getElementById('customButton').addEventListener('click', function(e) {
// Open Checkout with further options
handler.open({
name: 'My Co',
description: 'Listing subsctiption ($40.00)',
amount: 40*100,
shippingAddress: false
});
e.preventDefault();
});
</script>
<% end %>
<% end %>
Ideas on why only one of the 3 buttons is working properly?
Thanks!
You can get it to seem to work by having unique button ids, e.g.
<button id="<%= dom_id(pricing, 'btn') %>
but there is another problem, with the stripe js. If you execute StripeCheckout.configure multiple times it will create multiple iframes with the same name attribute. Unfortunately this means whatever your customer tries to buy, they will always be sold the last thing you inserted, even if the stripe popup said it was selling them something else.
We used this solution: one form, and dynamically inserting the price and times:
<%= form_tag charges_path, id: 'stripe-payment-form' do %>
<%= hidden_field_tag 'amount', nil, id: 'payment_amount' %>
<%= hidden_field_tag 'name', nil, id: 'payment_name' %>
<%= hidden_field_tag 'days', nil, id: 'payment_days' %>
<% Pricing.all.each do |pricing| %>
<p>
<button id="<%= dom_id(pricing, 'btn') %>">
Buy <%= pricing.name %> for <%= number_to_currency(pricing.pounds, unit: '£') %>
</button>
</p>
<% end %>
<%= javascript_tag do %>
var handler = StripeCheckout.configure({
key: "<%= Rails.configuration.stripe[:publishable_key] %>",
image: "<%= image_path('/images/apple-icons/apple-touch-icon-144x144-precomposed.png') %>",
token: function(token, args) {
var form = $('#stripe-payment-form');
// Use the token to create the charge with a server-side script.
// You can access the token ID with `token.id`
form.append($('<input type="hidden" name="stripeToken" />').val(token.id));
form.submit();
}
});
<% Pricing.all.each do |pricing| %>
document.getElementById('<%= dom_id(pricing, 'btn') %>').addEventListener('click', function(e) {
e.preventDefault();
var form = $('#stripe-payment-form');
// set the price etc for the button clicked
$('#payment_amount').val("<%= pricing.pence %>");
$('#payment_name').val("<%= pricing.name %>");
$('#payment_days').val("<%= pricing.days %>");
// Open Checkout with further options
handler.open({
name: 'Company name',
currency: 'GBP',
description: '<%= pricing.name %>',
amount: '<%= pricing.pence %>',
email: '<%= member.email %>',
});
});
<% end %>
<% end %>
<% end %>
I came across the same problem in my own app recently.
All three of your buttons have the same ID.
I know this is old, but I resolved this issue by changing the name of the handler variables (each one should have a different name) instead of changing the HTML ID's.
I recently encountered this problem and wanted to leave an alternative solution. In our app, we have two buttons on the page using stripe.js: "Buy Item" or "Pro Subscription". This method uses jQuery to just remove the second button from the DOM when the first one is clicked. If the user cancels the payment, the button is rendered back into the DOM. This is how the handler might look:
$('#firstButton').on('click', function() {
$('#secondButton').html(""); // Remove the second stripe script from the dom
handler.open({
// handler stuff
closed: function(){
$('#secondButton').html('<%= j render partial: "second_button" %>'); // Renders button back to the DOM if payment is cancelled.
}
});
});

Completely Stuck on AJAX Form Submission With Stripe

I am so frustrated. I'm working with Stripe to create a form submission system for payments. Basically, the form makes an AJAX call to Stripe, which gives me a token on success, which I then use to resubmit the form, also through AJAX. If the form is successful, it redirects to a new page, if not, it populates the form with error messages without re-navigation. Here's my form:
<%= form_for([#issue, #issue_order]) do |f| %>
<% if #issue_order.errors.any? %>
<div class="error_messages">
<h2><%= pluralize(#issue_order.errors.count, "error") %> occurred. </h2>
<ul>
<% #issue_order.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
</ul>
</div>
<% end %>
<% f.hidden_field :issue_id %>
<%= f.hidden_field :stripe_card_token %>
<div class="field">
<%= f.label :email %>
<%= f.text_field :email %>
</div>
<div class="field">
<%= label_tag :card_number, "Credit Card Number " %>
<%= text_field_tag :card_number, nil, name: nil %>
</div>
<div class="field">
<%= label_tag :card_code, "Security Code on Card (CVV) " %>
<%= text_field_tag :card_code, nil, name: nil %>
</div>
<div class="field">
<%= label_tag :card_month, "Card Expiration " %>
<%= select_month nil, {add_month_numbers_true: 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 id="stripe_error"></div>
<div class="actions"><%= f.submit "Purchase Issue", id: "submit_issue_order" %></div>
<% end %>
<div class="errors"></div>
Here is the javascript that handles the form and sets up the stripe information:
var issueOrder;
$(function() {
Stripe.setPublishableKey($('meta[name="stripe-key"]').attr('content'));
issueOrder.setupForm();
});
var issueOrder = {
setupForm: function() {
$('#new_issue_order').submit(function(e) {
e.preventDefault();
$('#submit_issue_order').attr('disabled', true);
issueOrder.processCard();
return false;
});
},
processCard: function() {
var card;
card = {
number: $('#card_number').val(),
cvc: $('#card_code').val(),
expMonth: $('#card_month').val(),
expYear: $('#card_year').val()
};
Stripe.createToken(card, issueOrder.handleStripeResponse)
},
handleStripeResponse: function(status, response) {
if (status == 200) {
$('#issue_order_stripe_card_token').val(response.id);
// $('#new_issue_order')[0].submit();
$.ajax({
type: "POST",
url: $('#new_issue_order').attr('action'),
data: { "issue_order": {
"stripe_card_token": $('#issue_order_stripe_card_token').val(),
"email": $('issue_order_email').val(),
},
"issue_id": $('#issue_order_issue_id').val()
},
dataType: "script"
}, issueOrder.processOrder);
}
else {
$('#stripe_error').text(response.error.message);
$('input[type=submit]').attr('disabled', false)
}
}
And here is my controller:
def create
charge = Stripe::Charge.create(
:amount => 400,
:currency => "usd",
:card => params['issue_order']['stripe_card_token']
)
if charge['paid'] == true
#issue_order = IssueOrder.new(email: params['issue_order']['email'], issue_id: params['issue_id'])
if #issue_order.save
#pdf_token = #issue_order.pdf_token
PdfMailer.pdf_email(params['issue_order']['email'], #issue_order).deliver
else·
flash[:error] = []
flash[:error].push("Your card was charged, but sadly we were unable to create·
a record in the database. Please contact us for your copy of the issue.")
respond_to do |format|
format.js
end
end
else
# run checks for errors and return error messages
flash[:error] = []
flash[:error].push("There was an error in processing your payment.")
render :json => {success: false}
end
end
Typical stripe setup stuff. Works fine when the stripe order is successfully processed. Well, it did before I hand-rolled the AJAX call, I'm assuming it'd be fine if I threw a respond_to |format| in the success case in the controller that redirected to the success page. However, for the error cases, my controller renders create.js.erb, which looks like this:
console.log('yo');
$('.errors').empty();
errors = xhr.getResponseHeader('X-Flash-Error').split(',');
<% flash[:error].each do |error| %>
$('.errors').append($('<p>' + <%= error %> + '</p>'));
<% end %>
setTimeout(function() {
$('.errors').empty();
}, 3500);
The controller clearly reaches the file and renders it, as evidenced by the logs:
Started POST "/issues/1/issue_orders" for 127.0.0.1 at 2013-11-12 23:33:17 -0500
Processing by IssueOrdersController#create as JS
Parameters: {"issue_order"=>{"stripe_card_token"=>"tok_102vmu2pSkyWUgPAToj334Oa"}, "issue_id"=>"1"}
(0.4ms) BEGIN
(0.4ms) ROLLBACK
Rendered issue_orders/create.js.erb (0.1ms)
["Your card was charged, but sadly we were unable to create \n a record in the database. Please contact us for your copy of the issue."]
Completed 200 OK in 1363ms (Views: 3.9ms | ActiveRecord: 0.8ms)
But NOTHING happens on my page, including the console log! If I don't hand roll the AJAX and use remote: true, it gets even worse -- it recognizes my submit() call as HTML and doesn't know what to do with the format, rendering an Unknown Format error.
Help!

Categories