Coffeescript / JQuery not detecting form submit click in rails update action - javascript

I have a profile form which updates user information.In this form there are fields to enter Credit Card Information. Stripe is being used as the payment gateway.
I have followed Ryan Bates episode on integration of rails with Stripe.
The only difference(what I see is) between his example and my implementation is that he uses a new form where as my form updates.
This is my form partial written in haml:
= form_for([#user, #profile], url: user_profile_path(#user), :html => { :multipart => true }) do |f|
- unless #profile.avatar.url == '/avatars/original/missing.png'
= image_tag #profile.avatar.url(:square)
= f.file_field :avatar, hide_label: true
%h3 Credit Card Information
- if #profile.stripe_customer_token.present?
Credit card has been provided.
- else
= f.hidden_field :stripe_customer_token
= f.text_field :credit_card_number, :autocomplete => false, label: "Credit Card Number", id: "card_number"
= f.text_field :card_code, :size => 4, :autocomplete => "off", label: "CVV Code", id: "card_code"
.field
= label_tag :exp_month, "Card Expiration"
%br
Month
= select_month nil, {add_month_numbers: true}, {name: :exp_month, id: "card_month", class: "form-control"}
%br
Year
= select_year nil, {start_year: Date.today.year, end_year: Date.today.year+15}, {name: :exp_year, id: "card_year", class: "form-control"}
#stripe_error
%noscript JavaScript is not enabled and is required for this form. First enable it in your web browser settings.
%br
= f.submit nil, id: "update_profile"
and this the coffee script:
jQuery ->
Stripe.setPublishableKey($('meta[name="stripe-key"]').attr('content'))
profile.setupForm()
profile =
setupForm: ->
$('#update_profile').submit -> ##### LINE A #####
$('input[type=submit]').attr('disabled', true)
if $('#card_number').length
profile.processCard()
false
else
true
processCard: ->
card =
number: $('#card_number').val()
cvc: $('#card_code').val()
expMonth: $('#card_month').val()
expYear: $('#card_year').val()
Stripe.createToken(card, profile.handleStripeResponse)
handleStripeResponse: (status, response) ->
if status == 200
$('#profile_stripe_customer_token').val(response.id)
$('#update_profile')[0].submit() ###### LINE B #####
else
$('#stripe_error').text(response.error.message)
$('input[type=submit]').attr('disabled', false)
The Problem
On clicking submit on the browser, coffee script does not detect the form submission at LINE A.
Introducing a random link and changing LINE A to find that link- from submit to click, detects the user click but LINE B does not work.
Question
Why does the coffee script not detect the user click and how do I get this to work.
Can this be done with Java script?

Related

Submit stops working after first successful submit

I have a simple form in a rails app that is rendered within a partial called roster_panel:
<div id = 'active_admin_content'>
<%= semantic_form_for #roster_item do |form| %>
<h3>Add a counselor</h3>
<div id="counselor_status_message"><%= #status_message %></div>
<%= form.inputs do %>
<%= form.input :first_name, input_html: {id: 'counselor_first_name'} %>
<%= form.input :last_name, input_html: {id: 'counselor_last_name'} %>
<%= form.input :email, input_html: {id: 'counselor_email'} %>
<div class="button_container" >
<input id="submit_counselor_add" type="button" value = "Send forms packet" class = "button" >
</div>
<% end %>
<% end %>
</div>
In my jquery code, I tie the submit click to this:
$( document ).on('turbolinks:load', function() {
$("#submit_counselor_add").click(function(){
$.get("add_counselor_info" , { id: $("#roster_id").text(), first_name: $("#counselor_first_name").val(),
last_name: $("#counselor_last_name").val(), counselor_email: $("#counselor_email").val() },
function(data){ $("#roster_panel").html(data);
}
)
});
});
This routes to this controller method:
def add_counselor_info
#roster = Roster.find(params[:id])
#group = ScheduledGroup.find(#roster.group_id)
#liaison = Liaison.find(#group.liaison_id)
#items = RosterItem.where(roster_id: #roster.id)
#roster_item = RosterItem.new(group_id: #group.id, roster_id: #roster.id,
first_name: params[:first_name], last_name: params[:last_name],
email: params[:counselor_email], youth: false, item_status: 'Unconfirmed' )
if #roster_item.save
#error_count = 0
#status_message = 'This counselor has been added and the forms package has been emailed. You may enter another counselor.'
#items = RosterItem.where(roster_id: #roster.id)
#roster_item = RosterItem.new
else
#error_count = #roster_item.errors.size
#status_message = "#{#error_count} errors prevented saving this information: "
#roster_item.errors.full_messages.each { | message | #status_message << message << ' '}
#items = RosterItem.where(roster_id: #roster.id)
end
render partial: 'roster_panel'
end
After a fresh page load, this process works fine and redisplays the form as expected. However, at that point the submit button no longer triggers the action in jquery. Other jquery functions on the page still work, however. This may have something to do with turbolinks, which I am not very familiar with.
Any help would be appreciated!
After submitting the form, the DOM is replaced by the new one, so on click event binding is being lost.
Try to bind this event through the parent element, which won't be overridden by javascript (e.g. body):
$( document ).on('turbolinks:load', function() {
$("body").on('click', '#submit_counselor_add', function() {
$.get("add_counselor_info", {
id: $("#roster_id").text(),
first_name: $("#counselor_first_name").val(),
last_name: $("#counselor_last_name").val(),
counselor_email: $("#counselor_email").val()
},function(data) {
$("#roster_panel").html(data);
});
});
});

ajax auto form submit with rails4

I'm using rails4.2.0
in my e-commerce site, when a user submit his payment type, I want to redirect outside website. The flow is below.
a user choose payment type
use click submit button
-- ajax (format js) --
redirect to outside website using post method
source of 2 and 3 are like ,
create.html.erb
<%= form_for(:user,:url => { controller: "settlements", action: "settlement"}, remote: true, html: {class: :settlement_form}) do |f| %>
<%= f.radio_button :settlement_type, 0 %>paypal
<%= f.radio_button :settlement_type, 1 %>credit card
<%= f.hidden_field :email, :value => #user.email %>
<%= f.hidden_field :fee_type, :value => #user.fee_type %>
<%= f.submit "Submit", data: { disable_with: "Please wait..." }, class: "btn btn-warning" %>
settlement_controller
def settlement
user = User.new(user_params)
if user.save
# parameters for outside website
#payment_params
else
render "new"
end
end
settlement.js.erb
var form = $('<form></form>',{id:"pay",action:'http://outside_ec_site_url/hoge',method:'POST'}).hide();
var body = $('redirect');
body.append(form);
form.append($('<input/>', {type: 'hidden', name: 'something', value: <%= #payment_params[:something] %>}));
form.append($('<input/>', {type: 'hidden', name: 'something', value: <%= #payment_params[:something] %>}))
form.submit();
I fixed this problem, but I want to know better method.
changed settlement.js.erb like,
$("#redirect").html("<%= escape_javascript(render :partial => 'pay' ) %>");
and created new file _pay.html.erb
<script>
$('<form/>', {id: 'paygent',action: "outside_website_url", method: "POST"})
.append($('<input/>', {type: 'hidden', name: 'something1', value: "<%= #payment_params[:somthing1] %>"}))
.append($('<input/>', {type: 'hidden', name: 'something2', value: "<%= #paygent_params[:something2] %>"}))
.appendTo(document.body)
.submit();
</script>
then, it works.
Do you know any other method? Any idea is appriciated.

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 %>

Removed novalidate doesn't validate form

I'm using Zurb Foundation's Abide validations for a form. When I render the form, the form has a novalidate attribute. I removed the attribute with
$('#new_user').removeAttr('novalidate')
I refreshed the page, but still unable to submit. I saw that I should add $('#new_user').validate(), but the didn't work either. Instead it added the novalidate back.
$("#new_user").removeAttr('novalidate')
$( ->
subscription.setupForm()
subscription =
setupFrom: ->
$('#new_user').submit ->
$('input[type=submit]').attr('disabled', true)
if $('#card_number').length
subscription.processCard()
false
else
true
processCard: ->
card =
number: $('#card_number').val()
cvc: $('#card_code').val()
expMonth: $('#card_month').val()
expYear: $('#card_year').val()
Stripe.createToken(card, subscription.handleStripeResponse)
handleStripeResponse: (status, response) ->
if status == 200
$('#subscription_stripe_card_token').val(response.id)
$('#new_subscription')[0].submit()
else
$('#stripe_error').text(response.error.message)
$('input[type=submit]').attr('disabled', false)
)
The beginning of the form
= form_for(resource, as: resource_name, url: registration_path(resource_name), data: {abide: true}) do |f|
= devise_error_messages!
= hidden_field_tag 'plan', #plan
.field
= f.label :name, 'Full name'
= f.email_field :name, autofocus: true, required: true, pattern: 'name'
%small.error
You must enter in your full name
...

Nested Model Form with required fields does not Save

I have a nested model form with parent Foo and child Bar.
I followed http://railscasts.com/episodes/196-nested-model-form-revised through getting this setup for me. It was worked great. I can add and delete Bars easily, through javascript (per the railscast)
Background:
I have a required field of "name" in Bar.
Problem:
If the user leaves the name field blank and then deletes that Bar (through javascript), it does not let me save the form. I do not get any sort of notification. I believe because of the client side validation has kicked it on the required field that I deleted, the form won't let me submit to the server.
Foo.rb
validates :title, presence: true
has_many bars
accepts_nested_attributes_for :workouts, :allow_destroy => true
Bar.rb
validates :name, presence: true
views/foos/_form.html.haml
= simple_form_for(#foo) do |f|
.form_inputs
= f.input :title
= f.simple_fields_for :bars do |p|
= render "bar_fields", f: p
%br
= link_to_add_fields "Add Bar", f, :bars
%br
= f.button :submit
views/foos/_bar_fields.html.haml
%h4 Bar
= f.input :name
= f.input :description
= f.hidden_field :_destroy
= link_to "Delete Bar", '#'
helpers/application_helper.rb
def link_to_add_fields(name, f, association, css_class = "add_fields btn btn-sm btn-info icon-plus")
new_object = f.object.send(association).klass.new
id = new_object.object_id
fields = f.fields_for(association, new_object, child_index: id) do |builder|
render(association.to_s.singularize + "_fields", f: builder)
end
link_to(name, '#', class: css_class, data: {id: id, fields: fields.gsub("\n", "")})
end
application.js
function remove_fields_(link) {
$(link).prev("input[type='hidden']").val("true");
$(link).closest(".fields").hide();
}
What am I doing wrong? Any workaround?
Don't see 'accepts_nested_attributes_for :bars' in your code example, be sure you use this.

Categories