Skip to content

Commit d0a1017

Browse files
authored
Merge pull request #1131 from MITLibraries/bullet
Detect N+1 errors in development
2 parents d33b44a + 1f2e74a commit d0a1017

File tree

9 files changed

+62
-28
lines changed

9 files changed

+62
-28
lines changed

Gemfile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ group :production do
4141
end
4242

4343
group :development, :test do
44+
gem 'bullet'
4445
gem 'byebug'
4546
gem 'capybara'
4647
gem 'selenium-webdriver'

Gemfile.lock

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,9 @@ GEM
136136
bootsnap (1.16.0)
137137
msgpack (~> 1.2)
138138
builder (3.2.4)
139+
bullet (7.0.7)
140+
activesupport (>= 3.0.0)
141+
uniform_notifier (~> 1.11)
139142
byebug (11.1.3)
140143
cancancan (3.5.0)
141144
capybara (3.38.0)
@@ -385,6 +388,7 @@ GEM
385388
unf_ext
386389
unf_ext (0.0.8.2)
387390
unicode-display_width (2.4.2)
391+
uniform_notifier (1.16.0)
388392
warden (1.2.9)
389393
rack (>= 2.0.9)
390394
web-console (4.2.0)
@@ -410,6 +414,7 @@ DEPENDENCIES
410414
aws-sdk-rails
411415
aws-sdk-s3
412416
bootsnap
417+
bullet
413418
byebug
414419
cancancan
415420
capybara

app/controllers/registrar_controller.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ def show
2727
end
2828

2929
def list_registrar
30-
@registrars = Registrar.all
30+
@registrars = Registrar.with_attached_graduation_list.includes([:user]).all
3131
@jobs = Delayed::Job.where(queue: 'default')
3232
end
3333

app/controllers/report_controller.rb

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -31,12 +31,14 @@ def empty_theses
3131
end
3232

3333
def expired_holds
34-
@list = Hold.active_or_expired.ends_today_or_before.order(:date_end)
34+
@list = Hold.active_or_expired.ends_today_or_before.order(:date_end).includes([:thesis, {
35+
thesis: %i[authors departments]
36+
}])
3537
end
3638

3739
def files
3840
report = Report.new
39-
theses = Thesis.all
41+
theses = Thesis.all.with_attached_files.includes(%i[authors departments])
4042
@terms = report.extract_terms theses
4143
subset = filter_theses_by_term theses
4244
@list = report.list_unattached_files subset
@@ -69,7 +71,7 @@ def student_submitted_theses
6971
@this_term = 'all terms'
7072
@this_term = term.in_time_zone('Eastern Time (US & Canada)').strftime('%b %Y') if term != 'all'
7173
report = Report.new
72-
theses = Thesis.all
74+
theses = Thesis.all.includes([:versions])
7375
@terms = report.extract_terms theses
7476
subset = filter_theses_by_term theses
7577
@list = report.list_student_submitted_metadata subset
@@ -79,7 +81,7 @@ def holds_by_source
7981
term = params[:graduation] ? params[:graduation].to_s : 'all'
8082
@this_term = 'all terms'
8183
@this_term = term.in_time_zone('Eastern Time (US & Canada)').strftime('%b %Y') if term != 'all'
82-
holds = Hold.all.includes(:thesis).includes(:hold_source).includes(thesis: :users).includes(thesis: :authors)
84+
holds = Hold.all.includes([:thesis, :hold_source, { thesis: [:authors, { authors: :user }] }])
8385
@terms = Report.new.extract_terms holds
8486
@hold_sources = HoldSource.pluck(:source).uniq.sort
8587
term_filtered = filter_holds_by_term holds

app/controllers/thesis_controller.rb

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -40,19 +40,20 @@ def deduplicate
4040
# Get array of defined terms where theses have coauthors
4141
@terms = defined_terms Thesis.where.not('coauthors = ?', '')
4242
# Filter relevant theses by selected term from querystring
43-
@thesis = filter_theses_by_term Thesis.where.not('coauthors = ?', '')
43+
@thesis = filter_theses_by_term Thesis.where.not('coauthors = ?', '').includes(%i[departments users])
4444
end
4545

