Skip to content
This repository was archived by the owner on Jul 24, 2020. It is now read-only.

Commit 6c5e673

Browse files
committed
Merge pull request #587 from YaleSTC/587_fix_cart_latency
[Fix Cart Latency] Remove CartReservations!
2 parents 0b270e4 + 339b27e commit 6c5e673

20 files changed

+161
-418
lines changed

app/controllers/application_controller.rb

+9-13
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ def first_time_user
6666
def cart
6767
session[:cart] ||= Cart.new
6868
if session[:cart].reserver_id.nil?
69-
session[:cart].set_reserver_id(current_user.id) if current_user
69+
session[:cart].reserver_id = current_user.id if current_user
7070
end
7171
session[:cart]
7272
end
@@ -110,7 +110,7 @@ def check_view_mode
110110
end
111111

112112
def fix_cart_date
113-
cart.set_start_date(Date.today) if cart.start_date < Date.today
113+
cart.start_date = (Date.today) if cart.start_date < Date.today
114114
end
115115

116116
#-------- end before_filter methods --------#
@@ -120,16 +120,17 @@ def update_cart
120120
cart = session[:cart]
121121
flash.clear
122122
begin
123-
cart.set_start_date(Date.strptime(params[:cart][:start_date_cart],'%m/%d/%Y'))
124-
cart.set_due_date(Date.strptime(params[:cart][:due_date_cart],'%m/%d/%Y'))
125-
cart.set_reserver_id(params[:reserver_id])
126-
rescue ArgumentError => e
127-
cart.set_start_date(Date.today)
123+
cart.start_date = Date.strptime(params[:cart][:start_date_cart],'%m/%d/%Y')
124+
cart.due_date = Date.strptime(params[:cart][:due_date_cart],'%m/%d/%Y')
125+
cart.fix_due_date
126+
cart.reserver_id = params[:reserver_id]
127+
rescue ArgumentError
128+
cart.start_date = Date.today
128129
flash[:error] = "Please enter a valid start or due date."
129130
end
130131

131132
# validate
132-
errors = Reservation.validate_set(cart.reserver, cart.cart_reservations)
133+
errors = Reservation.validate_set(cart.reserver, cart.prepare_all)
133134
# don't over-write flash if invalid date was set above
134135
flash[:error] ||= errors.to_sentence
135136
flash[:notice] = "Cart updated."
@@ -143,13 +144,8 @@ def update_cart
143144
end
144145

145146
def empty_cart
146-
#destroy old cart reservations
147-
current_cart = session[:cart]
148-
CartReservation.where(reserver_id: current_cart.reserver.id).destroy_all
149-
150147
session[:cart] = nil
151148
flash[:notice] = "Cart emptied."
152-
153149
redirect_to root_path
154150
end
155151

app/controllers/catalog_controller.rb

+1-2
Original file line numberDiff line numberDiff line change
@@ -56,8 +56,7 @@ def search
5656
# (or displays the appropriate errors)
5757
def change_cart(action, item)
5858
cart.send(action, item)
59-
60-
errors = Reservation.validate_set(cart.reserver, cart.cart_reservations)
59+
errors = Reservation.validate_set(cart.reserver, cart.prepare_all)
6160
flash[:error] = errors.to_sentence
6261
flash[:notice] = "Cart updated."
6362

app/controllers/reservations_controller.rb

+4-4
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ def new
4949
redirect_to catalog_path
5050
else
5151
# error handling
52-
@errors = Reservation.validate_set(cart.reserver, cart.cart_reservations)
52+
@errors = Reservation.validate_set(cart.reserver, cart.prepare_all)
5353
unless @errors.empty?
5454
if can? :override, :reservation_errors
5555
flash[:error] = 'Are you sure you want to continue? Please review the errors below.'
@@ -68,7 +68,8 @@ def create
6868
#using http://stackoverflow.com/questions/7233859/ruby-on-rails-updating-multiple-models-from-the-one-controller as inspiration
6969
Reservation.transaction do
7070
begin
71-
@errors = Reservation.validate_set(cart.reserver, cart.cart_reservations)
71+
cart_reservations = cart.prepare_all
72+
@errors = Reservation.validate_set(cart.reserver, cart_reservations)
7273
if @errors.empty?
7374
# If the reservation is a finalized reservation, save it as auto-approved ...
7475
params[:reservation][:approval_status] = "auto"
@@ -83,7 +84,7 @@ def create
8384
success_message = "This request has been successfully submitted, and is now subject to approval by an administrator."
8485
end
8586

