Skip to content

Commit 9d09afe

Browse files
Refactor Requests controller (#5563)
* Refactor requests controller Moving view instances to a View Object. * Remove unnecessary donations eager loading product_drive_participant This was raising a bullet error: GET /donations AVOID eager loading detected Donation => [:product_drive_participant] Remove from your query: .includes([:product_drive_participant]) * Refactor show action Moving view instances to a View Object to keep the controller clean. Add coverage for business logic * rename requests_info to avoid clashing with show request_info add coverage for Request model view * Create factories only when necessary * Rename filter variables with the view object instance from the controller * linter * Add full coverage to View::RequestInfo * Add full coverage to View::Requests * Memoize RequestInfo to avoid unnecessary DB calls To prevent performance degradation, `View::RequestInfo` memoizes expensive operations, especially DB calls. To make that happen, the object needs to be a regular class and not a Data object, which is immutable. * Memoize View::Requests to avoid unnecessary DB calls To prevent performance degradation, `View::Requests` memoizes expensive operations, especially DB calls. To make that happen, the object needs to be a regular class and not a Data object, which is immutable. * Trigger Build
1 parent 96b808b commit 9d09afe

11 files changed

Lines changed: 432 additions & 65 deletions

File tree

app/controllers/requests_controller.rb

Lines changed: 3 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -3,39 +3,16 @@ class RequestsController < ApplicationController
33
def index
44
setup_date_range_picker
55

6-
@requests = current_organization
7-
.ordered_requests
8-
.undiscarded
9-
.during(helpers.selected_range)
10-
.class_filter(filter_params)
11-
@unfulfilled_requests_count = current_organization.requests.where(status: [:pending, :started]).during(helpers.selected_range).class_filter(filter_params).count
12-
@paginated_requests = @requests.includes(:partner).page(params[:page])
13-
@calculate_product_totals = RequestsTotalItemsService.new(requests: @requests).calculate
14-
@items = current_organization.items.alphabetized.select(:id, :name)
15-
@partners = current_organization.partners.alphabetized.select(:id, :name, :status)
16-
@statuses = Request.statuses.transform_keys(&:humanize)
17-
@partner_users = User.where(id: @paginated_requests.map(&:partner_user_id)).select(:id, :name, :email)
18-
@request_types = Request.request_types.transform_keys(&:humanize)
19-
@selected_request_type = filter_params[:by_request_type]
20-
@selected_request_item = filter_params[:by_request_item_id]
21-
@selected_partner = filter_params[:by_partner]
22-
@selected_status = filter_params[:by_status]
6+
@requests_info = View::Requests.new(params: params, organization: current_organization, helpers: helpers)
237

248
respond_to do |format|
259
format.html
26-
format.csv { send_data Exports::ExportRequestService.new(@requests).generate_csv, filename: "Requests-#{Time.zone.today}.csv" }
10+
format.csv { send_data Exports::ExportRequestService.new(@requests_info.requests).generate_csv, filename: "Requests-#{Time.zone.today}.csv" }
2711
end
2812
end
2913

3014
def show
31-
@request = current_organization.requests.find(params[:id])
32-
@item_requests = @request.item_requests.includes(:item)
33-
34-
@inventory = View::Inventory.new(@request.organization_id)
35-
@default_storage_location = @request.partner.default_storage_location_id || @request.organization.default_storage_location
36-
@location = StorageLocation.find_by(id: @default_storage_location)
37-
38-
@custom_units = Flipper.enabled?(:enable_packs) && @request.item_requests.any? { |item| item.request_unit }
15+
@request_info = View::RequestInfo.new(params:, organization: current_organization)
3916
end
4017

4118
# Clicking the "New Distribution" button will set the the request to started

app/models/view/donations.rb

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,6 @@ def from_params(params:, organization:, helpers:)
3131
.includes(:storage_location,
3232
:donation_site,
3333
:product_drive,
34-
:product_drive_participant,
3534
:manufacturer,
3635
line_items: [:item])
3736
.order(created_at: :desc)

app/models/view/request_info.rb

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
module View
2+
class RequestInfo
3+
attr_reader :request
4+
5+
def initialize(params:, organization:)
6+
@request = organization.requests.find(params[:id])
7+
end
8+
9+
def item_requests
10+
@item_requests ||= @request.item_requests.includes(:item)
11+
end
12+
13+
def inventory
14+
@inventory ||= View::Inventory.new(@request.organization_id)
15+
end
16+
17+
def default_storage_location
18+
return @default_storage_location if defined?(@default_storage_location)
19+
20+
@efault_storage_location ||= @request.partner.default_storage_location_id || @request.organization.default_storage_location
21+
end
22+
23+
def location
24+
return @location if defined?(@location)
25+
26+
@location ||= StorageLocation.find_by(id: default_storage_location)
27+
end
28+
29+
def custom_units
30+
Flipper.enabled?(:enable_packs) && request.item_requests.any? { |item| item.request_unit }
31+
end
32+
end
33+
end

app/models/view/requests.rb

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
module View
2+
class Requests
3+
include DateRangeHelper
4+
5+
attr_reader :filters, :helpers, :organization, :paginated_requests, :params, :requests
6+
7+
def initialize(params:, organization:, helpers:)
8+
@params = params
9+
@organization = organization
10+
@filters = filter_params(params)
11+
@helpers = helpers
12+
13+
@requests = organization
14+
.ordered_requests
15+
.undiscarded
16+
.during(helpers.selected_range)
17+
.class_filter(filters)
18+
19+
@paginated_requests = requests.includes(:partner).page(params[:page])
20+
end
21+
22+
def filter_params(params = {})
23+
if params.key?(:filters)
24+
params.require(:filters).permit(:by_request_item_id, :by_partner, :by_status, :by_request_type)
25+
else
26+
{}
27+
end
28+
end
29+
30+
def unfulfilled_requests_count
31+
@unfulfilled_requests_count ||= organization
32+
.requests
33+
.where(status: [:pending, :started])
34+
.during(helpers.selected_range)
35+
.class_filter(filters)
36+
.count
37+
end
38+
39+
def calculate_product_totals
40+
@calculate_product_totals ||= RequestsTotalItemsService.new(requests: requests).calculate
41+
end
42+
43+
def items
44+
@items ||= organization.items.alphabetized.select(:id, :name)
45+
end
46+
47+
def partners
48+
@partners ||= organization.partners.alphabetized.select(:id, :name, :status)
49+
end
50+
51+
def statuses
52+
@statuses ||= Request.statuses.transform_keys(&:humanize)
53+
end
54+
55+
def partner_users
56+
@partner_users ||= User.where(id: paginated_requests.map(&:partner_user_id)).select(:id, :name, :email)
57+
end
58+
59+
def request_types
60+
@request_types ||= Request.request_types.transform_keys(&:humanize)
61+
end
62+
63+
def selected_request_type
64+
filters[:by_request_type]
65+
end
66+
67+
def selected_request_item
68+
filters[:by_request_item_id]
69+
end
70+
71+
def selected_partner
72+
filters[:by_partner]
73+
end
74+
75+
def selected_status
76+
filters[:by_status]
77+
end
78+
end
79+
end

app/views/requests/_calculate_product_totals.html.erb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
</tr>
1717
</thead>
1818
<tbody>
19-
<% @calculate_product_totals.sort_by { |name, quantity| name.downcase }.each do |name, quantity| %>
19+
<% @requests_info.calculate_product_totals.sort_by { |name, quantity| name.downcase }.each do |name, quantity| %>
2020
<tr>
2121
<td><%= name %></td>
2222
<td><%= quantity %></td>

app/views/requests/_new.html.erb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
<div class="modal-body p-4">
1111
<%= form_with(url: new_partners_request_path, method: :get) do |form| %>
1212
<div class="form-group">
13-
<%= form.collection_select(:partner_id, @partners.active, :id, :name, {include_blank: "Select a partner", required: true}, {class: "form-control mb-2"} ) %>
13+
<%= form.collection_select(:partner_id, @requests_info.partners.active, :id, :name, {include_blank: "Select a partner", required: true}, {class: "form-control mb-2"} ) %>
1414
</div>
1515
<%= submit_button({text: "Next", icon: nil, name: ""}) %>
1616
<% end %>

app/views/requests/_request_row.html.erb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
<td class="date"><%= request_row.created_at.strftime("%m/%d/%Y") %></td>
33
<td><%= request_row.partner.name %> </td>
44
<td>
5-
<% partner_user = @partner_users.find { |pu| pu.id == request_row.partner_user_id } %>
5+
<% partner_user = @requests_info.partner_users.find { |pu| pu.id == request_row.partner_user_id } %>
66
<%= "#{partner_user&.formatted_email}" %>
77
</td>
88
<td class="<%= quota_column_class(request_row.total_items, request_row.partner) %> text-right">

app/views/requests/index.html.erb

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -37,21 +37,21 @@
3737
<div class="card-body">
3838
<%= form_tag(requests_path, method: :get) do |f| %>
3939
<div class="row">
40-
<% if @items.present? %>
40+
<% if @requests_info.items.present? %>
4141
<div class="form-group col-lg-3 col-md-3 col-sm-6 col-xs-12">
42-
<%= filter_select(label: "Filter by item", scope: :by_request_item_id, collection: @items, selected: @selected_request_item) %>
42+
<%= filter_select(label: "Filter by item", scope: :by_request_item_id, collection: @requests_info.items, selected: @requests_info.selected_request_item) %>
4343
</div>
4444
<% end %>
45-
<% if @partners.present? %>
45+
<% if @requests_info.partners.present? %>
4646
<div class="form-group col-lg-3 col-md-3 col-sm-6 col-xs-12">
47-
<%= filter_select(scope: :by_partner, collection: @partners, selected: @selected_partner) %>
47+
<%= filter_select(scope: :by_partner, collection: @requests_info.partners, selected: @requests_info.selected_partner) %>
4848
</div>
4949
<% end %>
5050
<div class="form-group col-lg-3 col-md-3 col-sm-6 col-xs-12">
51-
<%= filter_select(scope: :by_request_type, collection: @request_types, key: :last, value: :first, selected: @selected_request_type) %>
51+
<%= filter_select(scope: :by_request_type, collection: @requests_info.request_types, key: :last, value: :first, selected: @requests_info.selected_request_type) %>
5252
</div>
5353
<div class="form-group col-lg-3 col-md-3 col-sm-6 col-xs-12">
54-
<%= filter_select(scope: :by_status, collection: @statuses, key: :last, value: :first, selected: @selected_status) %>
54+
<%= filter_select(scope: :by_status, collection: @requests_info.statuses, key: :last, value: :first, selected: @requests_info.selected_status) %>
5555
</div>
5656
<div class="form-group col-lg-3 col-md-4 col-sm-6 col-xs-12">
5757
<%= label_tag "Date Range" %>
@@ -67,13 +67,13 @@
6767
<%= modal_button_to("#calculateTotals", {text: "Calculate Product Totals", icon: nil, size: "md", type: "success"}) %>
6868
</div>
6969
<div class="d-flex flex-wrap gap-2">
70-
<% if @unfulfilled_requests_count > 0 %>
70+
<% if @requests_info.unfulfilled_requests_count > 0 %>
7171
<%= print_button_to(
7272
print_unfulfilled_requests_path(format: :pdf, filters: filter_params.merge(date_range: date_range_params)),
73-
text: "Print Unfulfilled Picklists (#{@unfulfilled_requests_count})",
73+
text: "Print Unfulfilled Picklists (#{@requests_info.unfulfilled_requests_count})",
7474
size: "md") %>
7575
<% end %>
76-
<%= download_button_to(requests_path(format: :csv, filters: filter_params.merge(date_range: date_range_params)), {text: "Export Requests", size: "md"}) if @requests.any? %>
76+
<%= download_button_to(requests_path(format: :csv, filters: filter_params.merge(date_range: date_range_params)), {text: "Export Requests", size: "md"}) if @requests_info.requests.any? %>
7777
<%= modal_button_to("#newRequest", text: "New Quantity Request", icon: "plus", type: "success") if current_user.has_role?(Role::ORG_ADMIN, current_organization) %>
7878
</div>
7979
</div>
@@ -112,13 +112,13 @@
112112
</tr>
113113
</thead>
114114
<tbody>
115-
<%= render partial: "request_row", collection: @paginated_requests %>
115+
<%= render partial: "request_row", collection: @requests_info.paginated_requests %>
116116
</tbody>
117117
</table>
118118
</div>
119119
<!-- /.card-body -->
120120
<div class="card-footer clearfix">
121-
<%= paginate @paginated_requests %>
121+
<%= paginate @requests_info.paginated_requests %>
122122
</div>
123123
<!-- /.card-footer-->
124124
</div>

app/views/requests/show.html.erb

Lines changed: 24 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,10 @@
22
<div class="container-fluid">
33
<div class="row mb-2">
44
<div class="col-sm-6">
5-
<% content_for :title, "Requests - #{@request.id} - #{current_organization.name}" %>
5+
<% content_for :title, "Requests - #{@request_info.request.id} - #{current_organization.name}" %>
66
<h1>
77
Request
8-
<small>from <%= @request.partner.name %></small>
8+
<small>from <%= @request_info.request.partner.name %></small>
99
</h1>
1010
</div>
1111
<div class="col-sm-6">
@@ -15,8 +15,8 @@
1515
<% end %>
1616
</li>
1717
<li class="breadcrumb-item"><%= link_to "Requests", requests_path %></li>
18-
<li class="breadcrumb-item"><a href="#"> Request from <%= @request.partner.name %>
19-
at <%= @request.created_at.to_fs(:distribution_date) %></a></li>
18+
<li class="breadcrumb-item"><a href="#"> Request from <%= @request_info.request.partner.name %>
19+
at <%= @request_info.request.created_at.to_fs(:distribution_date) %></a></li>
2020
</ol>
2121
</div>
2222
</div>
@@ -29,7 +29,7 @@
2929
<div class="col-12">
3030
<div class="card">
3131
<div class="card-header">
32-
<h3 class="card-title">This request was sent on <%= @request.created_at.to_fs(:distribution_date) %></h3>
32+
<h3 class="card-title">This request was sent on <%= @request_info.request.created_at.to_fs(:distribution_date) %></h3>
3333
</div>
3434
<div class="card-body p-0">
3535
<table class="table">
@@ -44,11 +44,11 @@
4444
</thead>
4545
<tbody>
4646
<tr>
47-
<td><%= @request.partner.name %></td>
48-
<td><%= @request.partner_user&.formatted_email %></td>
49-
<td><%= @request.request_type&.humanize %></td>
50-
<td><%= render partial: "status", locals: {status: @request.status} %></td>
51-
<td><%= @request.comments || 'None' %></td>
47+
<td><%= @request_info.request.partner.name %></td>
48+
<td><%= @request_info.request.partner_user&.formatted_email %></td>
49+
<td><%= @request_info.request.request_type&.humanize %></td>
50+
<td><%= render partial: "status", locals: {status: @request_info.request.status} %></td>
51+
<td><%= @request_info.request.comments || 'None' %></td>
5252
</tr>
5353
</table>
5454
</div>
@@ -67,48 +67,48 @@
6767
<tr>
6868
<th>Item</th>
6969
<th>Quantity</th>
70-
<% if @custom_units %>
70+
<% if @request_info.custom_units %>
7171
<th>Units (if applicable)</th>
7272
<% end %>
73-
<% if @default_storage_location %>
73+
<% if @request_info.default_storage_location %>
7474
<th>Default storage location inventory</th>
7575
<% end %>
7676
<th>Total Inventory</th>
7777
</tr>
7878
</thead>
7979
<tbody>
80-
<% @item_requests.each do |item_request| %>
80+
<% @request_info.item_requests.each do |item_request| %>
8181
<tr>
8282
<td><%= item_request.item_name %></td>
8383
<td><%= item_request.quantity %></td>
84-
<% if @custom_units %>
84+
<% if @request_info.custom_units %>
8585
<td><%= item_request.request_unit&.pluralize(item_request.quantity.to_i) %></td>
8686
<% end %>
87-
<% if @default_storage_location %>
88-
<% on_hand_for_location = @inventory.quantity_for(storage_location: @location&.id, item_id: item_request.item_id) %>
87+
<% if @request_info.default_storage_location %>
88+
<% on_hand_for_location = @request_info.inventory.quantity_for(storage_location: @request_info.location&.id, item_id: item_request.item_id) %>
8989
<td><%= on_hand_for_location&.positive? ? on_hand_for_location : 'N/A' %></td>
9090
<% end %>
91-
<% on_hand = @inventory.quantity_for(item_id: item_request.item_id) %>
91+
<% on_hand = @request_info.inventory.quantity_for(item_id: item_request.item_id) %>
9292
<td><%= on_hand || 0 %></td>
9393
</tr>
9494
<% end %>
9595
<tr>
9696
<td>Total (Quota)</td>
9797
<td>
98-
<%= @request.total_items %>
99-
<%= quota_display(@request.partner) %>
98+
<%= @request_info.request.total_items %>
99+
<%= quota_display(@request_info.request.partner) %>
100100
</td>
101101
<td />
102102
</tr>
103103
</tbody>
104104
</table>
105105
</div>
106106
<div class="card-footer flex flex-row space-x-2">
107-
<%= submit_button_to start_request_path(@request), {text: "Fulfill request", size: "md"} unless @request.distribution %>
108-
<%= view_button_to(distribution_path(@request.distribution), {text: "View Associated Distribution", size: "md"}) if @request.distribution %>
109-
<%= print_button_to print_picklist_request_path(@request), { format: :pdf, text: "Print", size: "md" } %>
110-
<% unless @request.status_fulfilled? %>
111-
<%= button_to 'Cancel', new_request_cancelation_path(request_id: @request.id),
107+
<%= submit_button_to start_request_path(@request_info.request), {text: "Fulfill request", size: "md"} unless @request_info.request.distribution %>
108+
<%= view_button_to(distribution_path(@request_info.request.distribution), {text: "View Associated Distribution", size: "md"}) if @request_info.request.distribution %>
109+
<%= print_button_to print_picklist_request_path(@request_info.request), { format: :pdf, text: "Print", size: "md" } %>
110+
<% unless @request_info.request.status_fulfilled? %>
111+
<%= button_to 'Cancel', new_request_cancelation_path(request_id: @request_info.request.id),
112112
method: :get, data: { disable_with: "Please wait..." }, form_class: 'd-inline', class: 'btn btn-danger btn-md' %>
113113
<% end %>
114114
</div>

0 commit comments

Comments
 (0)