diff --git a/Gemfile b/Gemfile index 106a68b..eafe4ee 100644 --- a/Gemfile +++ b/Gemfile @@ -1,7 +1,7 @@ source "https://rubygems.org" # Bundle edge Rails instead: gem "rails", github: "rails/rails", branch: "main" -gem "rails", "~> 8.0.0" +gem "rails", "~> 8.1.1" # The modern asset pipeline for Rails [https://github.com/rails/propshaft] gem "propshaft" # Use the Puma web server [https://github.com/puma/puma] diff --git a/Gemfile.lock b/Gemfile.lock index bbe3a8e..010c04f 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -7,29 +7,31 @@ GIT GEM remote: https://rubygems.org/ specs: - actioncable (8.0.4) - actionpack (= 8.0.4) - activesupport (= 8.0.4) + action_text-trix (2.1.15) + railties + actioncable (8.1.1) + actionpack (= 8.1.1) + activesupport (= 8.1.1) nio4r (~> 2.0) websocket-driver (>= 0.6.1) zeitwerk (~> 2.6) - actionmailbox (8.0.4) - actionpack (= 8.0.4) - activejob (= 8.0.4) - activerecord (= 8.0.4) - activestorage (= 8.0.4) - activesupport (= 8.0.4) + actionmailbox (8.1.1) + actionpack (= 8.1.1) + activejob (= 8.1.1) + activerecord (= 8.1.1) + activestorage (= 8.1.1) + activesupport (= 8.1.1) mail (>= 2.8.0) - actionmailer (8.0.4) - actionpack (= 8.0.4) - actionview (= 8.0.4) - activejob (= 8.0.4) - activesupport (= 8.0.4) + actionmailer (8.1.1) + actionpack (= 8.1.1) + actionview (= 8.1.1) + activejob (= 8.1.1) + activesupport (= 8.1.1) mail (>= 2.8.0) rails-dom-testing (~> 2.2) - actionpack (8.0.4) - actionview (= 8.0.4) - activesupport (= 8.0.4) + actionpack (8.1.1) + actionview (= 8.1.1) + activesupport (= 8.1.1) nokogiri (>= 1.8.5) rack (>= 2.2.4) rack-session (>= 1.0.1) @@ -37,42 +39,43 @@ GEM rails-dom-testing (~> 2.2) rails-html-sanitizer (~> 1.6) useragent (~> 0.16) - actiontext (8.0.4) - actionpack (= 8.0.4) - activerecord (= 8.0.4) - activestorage (= 8.0.4) - activesupport (= 8.0.4) + actiontext (8.1.1) + action_text-trix (~> 2.1.15) + actionpack (= 8.1.1) + activerecord (= 8.1.1) + activestorage (= 8.1.1) + activesupport (= 8.1.1) globalid (>= 0.6.0) nokogiri (>= 1.8.5) - actionview (8.0.4) - activesupport (= 8.0.4) + actionview (8.1.1) + activesupport (= 8.1.1) builder (~> 3.1) erubi (~> 1.11) rails-dom-testing (~> 2.2) rails-html-sanitizer (~> 1.6) - activejob (8.0.4) - activesupport (= 8.0.4) + activejob (8.1.1) + activesupport (= 8.1.1) globalid (>= 0.3.6) - activemodel (8.0.4) - activesupport (= 8.0.4) - activerecord (8.0.4) - activemodel (= 8.0.4) - activesupport (= 8.0.4) + activemodel (8.1.1) + activesupport (= 8.1.1) + activerecord (8.1.1) + activemodel (= 8.1.1) + activesupport (= 8.1.1) timeout (>= 0.4.0) - activestorage (8.0.4) - actionpack (= 8.0.4) - activejob (= 8.0.4) - activerecord (= 8.0.4) - activesupport (= 8.0.4) + activestorage (8.1.1) + actionpack (= 8.1.1) + activejob (= 8.1.1) + activerecord (= 8.1.1) + activesupport (= 8.1.1) marcel (~> 1.0) - activesupport (8.0.4) + activesupport (8.1.1) base64 - benchmark (>= 0.3) bigdecimal concurrent-ruby (~> 1.0, >= 1.3.1) connection_pool (>= 2.2.5) drb i18n (>= 1.6, < 2) + json logger (>= 1.4.2) minitest (>= 5.1) securerandom (>= 0.3) @@ -89,14 +92,13 @@ GEM bcrypt_pbkdf (1.1.1) bcrypt_pbkdf (1.1.1-arm64-darwin) bcrypt_pbkdf (1.1.1-x86_64-darwin) - benchmark (0.5.0) bigdecimal (3.3.1) bindex (0.8.1) bootsnap (1.18.6) msgpack (~> 1.2) bootstrap (5.3.5) popper_js (>= 2.11.8, < 3) - brakeman (7.1.0) + brakeman (7.1.1) racc builder (3.3.0) capybara (3.40.0) @@ -175,7 +177,7 @@ GEM activesupport (>= 6.0.0) railties (>= 6.0.0) io-console (0.8.1) - irb (1.15.2) + irb (1.15.3) pp (>= 0.6.0) rdoc (>= 4.0.0) reline (>= 0.4.2) @@ -299,7 +301,7 @@ GEM activesupport (>= 3.0.0) raabro (1.4.0) racc (1.8.1) - rack (3.2.3) + rack (3.2.4) rack-session (2.1.1) base64 (>= 0.1.0) rack (>= 3.0.0) @@ -307,20 +309,20 @@ GEM rack (>= 1.3) rackup (2.2.1) rack (>= 3) - rails (8.0.4) - actioncable (= 8.0.4) - actionmailbox (= 8.0.4) - actionmailer (= 8.0.4) - actionpack (= 8.0.4) - actiontext (= 8.0.4) - actionview (= 8.0.4) - activejob (= 8.0.4) - activemodel (= 8.0.4) - activerecord (= 8.0.4) - activestorage (= 8.0.4) - activesupport (= 8.0.4) + rails (8.1.1) + actioncable (= 8.1.1) + actionmailbox (= 8.1.1) + actionmailer (= 8.1.1) + actionpack (= 8.1.1) + actiontext (= 8.1.1) + actionview (= 8.1.1) + activejob (= 8.1.1) + activemodel (= 8.1.1) + activerecord (= 8.1.1) + activestorage (= 8.1.1) + activesupport (= 8.1.1) bundler (>= 1.15.0) - railties (= 8.0.4) + railties (= 8.1.1) rails-dom-testing (2.3.0) activesupport (>= 5.0.0) minitest @@ -328,9 +330,9 @@ GEM rails-html-sanitizer (1.6.2) loofah (~> 2.21) nokogiri (>= 1.15.7, != 1.16.7, != 1.16.6, != 1.16.5, != 1.16.4, != 1.16.3, != 1.16.2, != 1.16.1, != 1.16.0.rc1, != 1.16.0) - railties (8.0.4) - actionpack (= 8.0.4) - activesupport (= 8.0.4) + railties (8.1.1) + actionpack (= 8.1.1) + activesupport (= 8.1.1) irb (~> 1.13) rackup (>= 1.0.0) rake (>= 12.2) @@ -343,7 +345,7 @@ GEM activerecord (>= 7.2) activesupport (>= 7.2) i18n - rdoc (6.15.0) + rdoc (6.15.1) erb psych (>= 4.0.0) tsort @@ -381,25 +383,25 @@ GEM rubocop-rails (>= 2.30) ruby-progressbar (1.13.0) ruby_http_client (3.5.5) - rubyzip (3.2.1) - sass-embedded (1.93.2) + rubyzip (3.2.2) + sass-embedded (1.93.3) google-protobuf (~> 4.31) rake (>= 13) - sass-embedded (1.93.2-aarch64-linux-gnu) + sass-embedded (1.93.3-aarch64-linux-gnu) google-protobuf (~> 4.31) - sass-embedded (1.93.2-aarch64-linux-musl) + sass-embedded (1.93.3-aarch64-linux-musl) google-protobuf (~> 4.31) - sass-embedded (1.93.2-arm-linux-gnueabihf) + sass-embedded (1.93.3-arm-linux-gnueabihf) google-protobuf (~> 4.31) - sass-embedded (1.93.2-arm-linux-musleabihf) + sass-embedded (1.93.3-arm-linux-musleabihf) google-protobuf (~> 4.31) - sass-embedded (1.93.2-arm64-darwin) + sass-embedded (1.93.3-arm64-darwin) google-protobuf (~> 4.31) - sass-embedded (1.93.2-x86_64-darwin) + sass-embedded (1.93.3-x86_64-darwin) google-protobuf (~> 4.31) - sass-embedded (1.93.2-x86_64-linux-gnu) + sass-embedded (1.93.3-x86_64-linux-gnu) google-protobuf (~> 4.31) - sass-embedded (1.93.2-x86_64-linux-musl) + sass-embedded (1.93.3-x86_64-linux-musl) google-protobuf (~> 4.31) securerandom (0.4.1) selenium-webdriver (4.38.0) @@ -458,7 +460,7 @@ GEM unicode-display_width (3.2.0) unicode-emoji (~> 4.1) unicode-emoji (4.1.0) - uri (1.1.0) + uri (1.1.1) useragent (0.16.11) web-console (4.2.1) actionview (>= 6.0.0) @@ -513,7 +515,7 @@ DEPENDENCIES propshaft puma (>= 5.0) pundit (~> 2.5) - rails (~> 8.0.0) + rails (~> 8.1.1) ransack (~> 4.3) rubocop-rails-omakase selenium-webdriver diff --git a/app/models/section_participant.rb b/app/models/section_participant.rb index dd3bd72..689b59e 100644 --- a/app/models/section_participant.rb +++ b/app/models/section_participant.rb @@ -34,11 +34,21 @@ def self.ransackable_associations(auth_object = nil) end def sitting_attendances - lesson_attendances.where(sitting_lesson_id: section.sitting_lessons.joins(:sitting).merge(Sitting.kept).pluck(:id).uniq).where(present: true) + # sitting_lesson ids for kept sittings + sitting_lesson_ids = section.sitting_lessons.joins(:sitting).merge(Sitting.kept).pluck(:id) + return lesson_attendances.none if sitting_lesson_ids.empty? + + # Return one attendance per lesson (avoid double-counting lessons that appear in multiple sittings). + # Uses Postgres DISTINCT ON to pick a single LessonAttendance per sitting_lesson.lesson_id. + lesson_attendances + .joins(:sitting_lesson) + .where(sitting_lesson_id: sitting_lesson_ids, present: true) + .select("DISTINCT ON (sitting_lessons.lesson_id) lesson_attendances.*") + .order("sitting_lessons.lesson_id, lesson_attendances.created_at DESC") end def average_attendance - ((sitting_attendances.size / section.sitting_lessons.size.to_f) * 100).round(2) + ((sitting_attendances.size / section.lessons_covered.to_f) * 100).round(2) end def attendance_str diff --git a/app/views/section_participants/show.html.erb b/app/views/section_participants/show.html.erb index 0ee2940..3e4e3a2 100644 --- a/app/views/section_participants/show.html.erb +++ b/app/views/section_participants/show.html.erb @@ -12,6 +12,7 @@ Section Session + Lesson Date @@ -20,6 +21,7 @@ <%= @section.name %> <%= attendance.sitting_lesson.sitting.name %> + <%= attendance.sitting_lesson.lesson.title %> <%= attendance.sitting_lesson.sitting.done_on.strftime("%F %H:%M %p") %> <% end %>