【问题标题】:Rails - Events fully bookedRails - 活动已订满
【发布时间】:2016-12-23 01:18:05
【问题描述】:

我正在使用 Rails 构建一个事件应用程序。我已经在我的控制器中安装了一个代码块,以确保一旦分配/预订了活动的空间总数,就不会发生超额预订。 问题是它似乎只在付款后才起作用,而不是之前。当用户点击预订活动时,我需要代码来显示一条消息,但目前,它允许用户完成付款过程,拿走他们的钱,然后当它重定向回活动页面时,闪消息弹出。 它也仅适用于付费活动,不适用于免费活动。

这是我的 bookings_controller 代码 -

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
        #@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

这可以在控制器中调整还是需要模型中的方法?

【问题讨论】:

  • 此时您的事务块在 if 块之后结束。这是复制粘贴错误还是您的实际代码?
  • 这是实际代码。
  • 您是否尝试过将if 语句放在 预订交易块之前?在我看来,只有在活动空间可用而不是之后才调用 Booking 交易。

标签: ruby-on-rails ruby ruby-on-rails-4 model-view-controller paypal


【解决方案1】:

Rails 提倡胖模型和瘦控制器。考虑到这一点,您应该将业务逻辑从控制器中提取出来。您可以将此代码放入您的模型中。

您可以将交易延长到操作结束。当出现问题时,您可以引发错误并且事务将被回滚。如果在某些错误情况下付款已经完成,您必须处理/重新找到它。

但是,您的代码会遇到 2 个竞争条件。第一个比赛条件发生在某人被发送到贝宝并返回时。在这个时候,第二个客户可以预订并支付了一个活动,当第二个客户从贝宝回来时,不允许再预订这个活动。这可能需要很长时间,您应该重新找到您的客户。

第二个竞态条件从这里开始if @event.bookings.count &gt; @event.number_of_spaces这个语句可以是false同时用于多个请求。即使只剩下一个预订。在这种情况下,您最终会根据需要获得更多预订。

【讨论】:

  • 我是在预订模型中应用交易代码块,还是逻辑不同?我该如何在模型中执行此操作?
  • 我觉得这个问题更适合code review
  • @slowjack2k 仅供参考,您可以通过 [sitename.se] 获得魔术链接,例如[codereview.se] 转为Code Review =)
猜你喜欢
  • 2019-04-08
  • 2020-07-01
  • 1970-01-01
  • 1970-01-01
  • 2011-09-04
  • 2011-01-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多