86-
cart.cart_reservations.each do |cart_res|
87+
cart_reservations.each do |cart_res|
8788
@reservation = Reservation.new(params[:reservation])
8889
@reservation.equipment_model = cart_res.equipment_model
8990
# TODO: is this line needed? it's ugly. we should refactor if it's necessary.
@@ -92,7 +93,6 @@ def create
9293
successful_reservations << @reservation
9394
end
9495

95-
cart.items.each { |item| CartReservation.delete(item) }
9696
session[:cart] = Cart.new
9797

9898
# emails are probably failing---this code was already commented out 2014.06.19, and we don't know why.

app/models/cart.rb

+30-99
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,12 @@
1-
#TODO: change set_reserver_id, set_start_date, and set_due_date to use update_all
2-
31
class Cart
42
include ActiveModel::Validations
5-
extend ActiveModel::Naming
6-
73
validates :reserver_id, :start_date, :due_date, presence: true
84

95
attr_accessor :items, :start_date, :due_date, :reserver_id
10-
attr_reader :errors
116

127
def initialize
138
@errors = ActiveModel::Errors.new(self)
14-
@items = []
9+
@items = Hash.new()
1510
@start_date = Date.today
1611
@due_date = Date.tomorrow
1712
@reserver_id = nil
@@ -21,123 +16,59 @@ def persisted?
2116
false
2217
end
2318

24-
## Functions for error handling
25-
26-
def read_attribute_for_validation(attr)
27-
send(attr)
28-
end
29-
30-
def Cart.human_attribute_name(attr, options = {})
31-
attr
32-
end
33-
34-
def Cart.lookup_ancestors
35-
[self]
36-
end
37-
3819
## Item methods
3920

40-
# Adds CartReservation to database; saves ID into items array
21+
# Adds equipment model id to items hash
4122
def add_item(equipment_model)
42-
current_item = CartReservation.new(start_date: @start_date,
43-
due_date: @due_date, reserver: self.reserver)
44-
current_item.equipment_model = equipment_model
45-
if current_item.save
46-
@items << current_item.id
47-
end
23+
return if equipment_model.nil?
24+
key = equipment_model.id.to_s
25+
self.items[key] = self.items[key] ? self.items[key] + 1 : 1
4826
end
4927

50-
# Removes CartReservation from database and ID from items array
28+
# Remove equipment model id from items hash, or decrement its count
5129
def remove_item(equipment_model)
52-
to_be_deleted = nil
53-
@items.each { |item| to_be_deleted = item if CartReservation.find(item).equipment_model == equipment_model }
54-
CartReservation.delete(to_be_deleted)
55-
@items.delete(to_be_deleted)
56-
end
57-
58-
# Returns CartReservations that correspond to the IDs in the items array
59-
def cart_reservations
60-
CartReservation.where(id: @items)
61-
end
62-
63-
# Returns a hash of the equipment models in the cart with their quantities
64-
def models_with_quantities
65-
models = Hash.new
66-
cart_reservations.each { |res| models[res.equipment_model.id] = res.same_model_count(cart_reservations) }
67-
models
30+
return if equipment_model.nil?
31+
key = equipment_model.id.to_s
32+
self.items[key] = self.items[key] ? self.items[key] - 1 : 0
33+
self.items = self.items.except(key) if self.items[key] <= 0
6834
end
6935

7036
def empty?
7137
@items.empty?
7238
end
7339

