Reputation: 829
In my Ruby on Rails application I am creating a cinema system, and on the bookings/new page I am allowing the user to choose the amount of seats they require through a drop down menu. But what I want to do is display the number of seats that are currently free in the screen, for example if a screen has 50 seats and 7 have been booked I want the system to display: "There are 43 seats available." I know I will need a method for this but am unsure about how I would implement it and how I would show this message.
It is worth noting that a seat would only be booked for one showing, so it would be free for others, which means that the method would have to be able to count the amount of seats available for that showing.
Can someone please help.
bookings/form.html.erb:
<%= form_for @booking do |f| %>
<%= f.hidden_field :user_id %>
<%= f.hidden_field :showing_id %>
<%= image_tag "thor_hammer.jpg",:size => "900x250" %>
<h1>NEW BOOKING:</h1>
<tr>
<td width="350px">
<br><%= f.label :seats_quantity, 'Please Select The Amount of Seats Required:' %>
</td>
<td width="300px">
<br><%= f.select :seats_quantity, '1'..'10' %><br>
</td>
<td width="300px">
<div class="actions">
<br><%= f.submit 'Book Showing' %>
</div>
<br><%= render "/error_messages", :message_header => "Cannot save: ", :target => @booking %>
</td>
</tr>
<% end %>
Screen.rb:
class Screen < ActiveRecord::Base
has_many :seats
has_many :showings
def screens_info
"#{name}"
end
end
Seat.rb:
class Seat < ActiveRecord::Base
belongs_to :screen
end
Booking.rb:
class Booking < ActiveRecord::Base
belongs_to :user
belongs_to :showing
end
Showing.rb:
class Showing < ActiveRecord::Base
belongs_to :film
has_many :bookings
belongs_to :screen
end
Schema:
create_table "bookings", force: :cascade do |t|
t.integer "user_id"
t.integer "showing_id"
t.integer "seats_quantity"
end
create_table "screens", force: :cascade do |t|
t.string "name"
end
create_table "showings", force: :cascade do |t|
t.date "show_date"
t.time "show_time"
t.integer "film_id"
t.integer "screen_id"
end
create_table "seats", force: :cascade do |t|
t.string "row_letter"
t.integer "row_number"
t.integer "screen_id"
end
It is worth noting that whilst the seats
table contains the attributes row_letter
and row_number
a user IS NOT booking a specific seat, just the quantity of seats they require.
Upvotes: 2
Views: 242
Reputation: 27971
In your Screen
class add:
has_many :bookings, through: :showings
And then your code becomes something like:
def remaining_seats
seats.count - bookings.sum(:seats_quantity) # <-- edited when I realized there was a quantity in a booking
end
def screens_info
"#{name} (#{remaining_seats}/#{seats.count} remaining)"
end
Upvotes: 1
Reputation: 4171
EDIT
The manual way of doing this would be like so:
class Showing < ActiveRecord::Base
def booked_seats
bookings.pluck(:seats_quantity).sum
end
def available_seats
seats.count - booked_seats
end
end
OLD
This looks like a good use of Rails' counter_cache
.
class Booking < ActiveRecord::Base
belongs_to :showing, counter_cache: true
end
This will store the count in a column on the Showing model (which you have to add). Then when you do @showing.bookings.size
(not count), it will refer to that column.
"With this declaration, Rails will keep the cache value up to date, and then return that value in response to the size method." http://guides.rubyonrails.org/association_basics.html
Upvotes: 0
Reputation: 4847
You need to figure out two values: the total seats for a specific showing and how many of those seats are already booked. Supposing you have two variables called scr_id
and shw_id
where the first represents the Screen Id and the second the Showing Id.
Total seats:
total_seats = Seat.where(screen_id: scr_id).count
Total bookings:
total_bookings = Booking.where(showing_id: shw_id).count
And then you only need to compute the differente between both.
available_seats = total_seats - total_bookings
EDIT: SPECIFIC IMPLEMENTATION
It should be implemented as a method in the screen model:
def available_seatings(shw_id)
total_seats = Seat.where(screen_id: this.id).count
total_bookings = Booking.where(showing_id: shw_id).count
return total_seats - total_bookings
end
Then in the controller
@available_seatings = screen.available_seatings(shw_id)
You can then use the @available_seatings
variable in the view
Upvotes: 0