0
votes

I'm currently building an Events app using rails and I'm struggling a little with the booking confirmation side and how to show this to a user who has booked to attend an event.

This is my code in the 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



    end

    def create

        # actually process the booking
        @event = Event.find(params[:event_id])
        @booking = @event.bookings.new(booking_params)
        @booking.user = current_user

            if 
                @booking.paid_booking
                flash[:success] = "Your place on our event has been booked"
                @booking.update_attributes!(booking_number: "MAMA" + '- ' + SecureRandom.hex(4).upcase)
                redirect_to event_booking_path(@event)
            else
                flash[:error] = "Booking unsuccessful"
                render "new"
            end
    end

    def free_booking
            if 
                @booking.free_booking
                @booking.update_attributes!(booking_number: "MAMA" + '- ' + SecureRandom.hex(4).upcase)
                redirect_to event_booking_path(@event)
            else
                flash[:error] = "Booking unsuccessful"
                render "new"
            end
    end

    def show
        @event = Event.find(params[:event_id])
        @booking = @event.bookings.new
        @booking = Booking.find_by(params[:booking_number])
    end

    def update
        puts params
        @event = Event.find(params[:event_id])
        @booking = @event.bookings.new(booking_params)


        if @booking.save
            redirect_to event_booking_path , notice: "Booking was successfully updated!"
        else
            render 'new'
        end
    end




    private

    def booking_params
        params.require(:booking).permit(:stripe_token, :booking_number, :quantity, :event_id, :stripe_charge_id, :total_amount)
    end



end

Here's the form view for both free & paid bookings -

new.html.erb

<% if @booking.free_booking %>
  <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>



                <%= simple_form_for [@event, @booking], id: "new_booking" do |form| %>
                    <% if @booking.errors.any? %>
                        <h2><%= pluralize(@booking.errors.count, "error") %> prevented this Booking from saving:</h2>
                  <ul>
                        <% @booking.errors.full_messages.each do |message| %>
                      <li><%= message %></li>
                    <% end %>
                  </ul>
                <% end %>  

                <div class="form-group">
                    <p>Please confirm the number of spaces you wish to reserve for this event.</p>
                    <%= form.input :quantity, class: "form-control" %>
                </div>  
                 <p> This is a free event. No payment is required.</p>

                   <div class="panel-footer"> 


                     <%= form.submit :submit, label: 'Confirm Booking', class: "btn btn-primary" %>

                     <% end %>
                  </div>                       


<% else %>

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



                <%= simple_form_for [@event, @booking], id: "new_booking" do |form| %>

                 <div class="calculate-total">
                              <p>
                                  Confirm number of spaces you wish to book here:
                                    <input type="number" placeholder="1" name="booking[quantity]"  min="1" value="1" class="num-spaces">
                              </p>
                                <p>
                                    Total Amount
                                    £<span class="total" data-unit-cost="<%= @event.price %>">0</span>
                                </p>
                          </div>



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

And my model -

Booking.rb

class Booking < ActiveRecord::Base

    belongs_to :event
    belongs_to :user


  #before_create :set_booking_number 
  #before_validation :set_is_free
     validates :quantity, presence: true, numericality: { greater_than_or_equal_to: 0 }
     validates :total_amount, presence: true, numericality: { greater_than_or_equal_to: 0 }
     validates :quantity, :total_amount, :booking_number, presence: true

  def set_booking_number
    self.booking_number = "MAMA" + '- ' + SecureRandom.hex(4).upcase
  end

  def set_is_free
    set_is_free = total_amount.nil?
  end


  def free_booking
      self.valid?
        # Free events don't need to do anything special
          if event.is_free?

            save!
          end
  end



    def paid_booking
        # Don't process this booking if it isn't valid
        self.valid?



                # Paid events should charge the customer's card
                #else

            begin
                        self.total_amount = event.price_pennies * self.quantity
                        charge = Stripe::Charge.create(
                            amount: total_amount,
                            currency: "gbp",
                            source: stripe_token, 
                            description: "Booking created for amount #{total_amount}")
                        self.stripe_charge_id = charge.id
              self.booking_number = "MAMA" + '- ' + SecureRandom.hex(4).upcase
                        save!
                    rescue Stripe::CardError => e
                    errors.add(:base, e.message)
                    false
                end
            #end 
        #end
  end
end

In my show views I have the following code for free bookings. In this instance I simply want to confirm (at this stage) the event title, quantity of spaces they've requested and the unique booking number -

                <h1>Hi there</h1>

                <p>You have placed a booking on <%= @event.title %>.</p>

                <p>You have reserved <%= @booking.quantity %> spaces for this event.</p>

                <p>Your booking number is <%= @booking.booking_number %></p>

                <p>We hope you have a wonderful time. Enjoy!</p>

At the moment, when I perform a test booking I get this in my views - Booking confirmation

So, basically, the specific details for quantity and number are not showing. In my bookings table I have an event_id and user_id. Even though each booking attracts an id I dont actually have booking_id as a column in my bookings table - does this make any difference?

schema.rb

create_table "bookings", force: :cascade do |t|
    t.integer  "event_id"
    t.integer  "user_id"
    t.string   "stripe_token"
    t.datetime "created_at",                   null: false
    t.datetime "updated_at",                   null: false
    t.integer  "quantity",         default: 1
    t.integer  "total_amount"
    t.string   "stripe_charge_id"
    t.string   "booking_number"
  end

I'm sure this is something so obvious but I'm failing to spot it. What am I missing?

1
I think @booking.quantity is nil please check this\Kaushlendra Tomar
In my booking table its set as this - 't.integer "quantity", default: 1'Mike.Whitehead
Check, (perhaps in a rails console) that the the particular booking referenced by booking_number in the params hash actually exists in your d/b. Also you can delete the second line in the show method.margo
I've looked via the console and I got this - Booking.find_by(booking_number: "MAMA- 5D4EFC95") Booking Load (0.3ms) SELECT "bookings".* FROM "bookings" WHERE "bookings"."booking_number" = ? LIMIT 1 [["booking_number", "MAMA- 5D4EFC95"]] => #<Booking id: 91, event_id: 22, user_id: nil, stripe_token: nil, created_at: "2016-11-11 20:52:51", updated_at: "2016-11-11 20:52:51", quantity: 2, total_amount: nil, stripe_charge_id: nil, booking_number: "MAMA- 5D4EFC95">Mike.Whitehead
None of your booking attributes are being output, maybe try logging the @booking variable from the controller to ensure that it is what you expect it to be. Also have you setup any tests for that controller as that will also help you to debug.margo

1 Answers

1
votes

I'm not sure @booking is persisted into the database. new creates the object but doesn't save it. Try using the create method which calls new then save

 def update
        @event = Event.find(params[:event_id])

        if @event.bookings.create(booking_params)
            redirect_to event_booking_path , notice: "Booking was successfully updated!"
        else
            render 'new'
        end

end

edit I would actually use new and then save like so

     def update
        @event = Event.find(params[:event_id])
        @booking = @event.bookings.new(booking_params)


        if @booking.save
            redirect_to event_booking_path , notice: "Booking was successfully updated!"
        else
            render 'new'
        end

end

The save method will return with true or false if the object was saved or not, the result of this can be used in the conditional.

Create on the other hand will return the model regardless of whether the object was saved or not. Which means the if statement will always be true.

So, using new + save will allow you to actually see if the booking was saved or not or if another error occurred.