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 -
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?
I'm not sure
@booking
is persisted into the database.new
creates the object but doesn't save it. Try using thecreate
method which callsnew
thensave
edit I would actually use
new
and thensave
like soThe
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.