我正在使用Ruby on Rails构建一个事件应用程序。目前,希望预订活动的用户一次只能预订并支付一个空间。我需要提供设施让他们预订多个空间并支付适当的价格 - 所以5个空间,每个10英镑= 50英镑支付等。 我在RoR中寻找合适的解决方案来解决这个问题,但我正在打砖墙。 但是,我相信我可能以错误的方式接近这一点,并且使用javascript或jQuery的解决方案是最好的方法。 我在这两方面都非常新手,需要一些帮助来实现这一目标。
这是我的付款/预订页面 -
我希望用户能够在第一个文本区域中放置空格数,并且相应地更改价格(总金额)。
这是我的其他相关代码 -
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 :(得分: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)。
<强>更新强>
这里的关键是@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 %>
...
调整JavaScript以定位这些输入(而不是原始帖子中的input
和span
)。