4646
def publication_statuses
4747
@terms = defined_terms Thesis.all
4848
@publication_statuses = Thesis.all.pluck(:publication_status).uniq.sort
4949
# Filter relevant theses by selected term from querystring
50-
term_filtered = filter_theses_by_term Thesis.all.includes(:degrees, :departments, :users)
50+
term_filtered = filter_theses_by_term Thesis.all.includes(:degrees, :departments,
51+
:users).includes(degrees: :degree_type)
5152
@thesis = filter_theses_by_publication_status term_filtered
5253
end
5354

5455
def edit
55-
@thesis = Thesis.find(params[:id])
56+
@thesis = Thesis.includes([degrees: :degree_type]).find(params[:id])
5657
@thesis.association(:advisors).add_to_target(Advisor.new) if @thesis.advisors.count.zero?
5758
end
5859

@@ -79,8 +80,9 @@ def select
7980
# Get array of defined terms where unpublished theses have files attached
8081
@terms = defined_terms Thesis.joins(:files_attachments).group(:id).where('publication_status != ?', 'Published')
8182
# Filter relevant theses by selected term from querystring
82-
@thesis = filter_theses_by_term Thesis.joins(:files_attachments).group(:id).where('publication_status != ?',
83-
'Published')
83+
@thesis = filter_theses_by_term Thesis.joins(:files_attachments).includes(%i[departments users]).group(:id).where(
84+
'publication_status != ?', 'Published'
85+
)
8486
end
8587

8688
def show
@@ -98,7 +100,7 @@ def start
98100
end
99101

100102
def update
101-
@thesis = Thesis.find(params[:id])
103+
@thesis = Thesis.includes([authors: :user]).find(params[:id])
102104
if @thesis.update(thesis_params)
103105
flash[:success] = "#{@thesis.title} has been updated."
104106
ReceiptMailer.receipt_email(@thesis, current_user).deliver_later
@@ -109,7 +111,9 @@ def update
109111
end
110112

111113
def process_theses
112-
@thesis = Thesis.find(params[:id])
114+
@thesis = Thesis.with_attached_files.includes([:departments, {
115+
authors: [:user], degrees: [:degree_type]
116+
}]).find(params[:id])
113117
end
114118

115119
def process_theses_update
@@ -135,7 +139,7 @@ def process_theses_update
135139
end
136140

137141
def proquest_export_preview
138-
@theses = Thesis.ready_for_proquest_export
142+
@theses = Thesis.includes([authors: :user]).ready_for_proquest_export
139143
end
140144

141145
# TODO: we need to generate and send a budget report CSV for partially harvested theses (spec TBD).

app/controllers/transfer_controller.rb

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -51,18 +51,19 @@ def files
5151
end
5252

5353
def select
54-
@transfers = Transfer.all.with_attached_files.includes(:user).includes(:department)
54+
@transfers = Transfer.all.includes(:user).includes(:department)
5555
end
5656

5757
def show
5858
# Load the details of the requested Transfer record
59-
@transfer = Transfer.find(params[:id])
59+
@transfer = Transfer.with_attached_files.find(params[:id])
6060

6161
# Load the Thesis records for the period covered by this Transfer (the
6262
# graduation month/year, and the department)
6363
@theses = Thesis.where('grad_date = ?', @transfer.grad_date)
6464
@theses = @theses.includes(:departments).where('departments.name_dw = ?',
6565
@transfer.department.name_dw).references(:departments)
66+
@theses.with_attached_files
6667
end
6768

6869
private