74-
## Date methods
75-
76-
# Sets start date and updates all CartReservations to match
77-
def set_start_date(date)
78-
date = date.to_time.in_time_zone
79-
if date >= Date.today
80-
@start_date = date
81-
fix_due_date
82-
cart_reservations.update_all({start_date: @start_date, due_date: @due_date})
83-
end
84-
end
85-
86-
# Sets due date and updates all CartReservations to match
87-
def set_due_date(date)
88-
date = date.to_time.in_time_zone
89-
@due_date = date
90-
fix_due_date
91-
cart_reservations.update_all({start_date: @start_date, due_date: @due_date})
92-
end
93-
94-
# If the dates were illogical, sets due date to day after start date
95-
def fix_due_date
96-
if @start_date.to_time.in_time_zone > @due_date
97-
#TODO: allow admin to set default reservation length and respect that length here
98-
@due_date = @start_date + 1.day
99-
end
40+
# remove all items from cart
41+
def purge_all
42+
@items = Hash.new()
10043
end
10144

102-
#Create an array of all the reservations that should be renewed instead of having a new reservation
103-
def renewable_reservations
104-
user_reservations = reserver.reservations
105-
renewable_reservations = []
106-
@items.each do |item|
107-
cart_item_count = item.quantity #renew up to this many of the item
108-
matching_reservations = user_reservations.each do |res|
109-
# the end date should be the same as the start date
110-
# the reservation should be renewable
111-
# also the user should only renew as many reservations as they have in their cart
112-
if (res.due_date.to_date == @start_date &&
113-
res.equipment_model_id == item.equipment_model_id &&
114-
cart_item_count > 0 &&
115-
res.is_eligible_for_renew?)
116-
renewable_reservations << res
117-
cart_item_count-= 1
118-
end
45+
# return array of reservations crafted from the cart contents
46+
def prepare_all
47+
reservations = []
48+
@items.each do |id, quantity|
49+
quantity.times do
50+
reservations << Reservation.new(reserver: self.reserver,
51+
start_date: @start_date,
52+
due_date: @due_date,
53+
equipment_model_id: id)
11954
end
12055
end
121-
return renewable_reservations
56+
reservations
12257
end
12358

124-
12559
# Returns the cart's duration
12660
def duration #in days
12761
@due_date.to_date - @start_date.to_date + 1
12862
end
12963

130-
## Reserver methods
131-
132-
#TODO: should only have to set reserver OR reserver_id
133-
# Sets reserver id and updates the CartReservations to match
134-
def set_reserver_id(user_id)
135-
@reserver_id = user_id
136-
cart_reservations.update_all(reserver_id: @reserver_id)
137-
end
138-
13964
# Returns the reserver
14065
def reserver
141-
reserver = User.find(@reserver_id)
66+
User.find(@reserver_id)
67+
end
68+
69+
def fix_due_date
70+
if @start_date > @due_date
71+
@due_date = @start_date + 1.day
72+
end
14273
end
14374
end

app/models/cart_reservation.rb

-6
This file was deleted.

app/models/reservation.rb

+2-3
Original file line numberDiff line numberDiff line change
@@ -105,11 +105,11 @@ def self.validate_set(user, res_array = [])
105105
errors << user.name + " has overdue reservations that prevent new ones from being created. " unless user.reservations.overdue.empty?
106106

107107
res_array.each do |res|
108-
errors << "Reservation cannot be made in the past. " unless res.not_in_past? if self.class == CartReservation
108+
errors << "Reservation cannot be made in the past. " unless res.not_in_past?
109109
errors << "Reservation start date must be before due date. " unless res.start_date_before_due_date?
110110
errors << "Reservation must be for a piece of equipment. " unless res.not_empty?
111111
errors << "#{res.equipment_object.name} must be of type #{res.equipment_model.name}. " unless res.matched_object_and_model?
112-
errors << "#{res.equipment_model.name} should be renewed instead of re-checked out. " unless res.not_renewable? if self.class == CartReservation
112+
errors << "#{res.equipment_model.name} should be renewed instead of re-checked out. " unless res.not_renewable?
113113
errors << "#{res.equipment_model.name} cannot be reserved for more than #{res.equipment_model.category.maximum_checkout_length.to_s} days at a time. " unless res.duration_allowed?
114114
errors << "#{res.equipment_model.name} is not available for the full time period requested. " unless res.available?(res_array)
115115
errors << "A reservation cannot start on #{res.start_date.strftime('%m/%d')} because equipment cannot be picked up on that date. " unless res.start_date_is_not_blackout?
@@ -162,7 +162,6 @@ def is_eligible_for_renew?
162162

