diff --git a/Gemfile b/Gemfile index 3129d3104..e58d067da 100644 --- a/Gemfile +++ b/Gemfile @@ -37,6 +37,7 @@ gem "flamegraph" gem "memory_profiler" gem "rack-mini-profiler" gem "stackprof" +gem "prosopite" gem "oauth" # for linking accounts gem "mail" # for parsing incoming mail diff --git a/Gemfile.lock b/Gemfile.lock index cf9f04ee7..ca8011273 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -203,6 +203,7 @@ GEM hashery (~> 2.0) ruby-rc4 ttfunk + prosopite (1.4.2) psych (5.1.2) stringio public_suffix (5.0.4) @@ -416,6 +417,7 @@ DEPENDENCIES oauth parslet pdf-reader + prosopite puma rack-attack rack-mini-profiler diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index f98157cb8..a7aff0a8d 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -9,6 +9,7 @@ class ApplicationController < ActionController::Base before_action :mini_profiler before_action :prepare_exception_notifier before_action :set_traffic_style + around_action :n_plus_one_detection # 2023-10-07 one user in one of their browser envs is getting a CSRF failure, I'm reverting # because I'll be AFK a while. @@ -188,4 +189,11 @@ def tags_filtered_by_cookie tag: cookies[TAG_FILTER_COOKIE].to_s.split(",") ) end + + def n_plus_one_detection + Prosopite.scan + yield + ensure + Prosopite.finish + end end diff --git a/app/models/story.rb b/app/models/story.rb index 8762baf87..a7cebf7b5 100644 --- a/app/models/story.rb +++ b/app/models/story.rb @@ -415,6 +415,8 @@ def check_tags return end + # ignored to manage tags_a for nicer UI and because the n is typically 2-5 tags + Prosopite.pause taggings.each do |t| if !t.tag.can_be_applied_by?(u) && t.tag.privileged? raise "#{u.username} does not have permission to use privileged tag #{t.tag.tag}" @@ -429,6 +431,8 @@ def check_tags end end + Prosopite.resume + if taggings.reject { |t| t.marked_for_destruction? || t.tag.is_media? }.empty? errors.add(:base, "Must have at least one non-media (PDF, video) " \ "tag. If no tags apply to your content, it probably doesn't " \ diff --git a/config/initializers/prosopite.rb b/config/initializers/prosopite.rb new file mode 100644 index 000000000..c43ccbbf4 --- /dev/null +++ b/config/initializers/prosopite.rb @@ -0,0 +1,7 @@ +# typed: false + +if Rails.env.production? + Prosopite.custom_logger = Logger.new("/srv/lobste.rs/log/n_plus_one_detection.log") +else + Prosopite.raise = true +end