app/models/report.rb

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -15,11 +15,11 @@ def card_files(collection, term)
1515
'value' => subset.pluck(:id).uniq.count,
1616
'verb' => 'has',
1717
'label' => 'files attached',
18-
'note' => 'Only theses with a status of "Not ready for publication" and "Publication review" will be visible '\
18+
'note' => 'Only theses with a status of "Not ready for publication" and "Publication review" will be visible ' \
1919
'in the processing queue.',
2020
'link' => {
2121
'url' => url_helpers.thesis_select_path(graduation: term),
22-
'text' => "See #{subset.where('publication_status != ?', 'Published').pluck(:id).uniq.count} unpublished "\
22+
'text' => "See #{subset.where('publication_status != ?', 'Published').pluck(:id).uniq.count} unpublished " \
2323
'theses in processing queue'
2424
}
2525
}
@@ -235,8 +235,8 @@ def data_authors_not_graduated
235235
row_data = {}
236236
terms = Thesis.all.pluck(:grad_date).uniq.sort
237237
terms.each do |term|
238-
row_data[term] = Thesis.with_files.where('grad_date = ?', term).includes(authors: :user).includes(:departments)
239-
.reject(&:authors_graduated?).uniq.count
238+
row_data[term] =
239+
Thesis.with_files.where('grad_date = ?', term).includes([:authors]).reject(&:authors_graduated?).uniq.count
240240
end
241241
{
242242
label: 'Authors not graduated',
@@ -373,7 +373,7 @@ def table_copyright(collection)
373373
table_populate_defaults result, Copyright.pluck(:holder)
374374
{
375375
'title' => 'Thesis counts by copyright',
376-
'summary' => 'This table presents a summary of thesis records by their copyright status. The second column '\
376+
'summary' => 'This table presents a summary of thesis records by their copyright status. The second column ' \
377377
'names the copyright holder, while the first column shows how many records have that copyright.',
378378
'column' => 'Copyright holder',
379379
'data' => result
@@ -385,10 +385,10 @@ def table_department(collection)
385385
table_populate_defaults result, Department.pluck(:name_dw)
386386
{
387387
'title' => 'Thesis counts by department',
388-
'summary' => 'This table presents a summary of which departments have how many theses for the selected term. '\
389-
'The second column shows the programs at MIT which grant degrees, while the first column shows how '\
390-
'many theses have come from that program during this period.',
391-
'note' => 'Please note: total theses indicated by this table may be greater than the overall number of theses '\
388+
'summary' => 'This table presents a summary of which departments have how many theses for the selected term. ' \
389+
'The second column shows the programs at MIT which grant degrees, while the first column shows ' \
390+
'how many theses have come from that program during this period.',
391+
'note' => 'Please note: total theses indicated by this table may be greater than the overall number of theses ' \
392392
'because some theses have multiple departments.',
393393
'column' => 'Department',
394394
'data' => result
@@ -407,10 +407,10 @@ def table_license(collection)
407407
table_populate_defaults result, License.pluck(:display_description)
408408
{
409409
'title' => 'Thesis counts by Creative Commons license',
410-
'summary' => 'This table presents a summary of which Creative Commons license has been selected by the author, '\
411-
'for those theses for which the author retains copyright. The second column gives the specific CC '\
410+
'summary' => 'This table presents a summary of which Creative Commons license has been selected by the author, ' \
411+
'for those theses for which the author retains copyright. The second column gives the specific CC ' \
412412
'license selected, while the first column shows how many theses have selected it.',
413-
'note' => 'Please note: theses for which the author does not claim copyright will have "Undefined" in this '\
413+
'note' => 'Please note: theses for which the author does not claim copyright will have "Undefined" in this ' \
414414
'field.',
415415
'column' => 'License',
416416
'data' => result
@@ -438,7 +438,7 @@ def table_status(collection)
438438
table_populate_defaults result, Thesis.publication_statuses
439439
{
440440
'title' => 'Thesis counts by publication status',
441-
'summary' => 'This table presents a summary of thesis records by their publication status. The second column '\
441+
'summary' => 'This table presents a summary of thesis records by their publication status. The second column ' \
442442
'gives the status, while the first column gives how many records have that status.',
443443
'column' => 'Publication status',
444444
'data' => result

config/environments/development.rb

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,15 @@
11
require "active_support/core_ext/integer/time"
22

33
Rails.application.configure do
4+
config.after_initialize do
5+
Bullet.enable = true
6+
Bullet.alert = false
7+
Bullet.bullet_logger = false
8+
Bullet.console = true
9+
Bullet.rails_logger = true
10+
Bullet.add_footer = true
11+
end
12+
413
# Settings specified here will take precedence over those in config/application.rb.
514

615
# In the development environment your application's code is reloaded any time

config/environments/test.rb

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,18 @@
66
# and recreated between test runs. Don't rely on the data there!
77

88
Rails.application.configure do
9+
10+
# Bullet configuration: currently disabled because we can't currently fix all issues
11+
# This configuration block is still useful to allow manually enabling detection locally
12+
# to investigate problems.
13+
config.after_initialize do
14+
Bullet.enable = true
15+
Bullet.bullet_logger = true
16+
Bullet.raise = false # raise an error if n+1 query occurs
17+
Bullet.unused_eager_loading_enable = false
18+
Bullet.counter_cache_enable = false
19+
end
20+
921
# Settings specified here will take precedence over those in config/application.rb.
1022

1123
ENV['SP_PRIVATE_KEY'] = ''

0 commit comments

Comments
 (0)