From 7b40fd3c96265924ab729287f40da83f2cb5b350 Mon Sep 17 00:00:00 2001 From: David Zuckerman Date: Fri, 20 Feb 2026 16:10:06 -0800 Subject: [PATCH 01/36] upgrades for Rails 8 --- .rubocop.yml | 265 +++++++++++- .ruby-version | 2 +- .yarnrc | 2 +- Dockerfile | 5 +- Gemfile | 53 ++- Gemfile.lock | 505 ++++++++++++---------- app/controllers/application_controller.rb | 4 +- app/lib/lending/borrower_token.rb | 3 +- app/lib/lending/marc_metadata.rb | 2 +- app/models/iiif_directory.rb | 3 +- app/queries/item_query_factory.rb | 2 +- config/application.rb | 10 +- config/initializers/okcomputer.rb | 2 +- config/initializers/omniauth.rb | 4 + config/initializers/pagy.rb | 256 ++--------- spec/system/items_system_spec.rb | 2 +- 16 files changed, 643 insertions(+), 477 deletions(-) diff --git a/.rubocop.yml b/.rubocop.yml index a05ff8c..412e310 100644 --- a/.rubocop.yml +++ b/.rubocop.yml @@ -3,6 +3,7 @@ require: AllCops: UseCache: false + TargetRubyVersion: 3.4 # Exclude generated files Exclude: - 'bin/**/*' @@ -185,7 +186,7 @@ Lint/TripleQuotes: # (new in 1.9) Enabled: true Style/IfWithBooleanLiteralBranches: # (new in 1.9) Enabled: true -Gemspec/DateAssignment: # (new in 1.10) +Gemspec/DeprecatedAttributeAssignment: Enabled: true Style/HashConversion: # (new in 1.10) Enabled: true @@ -332,3 +333,265 @@ Rails/RedundantPresenceValidationOnBelongsTo: # new in 2.13 Enabled: true Rails/RootJoinChain: # new in 2.13 Enabled: true + +# added 20260220 +Gemspec/AddRuntimeDependency: # new in 1.65 + Enabled: true +Gemspec/AttributeAssignment: # new in 1.77 + Enabled: true +Gemspec/DevelopmentDependencies: # new in 1.44 + Enabled: true +Layout/EmptyLinesAfterModuleInclusion: # new in 1.79 + Enabled: true +Layout/LineContinuationLeadingSpace: # new in 1.31 + Enabled: true +Layout/LineContinuationSpacing: # new in 1.31 + Enabled: true +Lint/ArrayLiteralInRegexp: # new in 1.71 + Enabled: true +Lint/ConstantOverwrittenInRescue: # new in 1.31 + Enabled: true +Lint/ConstantReassignment: # new in 1.70 + Enabled: true +Lint/CopDirectiveSyntax: # new in 1.72 + Enabled: true +Lint/DuplicateMagicComment: # new in 1.37 + Enabled: true +Lint/DuplicateMatchPattern: # new in 1.50 + Enabled: true +Lint/DuplicateSetElement: # new in 1.67 + Enabled: true +Lint/HashNewWithKeywordArgumentsAsDefault: # new in 1.69 + Enabled: true +Lint/ItWithoutArgumentsInBlock: # new in 1.59 + Enabled: true +Lint/LiteralAssignmentInCondition: # new in 1.58 + Enabled: true +Lint/MixedCaseRange: # new in 1.53 + Enabled: true +Lint/NonAtomicFileOperation: # new in 1.31 + Enabled: true +Lint/NumericOperationWithConstantResult: # new in 1.69 + Enabled: true +Lint/RedundantRegexpQuantifiers: # new in 1.53 + Enabled: true +Lint/RedundantTypeConversion: # new in 1.72 + Enabled: true +Lint/RefinementImportMethods: # new in 1.27 + Enabled: true +Lint/RequireRangeParentheses: # new in 1.32 + Enabled: true +Lint/SharedMutableDefault: # new in 1.70 + Enabled: true +Lint/SuppressedExceptionInNumberConversion: # new in 1.72 + Enabled: true +Lint/UnescapedBracketInRegexp: # new in 1.68 + Enabled: true +Lint/UselessConstantScoping: # new in 1.72 + Enabled: true +Lint/UselessDefaultValueArgument: # new in 1.76 + Enabled: true +Lint/UselessDefined: # new in 1.69 + Enabled: true +Lint/UselessNumericOperation: # new in 1.66 + Enabled: true +Lint/UselessOr: # new in 1.76 + Enabled: true +Lint/UselessRescue: # new in 1.43 + Enabled: true +Metrics/CollectionLiteralLength: # new in 1.47 + Enabled: true +Naming/PredicateMethod: # new in 1.76 + Enabled: true +Security/CompoundHash: # new in 1.28 + Enabled: true +Style/AmbiguousEndlessMethodDefinition: # new in 1.68 + Enabled: true +Style/ArrayIntersect: # new in 1.40 + Enabled: true +Style/ArrayIntersectWithSingleElement: # new in 1.81 + Enabled: true +Style/BitwisePredicate: # new in 1.68 + Enabled: true +Style/CollectionQuerying: # new in 1.77 + Enabled: true +Style/CombinableDefined: # new in 1.68 + Enabled: true +Style/ComparableBetween: # new in 1.74 + Enabled: true +Style/ComparableClamp: # new in 1.44 + Enabled: true +Style/ConcatArrayLiterals: # new in 1.41 + Enabled: true +Style/DataInheritance: # new in 1.49 + Enabled: true +Style/DigChain: # new in 1.69 + Enabled: true +Style/DirEmpty: # new in 1.48 + Enabled: true +Style/EmptyClassDefinition: # new in 1.84 + Enabled: true +Style/EmptyHeredoc: # new in 1.32 + Enabled: true +Style/EmptyStringInsideInterpolation: # new in 1.76 + Enabled: true +Style/EnvHome: # new in 1.29 + Enabled: true +Style/ExactRegexpMatch: # new in 1.51 + Enabled: true +Style/FetchEnvVar: # new in 1.28 + Enabled: true +Style/FileEmpty: # new in 1.48 + Enabled: true +Style/FileNull: # new in 1.69 + Enabled: true +Style/FileTouch: # new in 1.69 + Enabled: true +Style/HashFetchChain: # new in 1.75 + Enabled: true +Style/HashSlice: # new in 1.71 + Enabled: true +Style/ItAssignment: # new in 1.70 + Enabled: true +Style/ItBlockParameter: # new in 1.75 + Enabled: true +Style/KeywordArgumentsMerging: # new in 1.68 + Enabled: true +Style/MagicCommentFormat: # new in 1.35 + Enabled: true +Style/MapCompactWithConditionalBlock: # new in 1.30 + Enabled: true +Style/MapIntoArray: # new in 1.63 + Enabled: true +Style/MapToSet: # new in 1.42 + Enabled: true +Style/MinMaxComparison: # new in 1.42 + Enabled: true +Style/ModuleMemberExistenceCheck: # new in 1.82 + Enabled: true +Style/NegativeArrayIndex: # new in 1.84 + Enabled: true +Style/ObjectThen: # new in 1.28 + Enabled: true +Style/OperatorMethodCall: # new in 1.37 + Enabled: true +Style/RedundantArrayConstructor: # new in 1.52 + Enabled: true +Style/RedundantArrayFlatten: # new in 1.76 + Enabled: true +Style/RedundantConstantBase: # new in 1.40 + Enabled: true +Style/RedundantCurrentDirectoryInPath: # new in 1.53 + Enabled: true +Style/RedundantDoubleSplatHashBraces: # new in 1.41 + Enabled: true +Style/RedundantEach: # new in 1.38 + Enabled: true +Style/RedundantFilterChain: # new in 1.52 + Enabled: true +Style/RedundantFormat: # new in 1.72 + Enabled: true +Style/RedundantHeredocDelimiterQuotes: # new in 1.45 + Enabled: true +Style/RedundantInitialize: # new in 1.27 + Enabled: true +Style/RedundantInterpolationUnfreeze: # new in 1.66 + Enabled: true +Style/RedundantLineContinuation: # new in 1.49 + Enabled: true +Style/RedundantRegexpArgument: # new in 1.53 + Enabled: true +Style/RedundantRegexpConstructor: # new in 1.52 + Enabled: true +Style/RedundantStringEscape: # new in 1.37 + Enabled: true +Style/ReturnNilInPredicateMethodDefinition: # new in 1.53 + Enabled: true +Style/ReverseFind: # new in 1.84 + Enabled: true +Style/SafeNavigationChainLength: # new in 1.68 + Enabled: true +Style/SendWithLiteralMethodName: # new in 1.64 + Enabled: true +Style/SingleLineDoEndBlock: # new in 1.57 + Enabled: true +Style/SuperArguments: # new in 1.64 + Enabled: true +Style/SuperWithArgsParentheses: # new in 1.58 + Enabled: true +Style/YAMLFileRead: # new in 1.53 + Enabled: true +Rails/ActionControllerFlashBeforeRender: # new in 2.16 + Enabled: true +Rails/ActionControllerTestCase: # new in 2.14 + Enabled: true +Rails/ActionOrder: # new in 2.17 + Enabled: true +Rails/ActiveSupportOnLoad: # new in 2.16 + Enabled: true +Rails/DangerousColumnNames: # new in 2.21 + Enabled: true +Rails/DeprecatedActiveModelErrorsMethods: # new in 2.14 + Enabled: true +Rails/DotSeparatedKeys: # new in 2.15 + Enabled: true +Rails/DuplicateAssociation: # new in 2.14 + Enabled: true +Rails/DuplicateScope: # new in 2.14 + Enabled: true +Rails/EnumSyntax: # new in 2.26 + Enabled: true +Rails/EnvLocal: # new in 2.22 + Enabled: true +Rails/FindByOrAssignmentMemoization: # new in 2.33 + Enabled: true +Rails/FreezeTime: # new in 2.16 + Enabled: true +Rails/HttpStatusNameConsistency: # new in 2.34 + Enabled: true +Rails/I18nLazyLookup: # new in 2.14 + Enabled: true +Rails/I18nLocaleTexts: # new in 2.14 + Enabled: true +Rails/IgnoredColumnsAssignment: # new in 2.17 + Enabled: true +Rails/MigrationClassName: # new in 2.14 + Enabled: true +Rails/MultipleRoutePaths: # new in 2.29 + Enabled: true +Rails/OrderArguments: # new in 2.33 + Enabled: true +Rails/RedirectBackOrTo: # new in 2.34 + Enabled: true +Rails/RedundantActiveRecordAllMethod: # new in 2.21 + Enabled: true +Rails/ResponseParsedBody: # new in 2.18 + Enabled: true +Rails/RootPathnameMethods: # new in 2.16 + Enabled: true +Rails/RootPublicPath: # new in 2.15 + Enabled: true +Rails/SelectMap: # new in 2.21 + Enabled: true +Rails/StripHeredoc: # new in 2.15 + Enabled: true +Rails/StrongParametersExpect: # new in 2.29 + Enabled: true +Rails/ThreeStateBooleanColumn: # new in 2.19 + Enabled: true +Rails/ToFormattedS: # new in 2.15 + Enabled: true +Rails/ToSWithArgument: # new in 2.16 + Enabled: true +Rails/TopLevelHashWithIndifferentAccess: # new in 2.16 + Enabled: true +Rails/TransactionExitStatement: # new in 2.14 + Enabled: true +Rails/UnusedRenderContent: # new in 2.21 + Enabled: true +Rails/WhereMissing: # new in 2.16 + Enabled: true +Rails/WhereNotWithMultipleConditions: # new in 2.17 + Enabled: true +Rails/WhereRange: # new in 2.25 + Enabled: true diff --git a/.ruby-version b/.ruby-version index be94e6f..2f4b607 100644 --- a/.ruby-version +++ b/.ruby-version @@ -1 +1 @@ -3.2.2 +3.4 diff --git a/.yarnrc b/.yarnrc index f5b1384..d133b35 100644 --- a/.yarnrc +++ b/.yarnrc @@ -2,4 +2,4 @@ # yarn lockfile v1 -lastUpdateCheck 1770150293563 +lastUpdateCheck 1771628502550 diff --git a/Dockerfile b/Dockerfile index 03f3209..e258d68 100644 --- a/Dockerfile +++ b/Dockerfile @@ -4,7 +4,7 @@ # The base stage scaffolds elements which are common to building and running # the application, such as installing ca-certificates, creating the app user, # and installing runtime system dependencies. -FROM ruby:3.2.2-slim AS base +FROM ruby:3.4-slim AS base # ------------------------------------------------------------ # Declarative metadata @@ -35,9 +35,12 @@ RUN apt-get update -qq # Install standard packages from the Debian repository RUN apt-get install -y --no-install-recommends \ + build-essential \ curl \ git \ gpg \ + libxml2-dev \ + libxslt1-dev \ libpq-dev \ libvips42 diff --git a/Gemfile b/Gemfile index 0e38aa9..300187c 100644 --- a/Gemfile +++ b/Gemfile @@ -1,33 +1,39 @@ source 'https://rubygems.org' git_source(:github) { |repo| "https://github.com/#{repo}.git" } -ruby '~> 3.2.2' +ruby '~> 3.4' +gem 'addressable', '~> 2.8' gem 'awesome_print', '~> 1.9' -gem 'berkeley_library-alma', '~> 0.0.7' +gem 'berkeley_library-alma', '~> 0.1.1' gem 'berkeley_library-docker', '~> 0.2.0' -gem 'berkeley_library-logging', '~> 0.2', '>= 0.2.7' -gem 'berkeley_library-marc', '~> 0.3' -gem 'berkeley_library-util', '~> 0.1', '>= 0.1.8' +gem 'berkeley_library-logging', '~> 0.3.0' +gem 'berkeley_library-marc', '~> 0.3.2' +gem 'berkeley_library-util', '~> 0.3.0' gem 'cssbundling-rails' -gem 'dotiw', '~> 5.3' -gem 'iiif-presentation', '~> 1.0' -gem 'jbuilder', '~> 2.5' +gem 'csv' +gem 'dotiw', '~> 5.3.3' +gem 'iiif-presentation', '~> 1.4' +gem 'jbuilder', '~> 2.14.0' gem 'jsbundling-rails' gem 'jwt', '~> 2.2' +gem 'nokogiri', '~> 1.18.0' # Workaround for https://github.com/alexspeller/non-stupid-digest-assets/issues/54 -gem 'non-stupid-digest-assets', git: 'https://github.com/BerkeleyLibrary/non-stupid-digest-assets.git', ref: '1de0c38' +#gem 'non-stupid-digest-assets', git: 'https://github.com/BerkeleyLibrary/non-stupid-digest-assets.git', ref: '1de0c38' +gem 'non-digest-assets', '~> 2.6.0' +gem "observer", '~> 0.1.2' gem 'okcomputer', '~> 1.19', '>= 1.19.1' -gem 'omniauth-cas', '~> 2.0' -gem 'pagy', '~> 5.6' +gem 'omniauth', '~> 2.1' +gem 'omniauth-cas', '~> 3.0.2' +gem 'pagy', '~> 43' gem 'pg', '~> 1.2' gem 'pg_search', '~> 2.3' -gem 'puma', '~> 5.0' -gem 'rails', '~> 7.0.4', '>= 7.0.4.3' -gem 'ruby-prof', '~> 0.17.0' # TODO: move this back to dev/test -gem 'ruby-vips', '~> 2.0' -gem 'sprockets-rails', '~> 3.4' -gem 'typesafe_enum', '~> 0.3' +gem 'psych', '~> 2.0.10' +gem 'puma', '~> 7.2.0' +gem 'rails', '~> 8.0.4' +gem 'ruby-vips', '~> 2.3' +gem 'sprockets-rails', '~> 3.5.0' +# gem 'typesafe_enum', '~> 0.3' group :development, :test do gem 'brakeman' @@ -35,23 +41,24 @@ group :development, :test do gem 'byebug', platforms: %i[mri mingw x64_mingw] gem 'colorize' gem 'factory_bot_rails' - gem 'rspec-rails', '~> 5.0' + gem 'ruby-prof', '~> 2.0.0' + gem 'rspec-rails', '~> 8.0' end group :development do gem 'dotenv', '~> 2.7', require: false gem 'foreman' gem 'listen' - gem 'rubocop', '~> 1.26.0' - gem 'rubocop-rails', '~> 2.13.2' - gem 'rubocop-rspec', '~> 2.4.0' - gem 'web-console', '>= 4.1.0' + gem 'rubocop', '~> 1.84.0' + gem 'rubocop-rails', '~> 2.34.0' + gem 'rubocop-rspec', '~> 3.9.0' + gem 'web-console', '>= 4.2.1' end group :test do gem 'capybara', '~> 3.36' gem 'concurrent-ruby', '~> 1.1' - gem 'database_cleaner-active_record', '~> 2.0' + gem 'database_cleaner-active_record', '~> 2.2' gem 'rspec', '~> 3.10' gem 'rspec_junit_formatter', '~> 0.5' gem 'selenium-webdriver', '~> 4.0' diff --git a/Gemfile.lock b/Gemfile.lock index abc3ff7..5d828c5 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -1,105 +1,105 @@ -GIT - remote: https://github.com/BerkeleyLibrary/non-stupid-digest-assets.git - revision: 1de0c3852c49c9578c45d1d6e24c7996b3ebe267 - ref: 1de0c38 - specs: - non-stupid-digest-assets (1.0.9) - sprockets (>= 2.0) - GEM remote: https://rubygems.org/ specs: - actioncable (7.0.4.3) - actionpack (= 7.0.4.3) - activesupport (= 7.0.4.3) + actioncable (8.0.4) + actionpack (= 8.0.4) + activesupport (= 8.0.4) nio4r (~> 2.0) websocket-driver (>= 0.6.1) - actionmailbox (7.0.4.3) - actionpack (= 7.0.4.3) - activejob (= 7.0.4.3) - activerecord (= 7.0.4.3) - activestorage (= 7.0.4.3) - activesupport (= 7.0.4.3) - mail (>= 2.7.1) - net-imap - net-pop - net-smtp - actionmailer (7.0.4.3) - actionpack (= 7.0.4.3) - actionview (= 7.0.4.3) - activejob (= 7.0.4.3) - activesupport (= 7.0.4.3) - mail (~> 2.5, >= 2.5.4) - net-imap - net-pop - net-smtp - rails-dom-testing (~> 2.0) - actionpack (7.0.4.3) - actionview (= 7.0.4.3) - activesupport (= 7.0.4.3) - rack (~> 2.0, >= 2.2.0) + 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) + mail (>= 2.8.0) + actionmailer (8.0.4) + actionpack (= 8.0.4) + actionview (= 8.0.4) + activejob (= 8.0.4) + activesupport (= 8.0.4) + mail (>= 2.8.0) + rails-dom-testing (~> 2.2) + actionpack (8.0.4) + actionview (= 8.0.4) + activesupport (= 8.0.4) + nokogiri (>= 1.8.5) + rack (>= 2.2.4) + rack-session (>= 1.0.1) rack-test (>= 0.6.3) - rails-dom-testing (~> 2.0) - rails-html-sanitizer (~> 1.0, >= 1.2.0) - actiontext (7.0.4.3) - actionpack (= 7.0.4.3) - activerecord (= 7.0.4.3) - activestorage (= 7.0.4.3) - activesupport (= 7.0.4.3) + 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) globalid (>= 0.6.0) nokogiri (>= 1.8.5) - actionview (7.0.4.3) - activesupport (= 7.0.4.3) + actionview (8.0.4) + activesupport (= 8.0.4) builder (~> 3.1) - erubi (~> 1.4) - rails-dom-testing (~> 2.0) - rails-html-sanitizer (~> 1.1, >= 1.2.0) - activejob (7.0.4.3) - activesupport (= 7.0.4.3) + erubi (~> 1.11) + rails-dom-testing (~> 2.2) + rails-html-sanitizer (~> 1.6) + activejob (8.0.4) + activesupport (= 8.0.4) globalid (>= 0.3.6) - activemodel (7.0.4.3) - activesupport (= 7.0.4.3) - activerecord (7.0.4.3) - activemodel (= 7.0.4.3) - activesupport (= 7.0.4.3) - activestorage (7.0.4.3) - actionpack (= 7.0.4.3) - activejob (= 7.0.4.3) - activerecord (= 7.0.4.3) - activesupport (= 7.0.4.3) + activemodel (8.0.4) + activesupport (= 8.0.4) + activerecord (8.0.4) + activemodel (= 8.0.4) + activesupport (= 8.0.4) + timeout (>= 0.4.0) + activestorage (8.0.4) + actionpack (= 8.0.4) + activejob (= 8.0.4) + activerecord (= 8.0.4) + activesupport (= 8.0.4) marcel (~> 1.0) - mini_mime (>= 1.1.0) - activesupport (7.0.4.3) - concurrent-ruby (~> 1.0, >= 1.0.2) + activesupport (8.0.4) + base64 + benchmark (>= 0.3) + bigdecimal + concurrent-ruby (~> 1.0, >= 1.3.1) + connection_pool (>= 2.2.5) + drb i18n (>= 1.6, < 2) + logger (>= 1.4.2) minitest (>= 5.1) - tzinfo (~> 2.0) + securerandom (>= 0.3) + tzinfo (~> 2.0, >= 2.0.5) + uri (>= 0.13.1) addressable (2.8.4) public_suffix (>= 2.0.2, < 6.0) - amazing_print (1.4.0) - ast (2.4.2) + amazing_print (1.8.1) + ast (2.4.3) awesome_print (1.9.2) + base64 (0.3.0) benchmark (0.5.0) - berkeley_library-alma (0.0.7.1) + berkeley_library-alma (0.1.1) berkeley_library-logging (~> 0.2) berkeley_library-marc (~> 0.3.1) berkeley_library-util (~> 0.1, >= 0.1.2) nokogiri (~> 1.13, >= 1.13.6) berkeley_library-docker (0.2.0) - berkeley_library-logging (0.2.7) - activesupport (>= 6) + berkeley_library-logging (0.3.0) + activesupport (>= 7) amazing_print (~> 1.1) - colorize (~> 0.8.1) + colorize (~> 1.0) lograge (~> 0.11) - ougai (~> 1.8) - berkeley_library-marc (0.3.1) + ougai (~> 2.0) + berkeley_library-marc (0.3.2) marc (~> 1.0) parslet (~> 2.0) ruby-marc-spec (~> 0.1) - berkeley_library-util (0.1.8) - berkeley_library-logging (~> 0.2) + berkeley_library-util (0.3.0) + berkeley_library-logging (~> 0.3) rest-client (~> 2.1) typesafe_enum (~> 0.3) + bigdecimal (4.0.1) bindex (0.8.1) brakeman (5.4.1) builder (3.2.4) @@ -118,62 +118,78 @@ GEM rack-test (>= 0.6.3) regexp_parser (>= 1.5, < 3.0) xpath (~> 3.2) - colorize (0.8.1) - concurrent-ruby (1.2.2) + colorize (1.1.0) + concurrent-ruby (1.3.6) + connection_pool (3.0.2) crack (0.4.5) rexml crass (1.0.6) cssbundling-rails (1.1.2) railties (>= 6.0.0) - database_cleaner-active_record (2.1.0) + csv (3.3.5) + database_cleaner-active_record (2.2.2) activerecord (>= 5.a) - database_cleaner-core (~> 2.0.0) + database_cleaner-core (~> 2.0) database_cleaner-core (2.0.1) - date (3.3.3) + date (3.5.1) diff-lcs (1.5.0) docile (1.4.0) - domain_name (0.5.20190701) - unf (>= 0.0.5, < 1.0.0) + domain_name (0.6.20240107) dotenv (2.8.1) dotiw (5.3.3) activesupport i18n + drb (2.2.3) erubi (1.12.0) factory_bot (6.2.1) activesupport (>= 5.0.0) factory_bot_rails (6.2.0) factory_bot (~> 6.2.0) railties (>= 5.0.0) - faraday (2.7.5) - faraday-net_http (>= 2.0, < 3.1) - ruby2_keywords (>= 0.0.4) - faraday-net_http (3.0.2) + faraday (2.14.1) + faraday-net_http (>= 2.0, < 3.5) + json + logger + faraday-net_http (3.4.2) + net-http (~> 0.5) ffi (1.15.5) foreman (0.89.1) - globalid (1.1.0) - activesupport (>= 5.0) + geo_coord (0.2.0) + globalid (1.3.0) + activesupport (>= 6.1) hashdiff (1.0.1) - hashie (5.0.0) + hashie (5.1.0) + logger http-accept (1.7.0) - http-cookie (1.0.5) + http-cookie (1.1.0) domain_name (~> 0.5) i18n (1.13.0) concurrent-ruby (~> 1.0) - iiif-presentation (1.1.0) + iiif-presentation (1.4.2) activesupport (>= 3.2.18) - faraday (>= 0.9) + faraday (~> 2.7) + geo_coord json - jbuilder (2.11.5) - actionview (>= 5.0.0) - activesupport (>= 5.0.0) + io-console (0.8.2) + irb (1.17.0) + pp (>= 0.6.0) + prism (>= 1.3.0) + rdoc (>= 4.0.0) + reline (>= 0.4.2) + jbuilder (2.14.1) + actionview (>= 7.0.0) + activesupport (>= 7.0.0) jsbundling-rails (1.1.1) railties (>= 6.0.0) json (2.6.3) jwt (2.7.0) + language_server-protocol (3.17.0.5) + lint_roller (1.1.0) listen (3.9.0) rb-fsevent (~> 0.10, >= 0.10.3) rb-inotify (~> 0.9, >= 0.9.10) - lograge (0.12.0) + logger (1.7.0) + lograge (0.14.0) actionpack (>= 4) activesupport (>= 4) railties (>= 4) @@ -181,104 +197,134 @@ GEM loofah (2.21.3) crass (~> 1.0.2) nokogiri (>= 1.12.0) - mail (2.8.1) + mail (2.9.0) + logger mini_mime (>= 0.1.1) net-imap net-pop net-smtp - marc (1.2.0) + marc (1.4.0) + nokogiri (~> 1.0) rexml - scrub_rb (>= 1.0.1, < 2) - unf - marcel (1.0.2) + marcel (1.1.0) matrix (0.4.2) - method_source (1.0.0) - mime-types (3.4.1) - mime-types-data (~> 3.2015) - mime-types-data (3.2023.0218.1) + mime-types (3.7.0) + logger + mime-types-data (~> 3.2025, >= 3.2025.0507) + mime-types-data (3.2026.0203) mini_mime (1.1.2) minitest (5.18.0) - net-imap (0.3.4) + mutex_m (0.3.0) + net-http (0.9.1) + uri (>= 0.11.1) + net-imap (0.6.3) date net-protocol net-pop (0.1.2) net-protocol - net-protocol (0.2.1) + net-protocol (0.2.2) timeout - net-smtp (0.3.3) + net-smtp (0.5.1) net-protocol netrc (0.11.0) nio4r (2.5.9) - nokogiri (1.15.2-aarch64-linux) + nokogiri (1.18.10-aarch64-linux-gnu) racc (~> 1.4) - nokogiri (1.15.2-arm64-darwin) - racc (~> 1.4) - nokogiri (1.15.2-x86_64-darwin) - racc (~> 1.4) - nokogiri (1.15.2-x86_64-linux) - racc (~> 1.4) - oj (3.14.3) + non-digest-assets (2.6.0) + activesupport (>= 6.0, < 8.2) + mutex_m (~> 0.3.0) + sprockets (~> 4.0) + observer (0.1.2) + oj (3.16.15) + bigdecimal (>= 3.0) + ostruct (>= 0.2) okcomputer (1.19.1) benchmark - omniauth (1.9.2) + omniauth (2.1.4) hashie (>= 3.4.6) - rack (>= 1.6.2, < 3) - omniauth-cas (2.0.0) - addressable (~> 2.3) - nokogiri (~> 1.5) - omniauth (~> 1.2) - ougai (1.9.1) + logger + rack (>= 2.2.3) + rack-protection + omniauth-cas (3.0.2) + addressable (~> 2.8) + nokogiri (~> 1.12) + omniauth (~> 2.1) + ostruct (0.6.3) + ougai (2.0.0) oj (~> 3.10) - pagy (5.10.1) - activesupport - parallel (1.23.0) - parser (3.2.2.1) + pagy (43.2.10) + json + uri + yaml + parallel (1.27.0) + parser (3.3.10.2) ast (~> 2.4.1) + racc parslet (2.0.0) pg (1.5.3) pg_search (2.3.6) activerecord (>= 5.2) activesupport (>= 5.2) + pp (0.6.3) + prettyprint + prettyprint (0.2.0) + prism (1.9.0) + psych (2.0.17) public_suffix (5.0.1) - puma (5.6.5) + puma (7.2.0) nio4r (~> 2.0) - racc (1.6.2) + racc (1.8.1) rack (2.2.7) + rack-protection (3.2.0) + base64 (>= 0.1.0) + rack (~> 2.2, >= 2.2.4) + rack-session (1.0.2) + rack (< 3) rack-test (2.1.0) rack (>= 1.3) - rails (7.0.4.3) - actioncable (= 7.0.4.3) - actionmailbox (= 7.0.4.3) - actionmailer (= 7.0.4.3) - actionpack (= 7.0.4.3) - actiontext (= 7.0.4.3) - actionview (= 7.0.4.3) - activejob (= 7.0.4.3) - activemodel (= 7.0.4.3) - activerecord (= 7.0.4.3) - activestorage (= 7.0.4.3) - activesupport (= 7.0.4.3) + rackup (1.0.1) + rack (< 3) + webrick + 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) bundler (>= 1.15.0) - railties (= 7.0.4.3) - rails-dom-testing (2.0.3) - activesupport (>= 4.2.0) + railties (= 8.0.4) + rails-dom-testing (2.3.0) + activesupport (>= 5.0.0) + minitest nokogiri (>= 1.6) - rails-html-sanitizer (1.5.0) - loofah (~> 2.19, >= 2.19.1) - railties (7.0.4.3) - actionpack (= 7.0.4.3) - activesupport (= 7.0.4.3) - method_source + 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) + irb (~> 1.13) + rackup (>= 1.0.0) rake (>= 12.2) - thor (~> 1.0) - zeitwerk (~> 2.5) + thor (~> 1.0, >= 1.2.2) + tsort (>= 0.2) + zeitwerk (~> 2.6) rainbow (3.1.1) rake (13.0.6) rb-fsevent (0.11.2) rb-inotify (0.11.1) ffi (~> 1.0) - regexp_parser (2.8.0) - request_store (1.5.1) + rdoc (6.3.4.1) + regexp_parser (2.11.3) + reline (0.6.3) + io-console (~> 0.5) + request_store (1.7.0) rack (>= 1.4) rest-client (2.1.0) http-accept (>= 1.7.0, < 2.0) @@ -286,58 +332,65 @@ GEM mime-types (>= 1.16, < 4.0) netrc (~> 0.8) rexml (3.2.5) - rspec (3.12.0) - rspec-core (~> 3.12.0) - rspec-expectations (~> 3.12.0) - rspec-mocks (~> 3.12.0) - rspec-core (3.12.2) - rspec-support (~> 3.12.0) - rspec-expectations (3.12.3) + rspec (3.13.2) + rspec-core (~> 3.13.0) + rspec-expectations (~> 3.13.0) + rspec-mocks (~> 3.13.0) + rspec-core (3.13.6) + rspec-support (~> 3.13.0) + rspec-expectations (3.13.5) diff-lcs (>= 1.2.0, < 2.0) - rspec-support (~> 3.12.0) - rspec-mocks (3.12.5) + rspec-support (~> 3.13.0) + rspec-mocks (3.13.7) diff-lcs (>= 1.2.0, < 2.0) - rspec-support (~> 3.12.0) - rspec-rails (5.1.2) - actionpack (>= 5.2) - activesupport (>= 5.2) - railties (>= 5.2) - rspec-core (~> 3.10) - rspec-expectations (~> 3.10) - rspec-mocks (~> 3.10) - rspec-support (~> 3.10) - rspec-support (3.12.0) + rspec-support (~> 3.13.0) + rspec-rails (8.0.3) + actionpack (>= 7.2) + activesupport (>= 7.2) + railties (>= 7.2) + rspec-core (~> 3.13) + rspec-expectations (~> 3.13) + rspec-mocks (~> 3.13) + rspec-support (~> 3.13) + rspec-support (3.13.7) rspec_junit_formatter (0.6.0) rspec-core (>= 2, < 4, != 2.12.0) - rubocop (1.26.1) + rubocop (1.84.2) + json (~> 2.3) + language_server-protocol (~> 3.17.0.2) + lint_roller (~> 1.1.0) parallel (~> 1.10) - parser (>= 3.1.0.0) + parser (>= 3.3.0.2) rainbow (>= 2.2.2, < 4.0) - regexp_parser (>= 1.8, < 3.0) - rexml - rubocop-ast (>= 1.16.0, < 2.0) + regexp_parser (>= 2.9.3, < 3.0) + rubocop-ast (>= 1.49.0, < 2.0) ruby-progressbar (~> 1.7) - unicode-display_width (>= 1.4.0, < 3.0) - rubocop-ast (1.28.1) - parser (>= 3.2.1.0) - rubocop-rails (2.13.2) + unicode-display_width (>= 2.4.0, < 4.0) + rubocop-ast (1.49.0) + parser (>= 3.3.7.2) + prism (~> 1.7) + rubocop-rails (2.34.3) activesupport (>= 4.2.0) + lint_roller (~> 1.1) rack (>= 1.1) - rubocop (>= 1.7.0, < 2.0) - rubocop-rspec (2.4.0) - rubocop (~> 1.0) - rubocop-ast (>= 1.1.0) + rubocop (>= 1.75.0, < 2.0) + rubocop-ast (>= 1.44.0, < 2.0) + rubocop-rspec (3.9.0) + lint_roller (~> 1.1) + rubocop (~> 1.81) ruby-marc-spec (0.1.3) marc (~> 1.1) parslet (~> 2.0) typesafe_enum (~> 0.3) - ruby-prof (0.17.0) + ruby-prof (2.0.2) + base64 + ostruct ruby-progressbar (1.13.0) - ruby-vips (2.1.4) + ruby-vips (2.3.0) ffi (~> 1.12) - ruby2_keywords (0.0.5) + logger rubyzip (2.3.2) - scrub_rb (1.0.1) + securerandom (0.4.1) selenium-webdriver (4.9.1) rexml (~> 3.2, >= 3.2.5) rubyzip (>= 1.2.2, < 3.0) @@ -353,20 +406,22 @@ GEM sprockets (4.2.0) concurrent-ruby (~> 1.0) rack (>= 2.2.4, < 4) - sprockets-rails (3.4.2) - actionpack (>= 5.2) - activesupport (>= 5.2) + sprockets-rails (3.5.2) + actionpack (>= 6.1) + activesupport (>= 6.1) sprockets (>= 3.0.0) thor (1.2.2) - timeout (0.3.2) + timeout (0.6.0) + tsort (0.2.0) typesafe_enum (0.3.1) tzinfo (2.0.6) concurrent-ruby (~> 1.0) - unf (0.1.4) - unf_ext - unf_ext (0.0.8.2) - unicode-display_width (2.4.2) - web-console (4.2.0) + unicode-display_width (3.2.0) + unicode-emoji (~> 4.1) + unicode-emoji (4.2.0) + uri (1.1.1) + useragent (0.16.11) + web-console (4.2.1) actionview (>= 6.0.0) activemodel (>= 6.0.0) bindex (>= 0.4.0) @@ -375,12 +430,15 @@ GEM addressable (>= 2.8.0) crack (>= 0.3.2) hashdiff (>= 0.4.0, < 2.0.0) + webrick (1.9.2) websocket (1.2.9) - websocket-driver (0.7.5) + websocket-driver (0.8.0) + base64 websocket-extensions (>= 0.1.0) websocket-extensions (0.1.5) xpath (3.2.0) nokogiri (~> 1.8) + yaml (0.4.0) zeitwerk (2.6.8) PLATFORMS @@ -390,12 +448,13 @@ PLATFORMS x86_64-linux DEPENDENCIES + addressable (~> 2.8) awesome_print (~> 1.9) - berkeley_library-alma (~> 0.0.7) + berkeley_library-alma (~> 0.1.1) berkeley_library-docker (~> 0.2.0) - berkeley_library-logging (~> 0.2, >= 0.2.7) - berkeley_library-marc (~> 0.3) - berkeley_library-util (~> 0.1, >= 0.1.8) + berkeley_library-logging (~> 0.3.0) + berkeley_library-marc (~> 0.3.2) + berkeley_library-util (~> 0.3.0) brakeman bundle-audit byebug @@ -403,42 +462,46 @@ DEPENDENCIES colorize concurrent-ruby (~> 1.1) cssbundling-rails - database_cleaner-active_record (~> 2.0) + csv + database_cleaner-active_record (~> 2.2) dotenv (~> 2.7) - dotiw (~> 5.3) + dotiw (~> 5.3.3) factory_bot_rails foreman - iiif-presentation (~> 1.0) - jbuilder (~> 2.5) + iiif-presentation (~> 1.4) + jbuilder (~> 2.14.0) jsbundling-rails jwt (~> 2.2) listen - non-stupid-digest-assets! + nokogiri (~> 1.18.0) + non-digest-assets (~> 2.6.0) + observer (~> 0.1.2) okcomputer (~> 1.19, >= 1.19.1) - omniauth-cas (~> 2.0) - pagy (~> 5.6) + omniauth (~> 2.1) + omniauth-cas (~> 3.0.2) + pagy (~> 43) pg (~> 1.2) pg_search (~> 2.3) - puma (~> 5.0) - rails (~> 7.0.4, >= 7.0.4.3) + psych (~> 2.0.10) + puma (~> 7.2.0) + rails (~> 8.0.4) rspec (~> 3.10) - rspec-rails (~> 5.0) + rspec-rails (~> 8.0) rspec_junit_formatter (~> 0.5) - rubocop (~> 1.26.0) - rubocop-rails (~> 2.13.2) - rubocop-rspec (~> 2.4.0) - ruby-prof (~> 0.17.0) - ruby-vips (~> 2.0) + rubocop (~> 1.84.0) + rubocop-rails (~> 2.34.0) + rubocop-rspec (~> 3.9.0) + ruby-prof (~> 2.0.0) + ruby-vips (~> 2.3) selenium-webdriver (~> 4.0) simplecov (~> 0.21) simplecov-rcov (~> 0.2) - sprockets-rails (~> 3.4) - typesafe_enum (~> 0.3) - web-console (>= 4.1.0) + sprockets-rails (~> 3.5.0) + web-console (>= 4.2.1) webmock RUBY VERSION - ruby 3.2.2p53 + ruby 3.4.8p72 BUNDLED WITH 2.4.10 diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index 99a5981..7341982 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -3,7 +3,7 @@ # rubocop:disable Metrics/ClassLength class ApplicationController < ActionController::Base include ExceptionHandling - include Pagy::Backend + include Pagy::Method # ------------------------------------------------------------ # Global controller configuration @@ -15,7 +15,7 @@ class ApplicationController < ActionController::Base # Global hooks after_action do - pagy_headers_merge(@pagy) if @pagy + response.headers.merge!(@pagy.headers_hash) if @pagy merge_link_header end diff --git a/app/lib/lending/borrower_token.rb b/app/lib/lending/borrower_token.rb index fb3771d..9c52e60 100644 --- a/app/lib/lending/borrower_token.rb +++ b/app/lib/lending/borrower_token.rb @@ -77,7 +77,8 @@ def _load(token_str) private def hmac_secret - @hmac_secret ||= Rails.application.secrets.fetch(:secret_key_base) { raise ArgumentError, 'Rails secret_key_base not set' }.to_s + # @hmac_secret ||= Rails.application.secrets.fetch(:secret_key_base) { raise ArgumentError, 'Rails secret_key_base not set' }.to_s + @hmac_secret ||= Rails.application.secret_key_base.to_s { raise ArgumentError, 'Rails secret_key_base not set' }.to_s end def decode(token_str) diff --git a/app/lib/lending/marc_metadata.rb b/app/lib/lending/marc_metadata.rb index 058d960..8283961 100644 --- a/app/lib/lending/marc_metadata.rb +++ b/app/lib/lending/marc_metadata.rb @@ -28,7 +28,7 @@ def from_file(marc_path) def load_marc_record(marc_path) marc_record = MARC::XMLReader.read(marc_path.to_s, freeze: true).first - return MarcMetadata.new(marc_record) if marc_record + MarcMetadata.new(marc_record) if marc_record end end diff --git a/app/models/iiif_directory.rb b/app/models/iiif_directory.rb index 110e6a8..a02472f 100644 --- a/app/models/iiif_directory.rb +++ b/app/models/iiif_directory.rb @@ -46,7 +46,6 @@ def fetch(directory, stage: :final) # @return [ActiveSupport::Cache::MemoryStore] def cache @cache ||= ActiveSupport::Cache::MemoryStore.new( - coder: ActiveSupport::Cache::NullCoder, expires_in: CACHE_EXPIRY ) end @@ -65,7 +64,7 @@ def reason_incomplete return "#{MSG_NO_IIIF_DIR}: #{path}" unless exists? return MSG_NO_PAGE_IMAGES unless page_images? return MSG_NO_MARC_XML unless marc_record? - return MSG_NO_MANIFEST unless manifest? + MSG_NO_MANIFEST unless manifest? end def exists? diff --git a/app/queries/item_query_factory.rb b/app/queries/item_query_factory.rb index 4c24138..2813046 100644 --- a/app/queries/item_query_factory.rb +++ b/app/queries/item_query_factory.rb @@ -74,7 +74,7 @@ def false?(flag) def keywords_or_nil(opt) keywords = opt.to_s.strip - return keywords unless keywords.empty? + keywords unless keywords.empty? end def strings_or_nil(opt) diff --git a/config/application.rb b/config/application.rb index 539a5aa..e6bef4f 100644 --- a/config/application.rb +++ b/config/application.rb @@ -1,11 +1,14 @@ # ------------------------------------------------------------ # Standard Rails initialization +ENV['SECRET_KEY_BASE'] ||= '1' if ENV['CI'] + require File.expand_path('boot', __dir__) require 'rails' require 'active_model/railtie' require 'active_record/railtie' +require 'active_storage/engine' require 'action_controller/railtie' require 'action_view/railtie' require 'sprockets/railtie' @@ -24,7 +27,12 @@ module UCBEARS class Application < Rails::Application # Initialize configuration defaults for originally generated Rails version. - config.load_defaults 7.0 + config.load_defaults 8.0 + + # Please, add to the `ignore` list any other `lib` subdirectories that do + # not contain `.rb` files, or that should not be reloaded or eager loaded. + # Common ones are `templates`, `generators`, or `middleware`, for example. + config.autoload_lib(ignore: %w[assets tasks]) # Don't generate system test files. config.generators.system_tests = nil diff --git a/config/initializers/okcomputer.rb b/config/initializers/okcomputer.rb index 21e24ac..6164d34 100644 --- a/config/initializers/okcomputer.rb +++ b/config/initializers/okcomputer.rb @@ -1,4 +1,4 @@ -require 'health_checks' +require Rails.root.join('app/lib/health_checks') OkComputer.logger = Rails.logger OkComputer.check_in_parallel = true diff --git a/config/initializers/omniauth.rb b/config/initializers/omniauth.rb index 3bc511e..c2f6ead 100644 --- a/config/initializers/omniauth.rb +++ b/config/initializers/omniauth.rb @@ -24,6 +24,10 @@ service_validate_url: '/cas/p3/serviceValidate', fetch_raw_info: fetch_raw_info + # OmniAuth 2 defaults to POST-only request phase. + # This app's login flow redirects users with a GET to /auth/:provider. + OmniAuth.config.allowed_request_methods = %i[get post] + # Override the default 'puts' logger that Omniauth uses. OmniAuth.config.logger = Rails.logger end diff --git a/config/initializers/pagy.rb b/config/initializers/pagy.rb index 4aa3464..6e67e21 100644 --- a/config/initializers/pagy.rb +++ b/config/initializers/pagy.rb @@ -1,232 +1,50 @@ # frozen_string_literal: true -# Pagy initializer file (5.6.4) -# Customize only what you really need and notice that the core Pagy works also without any of the following lines. -# Should you just cherry pick part of this file, please maintain the require-order of the extras - -# Pagy DEFAULT Variables -# See https://ddnexus.github.io/pagy/api/pagy#variables -# All the Pagy::DEFAULT are set for all the Pagy instances but can be overridden per instance by just passing them to -# Pagy.new|Pagy::Countless.new|Pagy::Calendar::*.new or any of the #pagy* controller methods - -# Instance variables -# See https://ddnexus.github.io/pagy/api/pagy#instance-variables -# Pagy::DEFAULT[:page] = 1 # default -# Pagy::DEFAULT[:items] = 20 # default -# Pagy::DEFAULT[:outset] = 0 # default +# Pagy initializer file (43.2.10) +# See https://ddnexus.github.io/pagy/resources/initializer/ # TODO: something more configurable -Pagy::DEFAULT[:items] = 2 if Rails.env.development? - -# Other Variables -# See https://ddnexus.github.io/pagy/api/pagy#other-variables -# Pagy::DEFAULT[:size] = [1,4,4,1] # default -# Pagy::DEFAULT[:page_param] = :page # default -# The :params can be also set as a lambda e.g ->(params){ params.exclude('useless').merge!('custom' => 'useful') } -# Pagy::DEFAULT[:params] = {} # default -# Pagy::DEFAULT[:fragment] = '#fragment' # example -# Pagy::DEFAULT[:link_extra] = 'data-remote="true"' # example -# Pagy::DEFAULT[:i18n_key] = 'pagy.item_name' # default -# Pagy::DEFAULT[:cycle] = true # example - -# Extras -# See https://ddnexus.github.io/pagy/extras - -# Backend Extras +Pagy.options[:items] = 2 if Rails.env.development? -# Array extra: Paginate arrays efficiently, avoiding expensive array-wrapping and without overriding -# See https://ddnexus.github.io/pagy/extras/array -# require 'pagy/extras/array' - -# Calendar extra: Add pagination filtering by calendar time unit (year, quarter, month, week, day) -# See https://ddnexus.github.io/pagy/extras/calendar -# require 'pagy/extras/calendar' -# Default for each unit -# Pagy::Calendar::Year::DEFAULT[:order] = :asc # Time direction of pagination -# Pagy::Calendar::Year::DEFAULT[:format] = '%Y' # strftime format -# -# Pagy::Calendar::Quarter::DEFAULT[:order] = :asc # Time direction of pagination -# Pagy::Calendar::Quarter::DEFAULT[:format] = '%Y-Q%q' # strftime format -# -# Pagy::Calendar::Month::DEFAULT[:order] = :asc # Time direction of pagination -# Pagy::Calendar::Month::DEFAULT[:format] = '%Y-%m' # strftime format -# -# Pagy::Calendar::Week::DEFAULT[:order] = :asc # Time direction of pagination -# Pagy::Calendar::Week::DEFAULT[:format] = '%Y-%W' # strftime format -# Pagy::Calendar::Week::DEFAULT[:offset] = 0 # Day offset from Sunday (0: Sunday; 1: Monday;... 6: Saturday) -# -# Pagy::Calendar::Day::DEFAULT[:order] = :asc # Time direction of pagination -# Pagy::Calendar::Day::DEFAULT[:format] = '%Y-%m-%d' # strftime format +############ Global Options ################################################################ +# See https://ddnexus.github.io/pagy/toolbox/options/ for details. +# Add your global options below. They will be applied globally. +# For example: # -# Uncomment the following lines, if you need calendar localization without using the I18n extra -# module LocalizePagyCalendar -# def localize(time, opts) -# ::I18n.l(time, **opts) -# end -# end -# Pagy::Calendar.prepend LocalizePagyCalendar - -# Countless extra: Paginate without any count, saving one query per rendering -# See https://ddnexus.github.io/pagy/extras/countless -# require 'pagy/extras/countless' -# Pagy::DEFAULT[:countless_minimal] = false # default (eager loading) - -# Elasticsearch Rails extra: Paginate `ElasticsearchRails::Results` objects -# See https://ddnexus.github.io/pagy/extras/elasticsearch_rails -# default :pagy_search method: change only if you use also -# the searchkick or meilisearch extra that defines the same -# Pagy::DEFAULT[:elasticsearch_rails_search_method] = :pagy_search -# require 'pagy/extras/elasticsearch_rails' - -# Headers extra: http response headers (and other helpers) useful for API pagination -# See http://ddnexus.github.io/pagy/extras/headers -require 'pagy/extras/headers' -# Pagy::DEFAULT[:headers] = { page: 'Current-Page', -# items: 'Page-Items', -# count: 'Total-Count', -# pages: 'Total-Pages' } # default -# TODO: put links in JSON response instead - -# Meilisearch extra: Paginate `Meilisearch` result objects -# See https://ddnexus.github.io/pagy/extras/meilisearch -# default :pagy_search method: change only if you use also -# the elasticsearch_rails or searchkick extra that define the same method -# Pagy::DEFAULT[:meilisearch_search_method] = :pagy_search -# require 'pagy/extras/meilisearch' - -# Metadata extra: Provides the pagination metadata to Javascript frameworks like Vue.js, react.js, etc. -# See https://ddnexus.github.io/pagy/extras/metadata -# you must require the shared internal extra (BEFORE the metadata extra) ONLY if you need also the :sequels -# require 'pagy/extras/shared' -# require 'pagy/extras/metadata' -# For performance reasons, you should explicitly set ONLY the metadata you use in the frontend -# Pagy::DEFAULT[:metadata] = %i[scaffold_url page prev next last] # example - -# Searchkick extra: Paginate `Searchkick::Results` objects -# See https://ddnexus.github.io/pagy/extras/searchkick -# default :pagy_search method: change only if you use also -# the elasticsearch_rails or meilisearch extra that defines the same -# DEFAULT[:searchkick_search_method] = :pagy_search -# require 'pagy/extras/searchkick' -# uncomment if you are going to use Searchkick.pagy_search -# Searchkick.extend Pagy::Searchkick - -# Frontend Extras - -# Bootstrap extra: Add nav, nav_js and combo_nav_js helpers and templates for Bootstrap pagination -# See https://ddnexus.github.io/pagy/extras/bootstrap -# require 'pagy/extras/bootstrap' - -# Bulma extra: Add nav, nav_js and combo_nav_js helpers and templates for Bulma pagination -# See https://ddnexus.github.io/pagy/extras/bulma -# require 'pagy/extras/bulma' - -# Foundation extra: Add nav, nav_js and combo_nav_js helpers and templates for Foundation pagination -# See https://ddnexus.github.io/pagy/extras/foundation -# require 'pagy/extras/foundation' +# Pagy.options[:limit] = 10 # Limit the items per page +# Pagy.options[:client_max_limit] = 100 # The client can request a limit up to 100 +# Pagy.options[:max_pages] = 200 # Allow only 200 pages +# Pagy.options[:jsonapi] = true # Use JSON:API compliant URLs -# Materialize extra: Add nav, nav_js and combo_nav_js helpers for Materialize pagination -# See https://ddnexus.github.io/pagy/extras/materialize -# require 'pagy/extras/materialize' - -# Navs extra: Add nav_js and combo_nav_js javascript helpers -# Notice: the other frontend extras add their own framework-styled versions, -# so require this extra only if you need the unstyled version -# See https://ddnexus.github.io/pagy/extras/navs -# require 'pagy/extras/navs' - -# Semantic extra: Add nav, nav_js and combo_nav_js helpers for Semantic UI pagination -# See https://ddnexus.github.io/pagy/extras/semantic -# require 'pagy/extras/semantic' - -# UIkit extra: Add nav helper and templates for UIkit pagination -# See https://ddnexus.github.io/pagy/extras/uikit -# require 'pagy/extras/uikit' - -# Multi size var used by the *_nav_js helpers -# See https://ddnexus.github.io/pagy/extras/navs#steps -# Pagy::DEFAULT[:steps] = { 0 => [2,3,3,2], 540 => [3,5,5,3], 720 => [5,7,7,5] } # example - -# Feature Extras - -# Gearbox extra: Automatically change the number of items per page depending on the page number -# See https://ddnexus.github.io/pagy/extras/gearbox -# require 'pagy/extras/gearbox' -# set to false only if you want to make :gearbox_extra an opt-in variable -# Pagy::DEFAULT[:gearbox_extra] = false # default true -# Pagy::DEFAULT[:gearbox_items] = [15, 30, 60, 100] # default - -# Items extra: Allow the client to request a custom number of items per page with an optional selector UI -# See https://ddnexus.github.io/pagy/extras/items -# require 'pagy/extras/items' -# set to false only if you want to make :items_extra an opt-in variable -# Pagy::DEFAULT[:items_extra] = false # default true -# Pagy::DEFAULT[:items_param] = :items # default -# Pagy::DEFAULT[:max_items] = 100 # default - -# Overflow extra: Allow for easy handling of overflowing pages -# See https://ddnexus.github.io/pagy/extras/overflow -# require 'pagy/extras/overflow' -# Pagy::DEFAULT[:overflow] = :empty_page # default (other options: :last_page and :exception) - -# Support extra: Extra support for features like: incremental, infinite, auto-scroll pagination -# See https://ddnexus.github.io/pagy/extras/support -# require 'pagy/extras/support' - -# Trim extra: Remove the page=1 param from links -# See https://ddnexus.github.io/pagy/extras/trim -# require 'pagy/extras/trim' -# set to false only if you want to make :trim_extra an opt-in variable -# Pagy::DEFAULT[:trim_extra] = false # default true - -# Standalone extra: Use pagy in non Rack environment/gem -# See https://ddnexus.github.io/pagy/extras/standalone -# require 'pagy/extras/standalone' -# Pagy::DEFAULT[:url] = 'http://www.example.com/subdir' # optional default - -# Rails - -# Rails: extras assets path required by the helpers that use javascript -# (pagy*_nav_js, pagy*_combo_nav_js, and pagy_items_selector_js) -# See https://ddnexus.github.io/pagy/extras#javascript -# Rails.application.config.assets.paths << Pagy.root.join('javascripts') - -# I18n - -# Pagy internal I18n: ~18x faster using ~10x less memory than the i18n gem -# See https://ddnexus.github.io/pagy/api/frontend#i18n -# Notice: No need to configure anything in this section if your app uses only "en" -# or if you use the i18n extra below +############ JavaScript #################################################################### +# See https://ddnexus.github.io/pagy/resources/javascript/ for details. +# Examples for Rails: +# For apps with an assets pipeline +# Rails.application.config.assets.paths << Pagy::ROOT.join('javascripts') # -# Examples: -# load the "de" built-in locale: -# Pagy::I18n.load(locale: 'de') -# -# load the "de" locale defined in the custom file at :filepath: -# Pagy::I18n.load(locale: 'de', filepath: 'path/to/pagy-de.yml') -# -# load the "de", "en" and "es" built-in locales: -# (the first passed :locale will be used also as the default_locale) -# Pagy::I18n.load({ locale: 'de' }, -# { locale: 'en' }, -# { locale: 'es' }) +# For apps with a javascript builder (e.g. esbuild, webpack, etc.) +# javascript_dir = Rails.root.join('app/javascript') +# Pagy.sync_javascript(javascript_dir, 'pagy.mjs') if Rails.env.development? + +############# Overriding Pagy::I18n Lookup ################################################# +# Refer to https://ddnexus.github.io/pagy/resources/i18n/ for details. +# Override the I18n lookup by dropping your custom dictionary in some pagy dir. +# Example for Rails: # -# load the "en" built-in locale, a custom "es" locale, -# and a totally custom locale complete with a custom :pluralize proc: -# (the first passed :locale will be used also as the default_locale) -# Pagy::I18n.load({ locale: 'en' }, -# { locale: 'es', filepath: 'path/to/pagy-es.yml' }, -# { locale: 'xyz', # not built-in -# filepath: 'path/to/pagy-xyz.yml', -# pluralize: lambda{ |count| ... } ) +# Pagy::I18n.pathnames << Rails.root.join('config/locales/pagy') -# I18n extra: uses the standard i18n gem which is ~18x slower using ~10x more memory -# than the default pagy internal i18n (see above) -# See https://ddnexus.github.io/pagy/extras/i18n -# require 'pagy/extras/i18n' +############# I18n Gem Translation ######################################################### +# See https://ddnexus.github.io/pagy/resources/i18n/ for details. +# +# Pagy.translate_with_the_slower_i18n_gem! -# Default i18n key -# Pagy::DEFAULT[:i18n_key] = 'pagy.item_name' # default +############# Calendar Localization for non-en locales #################################### +# See https://ddnexus.github.io/pagy/toolbox/paginators/calendar#localization for details. +# Add your desired locales to the list and uncomment the following line to enable them, +# regardless of whether you use the I18n gem for translations or not, whether with +# Rails or not. +# +# Pagy::Calendar.localize_with_rails_i18n_gem(*your_locales) # When you are done setting your own default freeze it, so it will not get changed accidentally -Pagy::DEFAULT.freeze +Pagy.options.freeze diff --git a/spec/system/items_system_spec.rb b/spec/system/items_system_spec.rb index 382417d..53f6c06 100644 --- a/spec/system/items_system_spec.rb +++ b/spec/system/items_system_spec.rb @@ -32,7 +32,7 @@ it 'displays the items' do visit items_path - expected_count = [Item.count, Pagy::DEFAULT[:items]].min + expected_count = [Item.count, Pagy.options[:items]].min expected_items = Item.take(expected_count) expect(expected_items).not_to be_empty From 86fa80b2bfb810a2d7dc0b7c9e8539b9fc788783 Mon Sep 17 00:00:00 2001 From: David Zuckerman Date: Fri, 20 Feb 2026 17:04:28 -0800 Subject: [PATCH 02/36] dependency updates --- app/controllers/application_controller.rb | 18 ++++++++---------- app/controllers/items_controller.rb | 2 +- .../application/standard_error.json.jbuilder | 4 ++-- .../validation_errors.json.jbuilder | 4 ++-- 4 files changed, 13 insertions(+), 15 deletions(-) diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index 7341982..ade1c67 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -137,7 +137,7 @@ def with_profile(report_filename, &) return if performed? flash_now!(:danger, t('application.profile.failed', msg: e.message)) - render('application/standard_error', locals: { exception: e }) + render('application/standard_error', status: :internal_server_error, locals: { status: :internal_server_error, exception: e, message: e.message }) end # ------------------------------ @@ -190,17 +190,15 @@ def ensure_flash_array(flash_obj, lvl) end def do_profile(report_filename, &block) - RubyProf.stop if RubyProf.running? - RubyProf.start - begin - block.call - ensure - write_profile_report(report_filename) if RubyProf.running? - end + result = RubyProf.profile(&block) + write_profile_report(report_filename, result) + rescue => e + logger.error("Profiling failed: #{e.message}") + # Still execute the block even if profiling fails + block.call unless result end - def write_profile_report(report_filename) - result = RubyProf.stop + def write_profile_report(report_filename, result) File.open(File.join(public_dir, report_filename), 'w') do |f| RubyProf::GraphHtmlPrinter.new(result).print(f, min_percent: 2) end diff --git a/app/controllers/items_controller.rb b/app/controllers/items_controller.rb index 672cf7e..bfe4208 100644 --- a/app/controllers/items_controller.rb +++ b/app/controllers/items_controller.rb @@ -55,7 +55,7 @@ def processing def paginate_items Item.scan_for_new_items! - @pagy, @items = pagy(items) + @pagy, @items = pagy(:offset, items) response.headers['Current-Page-Items'] = @items.count end diff --git a/app/views/application/standard_error.json.jbuilder b/app/views/application/standard_error.json.jbuilder index 5483bc3..6761a95 100644 --- a/app/views/application/standard_error.json.jbuilder +++ b/app/views/application/standard_error.json.jbuilder @@ -1,6 +1,6 @@ json.success(false) json.error do - json.code(Rack::Utils.status_code(status)) - json.message(message) + json.code(Rack::Utils.status_code(local_assigns[:status])) + json.message(local_assigns[:message]) json.errors([{ location: request.original_fullpath }]) end diff --git a/app/views/application/validation_errors.json.jbuilder b/app/views/application/validation_errors.json.jbuilder index 5c904c4..c0fece7 100644 --- a/app/views/application/validation_errors.json.jbuilder +++ b/app/views/application/validation_errors.json.jbuilder @@ -1,8 +1,8 @@ json.success(false) json.error do - json.code(Rack::Utils.status_code(status)) + json.code(Rack::Utils.status_code(local_assigns[:status])) json.errors do - json.array!(errors) do |error| + json.array!(local_assigns[:errors]) do |error| json.type error.type json.attribute error.attribute json.message error.full_message From 5aec166e3ef18aab1436609d9b37ff7a6aed1a9d Mon Sep 17 00:00:00 2001 From: David Zuckerman Date: Mon, 23 Feb 2026 07:47:21 -0800 Subject: [PATCH 03/36] Pagy uses pagy.limit now for number of items on page --- app/javascript/items/api/items.js | 4 ++-- app/javascript/items/components/ItemPaging.vue | 4 ++-- config/initializers/pagy.rb | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/app/javascript/items/api/items.js b/app/javascript/items/api/items.js index 7293987..f3c4604 100644 --- a/app/javascript/items/api/items.js +++ b/app/javascript/items/api/items.js @@ -58,7 +58,7 @@ function pagingFromResponse (response) { const paging = { currentPage: getInt(headers, 'current-page', 1), totalPages: getInt(headers, 'total-pages', 1), - itemsPerPage: getInt(headers, 'page-items', 0), + itemsPerPage: getInt(headers, 'page-limit', 0), currentPageItems: getInt(headers, 'current-page-items', 0), totalItems: getInt(headers, 'total-count', 0) } @@ -71,7 +71,7 @@ function pagingFromResponse (response) { } const links = Link.parse(linkHeader) - for (const rel of ['first', 'prev', 'next', 'last']) { + for (const rel of ['first', 'previous', 'next', 'last']) { if (links.has('rel', rel)) { const urlStr = links.get('rel', rel)[0].uri paging[rel] = new URL(urlStr) diff --git a/app/javascript/items/components/ItemPaging.vue b/app/javascript/items/components/ItemPaging.vue index 1dfdc87..7f72e8d 100644 --- a/app/javascript/items/components/ItemPaging.vue +++ b/app/javascript/items/components/ItemPaging.vue @@ -19,11 +19,11 @@