Javascript / jQuery - Price calculation -
i'm building events app using ruby on rails. @ moment user wishes book onto event can book , pay 1 space @ time. need offer facility them book multiple spaces , pay appropriate price - 5 spaces £10 each = £50 pay etc. i've looked appropriate solutions in ror sort i'm hitting brick wall. however, believe i've perhaps approached wrong way , solution using javascript or jquery best way forward. i'm novice @ both , need assistance in achieving objective.
here's payment/booking page -
i want user able place number of spaces in first text area , price (total amount) change accordingly.
here's other relevant code -
booking.rb -
class booking < activerecord::base belongs_to :event belongs_to :user def total_amount #quantity.to_i * @price_currency.to_money quantity.to_i * strip_currency(event.price) end private def strip_currency(amount = '') amount.to_s.gsub(/[^\d\.]/, '').to_f end end
bookings_controller.rb
class bookingscontroller < applicationcontroller before_action :authenticate_user! def new # booking form # need find event we're making booking on @event = event.find(params[:event_id]) # , because event "has_many :bookings" @booking = @event.bookings.new(quantity: params[:quantity]) # person booking event? @booking.user = current_user #@booking.quantity = @booking.quantity @total_amount = @booking.quantity.to_f * @event.price.to_f end def create # process booking @event = event.find(params[:event_id]) @booking = @event.bookings.new(booking_params) @booking.user = current_user @price = price @quantity = quantity #@total_amount = @booking.quantity.to_f * @event.price.to_f booking.transaction @event.reload if @event.bookings.count > @event.number_of_spaces flash[:warning] = "sorry, event booked." raise activerecord::rollback, "event booked" end end if @booking.save # charge user who's booked # #{} == puts variable string stripe::charge.create(amount: @event.price_pennies, currency: "gbp", card: @booking.stripe_token, description: "booking number #{@booking.id}") flash[:success] = "your place on our event has been booked" redirect_to event_path(@event) else flash[:error] = "payment unsuccessful" render "new" end if @event.is_free? @booking.save! flash[:success] = "your place on our event has been booked" redirect_to event_path(@event) end end #def total_amount #@total_amount = @booking.quantity * @event.price #end private def booking_params params.require(:booking).permit(:stripe_token, :quantity) end end
bookings.new.html.erb
<div class="col-md-6 col-md-offset-3" id="eventshow"> <div class="row"> <div class="panel panel-default"> <div class="panel-heading"> <h2>confirm booking</h2> </div> <div class="panel-body"> <p>confirm number of spaces wish book here: <input type="number" placeholder="1" min="1" value="1"></p> <p>total amount £<%= @event.price %></p> <%= simple_form_for [@event, @booking], id: "new_booking" |form| %> <span class="payment-errors"></span> <div class="form-row"> <label> <span>card number</span> <input type="text" size="20" data-stripe="number"/> </label> </div> <div class="form-row"> <label> <span>cvc</span> <input type="text" size="4" data-stripe="cvc"/> </label> </div> <div class="form-row"> <label> <span>expiration (mm/yyyy)</span> <input type="text" size="2" data-stripe="exp-month"/> </label> <span> / </span> <input type="text" size="4" data-stripe="exp-year"/> </div> </div> <div class="panel-footer"> <%= form.button :submit %> </div> <% end %> <% end %> </div> </div> </div> <script type="text/javascript" src="https://js.stripe.com/v2/"></script> <script type="text/javascript"> stripe.setpublishablekey('<%= stripe_public_key %>'); var striperesponsehandler = function(status, response) { var $form = $('#new_booking'); if (response.error) { // show errors on form $form.find('.payment-errors').text(response.error.message); $form.find('input[type=submit]').prop('disabled', false); } else { // token contains id, last4, , card type var token = response.id; // insert token form gets submitted server $form.append($('<input type="hidden" name="booking[stripe_token]" />').val(token)); // , submit $form.get(0).submit(); } }; // jquery(function($) { - changed line below $(document).on("ready page:load", function () { $('#new_booking').submit(function(event) { var $form = $(this); // disable submit button prevent repeated clicks $form.find('input[type=submit]').prop('disabled', true); stripe.card.createtoken($form, striperesponsehandler); // prevent form submitting default action return false; }); }); </script>
one aspect of building site didn't appreciate how difficult , complex can deal money when using ror. few of suggestions i've received stated should using monetize gem (i'm not, i'm using money-rails) , coupled model method/mvc magic achieve this. however, think i'd prefer route if right solution can found.
as suggest, 1 approach use javascript calculate total.
you change snippet of view:
<p> confirm number of spaces wish book here: <input type="number" placeholder="1" min="1" value="1"> </p> <p>total amount £<%= @event.price %></p>
to make easier target jquery , provide reference price per space. example:
<div class="calculate-total"> <p> confirm number of spaces wish book here: <input type="number" placeholder="1" min="1" value="1"> </p> <p> total amount £<span class="total" data-unit-cost="<%= @event.price %>">0</span> </p> </div>
using javascript, can listen keyup
event on input field , perform calculation.
$('.calculate-total input').on('keyup', calculatebookingprice); function calculatebookingprice() { var unitcost = parsefloat($('.calculate-total .total').data('unit-cost')), numspaces = parseint($('.calculate-total .num-spaces').val()), total = (numspaces * unitcost).tofixed(2); if (isnan(total)) { total = 0; } $('.calculate-total span.total').text(total); }
having function separated event listener means call when page loads have starting value.
here's fiddle demonstrate (it assumes @event.price
10).
update
the key here @event.price
should return unit price of booking. new action can simple this:
def new # find event booking. @event = event.find(params[:event_id]) # @event.price should return unit cost of booking. # don't need set attributes here -- can add them in create. @booking = @event.bookings.new end
also note if want store quantity
and/or total_amount
on @booking
object, should move fields inside form (simple_form_for
) , adjust markup submitted part of booking. this:
<%= simple_form_for [@event, @booking], id: "new_booking" |form| %> <%= f.input :quantity %> <%= f.input :total_amount %> ...
and adjust javascript target these inputs (instead of input
, span
in original post).
Comments
Post a Comment