2016-09-07 107 views
0

我正在使用Ruby on Rails构建事件应用程序。目前,希望预订活动的用户一次只能预订一个空间并支付一个空间。我需要为他们提供预订多个空间并支付适当的价格的设施 - 所以每个10英镑需要5个空格= 50英镑付费等。 我已经在RoR中寻找适当的解决方案来对此进行排序,但我正在点击一堵砖墙。 但是,我相信我也许以这种错误的方式来解决这个问题,并且使用javascript或jQuery的解决方案是最好的解决方案。 我在这两方面都是新手,需要一些帮助来实现这个目标。Javascript/jQuery - 价格计算

这里是我的付款/预订页面 -

Booking page

我希望用户能够把在第一个文本区域和价格(总量)相应地改变的空格数。

这里是我的其他相关代码 -

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 
     # I need to find the event that we're making a booking on 
     @event = Event.find(params[:event_id]) 
     # and because the event "has_many :bookings" 
     @booking = @event.bookings.new(quantity: params[:quantity]) 
     # which person is booking the event? 
     @booking.user = current_user 
     #@booking.quantity = @booking.quantity 
     @total_amount = @booking.quantity.to_f * @event.price.to_f 
    end 

    def create 
     # actually process the 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 do 

      @event.reload 
      if @event.bookings.count > @event.number_of_spaces 
      flash[:warning] = "Sorry, this event is fully booked." 
      raise ActiveRecord::Rollback, "event is fully booked" 
      end 
     end 

     if @booking.save 

      # CHARGE THE USER WHO'S BOOKED 
      # #{} == puts a variable into a 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 Your Booking</h2> 
     </div> 

      <div class="panel-body">  
       <p>Confirm number of spaces you wish to 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" do |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 the errors on the form 
    $form.find('.payment-errors').text(response.error.message); 
    $form.find('input[type=submit]').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="booking[stripe_token]"  />').val(token)); 
    // and submit 
    $form.get(0).submit(); 
    } 
    }; 

    // jQuery(function($) { - changed to the line below 
    $(document).on("ready page:load", function() { 

    $('#new_booking').submit(function(event) { 
     var $form = $(this); 

     // Disable the submit button to prevent repeated clicks 
     $form.find('input[type=submit]').prop('disabled', true); 

     Stripe.card.createToken($form, stripeResponseHandler); 

     // Prevent the form from submitting with the default action 
     return false; 
    }); 
    }); 
</script> 

建设这个网站的一个方面,我不明白的是在使用RoR时如何处理金钱是多么困难和复杂。我收到的一些建议表明,我应该使用获利宝石(我不是,我正在使用money-rails),而这与一些模型方法/ MVC魔术结合可以实现这一点。但是,如果能够找到正确的解决方案,我认为我更喜欢这条路线。

+0

这是什么'page:load'事件? ,从未听说过 – madalinivascu

+0

这涉及到条形支付过程。 –

回答

0

正如你所建议的,一种方法是使用JavaScript来计算总数。

你可以改变你鉴于此片段:

<p> 
    Confirm number of spaces you wish to book here: 
    <input type="number" placeholder="1" min="1" value="1"> 
</p> 
<p>Total Amount £<%= @event.price %></p> 

,使其更容易与jQuery的目标,并提供每个价格空间的参考。例如:

<div class="calculate-total"> 
    <p> 
    Confirm number of spaces you wish to 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> 

使用JavaScript,你可以监听输入字段keyup事件并进行计算。

$('.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); 
} 

使函数与事件侦听器分离意味着您可以在页面加载时调用它,以便您有一个起始值。

Here's a fiddle来演示(它假定@event.price是10)。

UPDATE

这里的关键是,@event.price应该返回一个预订的单价。你动作可以如此简单:

def new 
    # Find the event for the booking. 
    @event = Event.find(params[:event_id]) 
    # @event.price should return the unit cost of a booking. 

    # Don't need to set attributes here -- you can add them in create. 
    @booking = @event.bookings.new 
end 

还要注意的是,如果你想存储quantity和/或total_amount@booking对象上,你应该将你的形式(simple_form_for)中的字段和调整标记以便它们作为预订的一部分提交。是这样的:

<%= simple_form_for [@event, @booking], id: "new_booking" do |form| %> 
    <%= f.input :quantity %> 
    <%= f.input :total_amount %> 
    ... 
(在我原来的职位,而不是 inputspan

,并调整JavaScript来针对这些输入。

+0

谢谢,但是当我尝试这个事件价格假定为零。我显然需要初始事件价格来反映事件的实际价格。 –

+0

当然。当你在'new'操作中发现'@ event'时,'@ event.price'应该已经设置好了。在答案中增加了一些细节。 – seancdavis

+0

我是否需要在预订模型中添加一些内容以反映数量?我在上面的问题中包含了预订模型,这反映了我尝试使用Ruby制定total_amount方法的尝试。这是否需要现在出来? –