163163
max_renewal_days = self.equipment_model.maximum_renewal_days_before_due
164164
max_renewal_days = Float::INFINITY if max_renewal_days == 'unrestricted'
165-
166165
return ((self.due_date.to_date - Date.today).to_i < max_renewal_days ) &&
167166
(self.times_renewed < max_renewal_times)
168167
end

app/models/reservation_validations.rb

+1-2
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,6 @@ def matched_object_and_model?
5858
# Checks that the reservation is not renewable
5959
#TODO: allow admin override
6060
def not_renewable?
61-
return true unless self.class == CartReservation || self.status == "reserved"
6261
reserver.reservations.each do |res|
6362
if res.equipment_model == self.equipment_model && res.due_date.to_date == self.start_date.to_date && res.is_eligible_for_renew?
6463
errors.add(:base, res.equipment_model.name + " should be renewed instead of re-checked out.\n")
@@ -184,7 +183,7 @@ def get_overlapping_reservations(reservations)
184183
#include all reservations made by user
185184
reservations.concat(reserver.reservations)
186185
reservations.uniq!
187-
reservations.select{ |res| res.overlaps_with?(self) && (res.class == CartReservation || res.checked_in == nil) }
186+
reservations.select{ |res| res.overlaps_with?(self) && (res.checked_in == nil) }
188187
end
189188

190189

Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
<div id="list_items_in_cart">
2-
<% if cart.cart_reservations.size == 0 %>
2+
<% if cart.items.empty? %>
33
<span id="cart_is_empty">(empty)</span>
44
<% else %>
55
<table id="table_list_items" class="table table-bordered table-striped table-condensed">
6-
<% cart.models_with_quantities.each_pair do |model_id, quantity| %>
6+
<% cart.items.each do |model_id, quantity| %>
77
<tr>
88
<td colspan="2"><%= quantity %> x
99
<div id="remove_button"><%= link_to "Remove", remove_from_cart_path(EquipmentModel.find(model_id)),
@@ -14,4 +14,4 @@
1414
<% end %>
1515
</table>
1616
<% end %>
17-
</div>
17+
</div>

app/views/reservations/_new_request.html.erb

+1-1
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@
3030
</p>
3131
<p>
3232
<ul class="rounded-list">
33-
<% cart.models_with_quantities.each_pair do |model_id, quantity| %>
33+
<% cart.items.each do |model_id, quantity| %>
3434
<li data-value="<%= quantity %>"><%= link_to EquipmentModel.find(model_id).name, EquipmentModel.find(model_id) %></li>
3535
<% end %>
3636
</ul>

app/views/reservations/_new_reservation.html.erb

+1-1
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@
3030
</p>
3131
<p>
3232
<ul class="rounded-list">
33-
<% cart.models_with_quantities.each_pair do |model_id, quantity| %>
33+
<% cart.items.each do |model_id, quantity| %>
3434
<li data-value="<%= quantity %>"><%= link_to EquipmentModel.find(model_id).name, EquipmentModel.find(model_id) %></li>
3535
<% end %>
3636
</ul>

app/views/users/create_success.js.erb

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
<% if params[:from_cart] == "true" %>
2-
<% session[:cart].set_reserver_id(@user.id) %>
2+
<% session[:cart].reserver_id = @user.id %>
33
$('#userModal').modal('hide');
44
$(window.location.reload());
55
<% elsif params[:action] == "update" %>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
class RemoveCartReservations < ActiveRecord::Migration
2+
def up
3+
drop_table :cart_reservations
4+
end
5+
6+
def down
7+
raise ActiveRecord::IrreversibleMigration
8+
end
9+
end

0 commit comments

Comments
 (0)