diff --git a/Gemfile b/Gemfile index 199f8263..4128be1c 100644 --- a/Gemfile +++ b/Gemfile @@ -5,7 +5,7 @@ git_source(:github) { |repo| "https://github.com/#{repo}.git" } ruby ">= 3.1.4", "< 3.5" -gem "rails", "~> 7.2.2" +gem "rails", "~> 8.1.1" gem "mysql2", "~> 0.5.6" # Use Puma as the app server diff --git a/Gemfile.lock b/Gemfile.lock index 5bd02fe8..4bdece2f 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -19,46 +19,48 @@ GIT GEM remote: https://rubygems.org/ specs: - actioncable (7.2.2.2) - actionpack (= 7.2.2.2) - activesupport (= 7.2.2.2) + 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 (7.2.2.2) - actionpack (= 7.2.2.2) - activejob (= 7.2.2.2) - activerecord (= 7.2.2.2) - activestorage (= 7.2.2.2) - activesupport (= 7.2.2.2) + 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 (7.2.2.2) - actionpack (= 7.2.2.2) - actionview (= 7.2.2.2) - activejob (= 7.2.2.2) - activesupport (= 7.2.2.2) + 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 (7.2.2.2) - actionview (= 7.2.2.2) - activesupport (= 7.2.2.2) + actionpack (8.1.1) + actionview (= 8.1.1) + activesupport (= 8.1.1) nokogiri (>= 1.8.5) - racc - rack (>= 2.2.4, < 3.2) + rack (>= 2.2.4) rack-session (>= 1.0.1) rack-test (>= 0.6.3) rails-dom-testing (~> 2.2) rails-html-sanitizer (~> 1.6) useragent (~> 0.16) - actiontext (7.2.2.2) - actionpack (= 7.2.2.2) - activerecord (= 7.2.2.2) - activestorage (= 7.2.2.2) - activesupport (= 7.2.2.2) + 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 (7.2.2.2) - activesupport (= 7.2.2.2) + actionview (8.1.1) + activesupport (= 8.1.1) builder (~> 3.1) erubi (~> 1.11) rails-dom-testing (~> 2.2) @@ -66,39 +68,40 @@ GEM active_link_to (1.0.5) actionpack addressable - activejob (7.2.2.2) - activesupport (= 7.2.2.2) + activejob (8.1.1) + activesupport (= 8.1.1) globalid (>= 0.3.6) - activemodel (7.2.2.2) - activesupport (= 7.2.2.2) - activerecord (7.2.2.2) - activemodel (= 7.2.2.2) - activesupport (= 7.2.2.2) + 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 (7.2.2.2) - actionpack (= 7.2.2.2) - activejob (= 7.2.2.2) - activerecord (= 7.2.2.2) - activesupport (= 7.2.2.2) + activestorage (8.1.1) + actionpack (= 8.1.1) + activejob (= 8.1.1) + activerecord (= 8.1.1) + activesupport (= 8.1.1) marcel (~> 1.0) - activesupport (7.2.2.2) + 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) tzinfo (~> 2.0, >= 2.0.5) + uri (>= 0.13.1) addressable (2.8.7) public_suffix (>= 2.0.2, < 7.0) ast (2.4.3) base64 (0.3.0) - benchmark (0.4.1) - bigdecimal (3.3.0) + benchmark (0.5.0) + bigdecimal (3.3.1) bindex (0.8.1) bootsnap (1.18.6) msgpack (~> 1.2) @@ -123,10 +126,10 @@ GEM crass (1.0.6) cssbundling-rails (1.4.3) railties (>= 6.0.0) - date (3.4.1) + date (3.5.0) deep_merge (1.2.2) drb (2.2.3) - erb (5.0.3) + erb (5.1.3) erubi (1.13.1) execjs (2.10.0) ffi (1.17.2-aarch64-linux-gnu) @@ -135,7 +138,7 @@ GEM ffi (1.17.2-x86_64-darwin) ffi (1.17.2-x86_64-linux-gnu) ffi (1.17.2-x86_64-linux-musl) - globalid (1.2.1) + globalid (1.3.0) activesupport (>= 6.1) haml (6.3.0) temple (>= 0.8.2) @@ -153,7 +156,7 @@ GEM mini_magick (>= 4.9.5, < 6) ruby-vips (>= 2.0.17, < 3) 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) @@ -178,12 +181,13 @@ GEM loofah (2.24.1) 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 - marcel (1.0.4) + marcel (1.1.0) matrix (0.4.2) mimemagic (0.4.3) nokogiri (~> 1) @@ -195,7 +199,7 @@ GEM minitest (5.26.0) msgpack (1.8.0) mysql2 (0.5.6) - net-imap (0.5.9) + net-imap (0.5.12) date net-protocol net-pop (0.1.2) @@ -204,18 +208,18 @@ GEM timeout net-smtp (0.5.1) net-protocol - nio4r (2.7.4) - nokogiri (1.18.9-aarch64-linux-gnu) + nio4r (2.7.5) + nokogiri (1.18.10-aarch64-linux-gnu) racc (~> 1.4) - nokogiri (1.18.9-arm-linux-gnu) + nokogiri (1.18.10-arm-linux-gnu) racc (~> 1.4) - nokogiri (1.18.9-arm64-darwin) + nokogiri (1.18.10-arm64-darwin) racc (~> 1.4) - nokogiri (1.18.9-x86_64-darwin) + nokogiri (1.18.10-x86_64-darwin) racc (~> 1.4) - nokogiri (1.18.9-x86_64-linux-gnu) + nokogiri (1.18.10-x86_64-linux-gnu) racc (~> 1.4) - nokogiri (1.18.9-x86_64-linux-musl) + nokogiri (1.18.10-x86_64-linux-musl) racc (~> 1.4) ostruct (0.6.3) parallel (1.27.0) @@ -226,7 +230,7 @@ GEM rack (>= 1.6.13) rackup (>= 1.0.1) rake (>= 12.3.3) - pp (0.6.2) + pp (0.6.3) prettyprint prettyprint (0.2.0) prism (1.6.0) @@ -237,7 +241,7 @@ GEM puma (6.6.1) nio4r (~> 2.0) racc (1.8.1) - rack (3.1.18) + rack (3.2.4) rack-session (2.1.1) base64 (>= 0.1.0) rack (>= 3.0.0) @@ -245,20 +249,20 @@ GEM rack (>= 1.3) rackup (2.2.1) rack (>= 3) - rails (7.2.2.2) - actioncable (= 7.2.2.2) - actionmailbox (= 7.2.2.2) - actionmailer (= 7.2.2.2) - actionpack (= 7.2.2.2) - actiontext (= 7.2.2.2) - actionview (= 7.2.2.2) - activejob (= 7.2.2.2) - activemodel (= 7.2.2.2) - activerecord (= 7.2.2.2) - activestorage (= 7.2.2.2) - activesupport (= 7.2.2.2) + 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 (= 7.2.2.2) + railties (= 8.1.1) rails-dom-testing (2.3.0) activesupport (>= 5.0.0) minitest @@ -266,23 +270,24 @@ 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) - rails-i18n (7.0.10) + rails-i18n (8.0.2) i18n (>= 0.7, < 2) - railties (>= 6.0.0, < 8) - railties (7.2.2.2) - actionpack (= 7.2.2.2) - activesupport (= 7.2.2.2) + railties (>= 8.0.0, < 9) + railties (8.1.1) + actionpack (= 8.1.1) + activesupport (= 8.1.1) irb (~> 1.13) rackup (>= 1.0.0) rake (>= 12.2) thor (~> 1.0, >= 1.2.2) + tsort (>= 0.2) zeitwerk (~> 2.6) rainbow (3.1.1) - rake (13.3.0) + rake (13.3.1) rb-fsevent (0.11.2) rb-inotify (0.11.1) ffi (~> 1.0) - rdoc (6.15.0) + rdoc (6.15.1) erb psych (>= 4.0.0) tsort @@ -369,7 +374,7 @@ GEM temple (0.10.3) thor (1.4.0) tilt (2.6.0) - timeout (0.4.3) + timeout (0.4.4) tsort (0.2.0) turbo-rails (2.0.16) actionpack (>= 7.1.0) @@ -381,6 +386,7 @@ GEM unicode-display_width (3.2.0) unicode-emoji (~> 4.1) unicode-emoji (4.1.0) + uri (1.1.1) useragent (0.16.11) web-console (4.2.1) actionview (>= 6.0.0) @@ -419,7 +425,7 @@ DEPENDENCIES mysql2 (~> 0.5.6) passenger (~> 6.0, >= 6.0.27) puma (~> 6.6) - rails (~> 7.2.2) + rails (~> 8.1.1) rdoc (>= 6.6.3.1) rollbar rubocop diff --git a/bin/ci b/bin/ci new file mode 100755 index 00000000..4137ad5b --- /dev/null +++ b/bin/ci @@ -0,0 +1,6 @@ +#!/usr/bin/env ruby +require_relative "../config/boot" +require "active_support/continuous_integration" + +CI = ActiveSupport::ContinuousIntegration +require_relative "../config/ci.rb" diff --git a/bin/dev b/bin/dev index ad72c7d5..d42bbaac 100755 --- a/bin/dev +++ b/bin/dev @@ -1,5 +1,4 @@ #!/usr/bin/env sh - if ! gem list foreman -i --silent; then echo "Installing foreman..." gem install foreman @@ -14,3 +13,4 @@ export RUBY_DEBUG_OPEN="true" export RUBY_DEBUG_LAZY="true" exec foreman start -f Procfile.dev "$@" +# exec "./bin/rails", "server", *ARGV diff --git a/bin/rubocop b/bin/rubocop index b3801537..caeb771d 100755 --- a/bin/rubocop +++ b/bin/rubocop @@ -24,7 +24,7 @@ end require "rubygems" require "bundler/setup" -# explicit rubocop config increases performance slightly while avoiding config confusion. +# Explicit RuboCop config increases performance slightly while avoiding config confusion. ARGV.unshift("--config", File.expand_path("../.rubocop.yml", __dir__)) load Gem.bin_path("rubocop", "rubocop") diff --git a/bin/setup b/bin/setup index c99da7c7..57fc1602 100755 --- a/bin/setup +++ b/bin/setup @@ -5,7 +5,7 @@ require "fileutils" APP_ROOT = File.expand_path("..", __dir__) def system!(*args) - system(*args) || abort("\n== Command #{args} failed ==") + system(*args, exception: true) || abort("\n== Command #{args} failed ==") end FileUtils.chdir APP_ROOT do @@ -17,6 +17,11 @@ FileUtils.chdir APP_ROOT do system! "gem install bundler --conservative" system("bundle check") || system!("bundle install") + # puts "\n== Copying sample files ==" + # unless File.exist?("config/database.yml") + # FileUtils.cp "config/database.yml.sample", "config/database.yml" + # end + puts "\n== Install JavaScript dependencies ==" system("yarn check --check-files") || system!("yarn install") @@ -26,9 +31,15 @@ FileUtils.chdir APP_ROOT do puts "\n== Preparing database ==" system! "bin/rails db:prepare" + system! "bin/rails db:reset" if ARGV.include?("--reset") + puts "\n== Removing old logs and tempfiles ==" system! "bin/rails log:clear tmp:clear" - puts "\n== Restarting application server ==" - system! "bin/rails restart" + unless ARGV.include?("--skip-server") + puts "\n== Starting development server ==" + STDOUT.flush # flush the output before exec(2) so that it displays + #exec "bin/dev" + system! "bin/rails restart" + end end diff --git a/config/application.rb b/config/application.rb index 0753a903..81f562ba 100644 --- a/config/application.rb +++ b/config/application.rb @@ -11,7 +11,7 @@ module HomeCms class Application < Rails::Application # Initialize configuration defaults for originally generated Rails version. - config.load_defaults 7.2 + config.load_defaults 8.1 # 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. @@ -20,17 +20,19 @@ class Application < Rails::Application # Configuration for the application, engines, and railties goes here. # - # Ensuring that ActiveStorage routes are loaded before Comfy's globbing - # route. Without this file serving routes are inaccessible. - config.railties_order = [ActiveStorage::Engine, :main_app, :all] - config.exceptions_app = routes - # These settings can be overridden in specific environments using the files # in config/environments, which are processed later. # # config.time_zone = "Central Time (US & Canada)" # config.eager_load_paths << Rails.root.join("extras") + # Begin CMS customizations + + # Ensuring that ActiveStorage routes are loaded before Comfy's globbing + # route. Without this file serving routes are inaccessible. + config.railties_order = [ActiveStorage::Engine, :main_app, :all] + config.exceptions_app = routes + # This is for the cms edit page preview and update buttons. # app/views/comfy/admin/cms/pages/_form.html.haml # https://github.com/ualbertalib/library-cms/issues/378 diff --git a/config/ci.rb b/config/ci.rb new file mode 100644 index 00000000..4d1792da --- /dev/null +++ b/config/ci.rb @@ -0,0 +1,23 @@ +# Run using bin/ci + +# frozen_string_literal: true + +CI.run do + step "Setup", "bin/setup --skip-server" + + step "Style: Ruby", "bin/rubocop" + + step "Security: Importmap vulnerability audit", "bin/importmap audit" + + step "Tests: Rails", "bin/rails test" + step "Tests: System", "bin/rails test:system" + step "Tests: Seeds", "env RAILS_ENV=test bin/rails db:seed:replant" + + # Optional: set a green GitHub commit status to unblock PR merge. + # Requires the `gh` CLI and `gh extension install basecamp/gh-signoff`. + # if success? + # step "Signoff: All systems go. Ready for merge and deploy.", "gh signoff" + # else + # failure "Signoff: CI failed. Do not merge or deploy.", "Fix the issues and try again." + # end +end diff --git a/config/environments/development.rb b/config/environments/development.rb index cd737d79..b7a37bcb 100644 --- a/config/environments/development.rb +++ b/config/environments/development.rb @@ -5,9 +5,7 @@ Rails.application.configure do # Settings specified here will take precedence over those in config/application.rb. - # In the development environment your application's code is reloaded any time - # it changes. This slows down response time but is perfect for development - # since you don't have to restart the web server when you make code changes. + # Make code changes take effect immediately without server restart. config.enable_reloading = true # Do not eager load code on boot. @@ -19,32 +17,33 @@ # Enable server timing. config.server_timing = true - # Enable/disable caching. By default caching is disabled. - # Run rails dev:cache to toggle caching. + # Enable/disable Action Controller caching. By default Action Controller caching is disabled. + # Run rails dev:cache to toggle Action Controller caching. if Rails.root.join("tmp/caching-dev.txt").exist? config.action_controller.perform_caching = true config.action_controller.enable_fragment_cache_logging = true config.cache_store = :memory_store - config.public_file_server.headers = { - "Cache-Control" => "public, max-age=#{2.days.to_i}" - } + config.public_file_server.headers = {"cache-control" => "public, max-age=#{2.days.to_i}"} else config.action_controller.perform_caching = false config.cache_store = :null_store end + # Change to :null_store to avoid any caching. + # config.cache_store = :memory_store + # Store uploaded files on the local file system (see config/storage.yml for options). config.active_storage.service = :local # Don't care if the mailer can't send. config.action_mailer.raise_delivery_errors = false - # Disable caching for Action Mailer templates even if Action Controller - # caching is enabled. + # Make template changes take effect immediately. config.action_mailer.perform_caching = false + # Set localhost to be used by links generated in mailer templates. # config.action_mailer.default_url_options = { host: "localhost", port: 3000 } # Print deprecation notices to the Rails logger. @@ -62,17 +61,23 @@ # Highlight code that triggered database queries in logs. config.active_record.verbose_query_logs = true + # Append comments with runtime information tags to SQL queries in logs. + config.active_record.query_log_tags_enabled = true + # Highlight code that enqueued background job in logs. config.active_job.verbose_enqueue_logs = true # Suppress logger output for asset requests. config.assets.quiet = true + # Highlight code that triggered redirect in logs. + config.action_dispatch.verbose_redirect_logs = true + # Raises error for missing translations. # config.i18n.raise_on_missing_translations = true # Annotate rendered view with file names. - # config.action_view.annotate_rendered_view_with_filenames = true + config.action_view.annotate_rendered_view_with_filenames = true # Uncomment if you wish to allow Action Cable access from any origin. # config.action_cable.disable_request_forgery_protection = true diff --git a/config/environments/production.rb b/config/environments/production.rb index b3e1f471..fad62a88 100644 --- a/config/environments/production.rb +++ b/config/environments/production.rb @@ -8,19 +8,17 @@ # Code is not reloaded between requests. config.enable_reloading = false - # Eager load code on boot. This eager loads most of Rails and - # your application in memory, allowing both threaded web servers - # and those relying on copy on write to perform better. - # Rake tasks automatically ignore this option for performance. + # Eager load code on boot for better performance and memory savings (ignored by Rake tasks). config.eager_load = true - # Full error reports are disabled and caching is turned on. + # Full error reports are disabled. config.consider_all_requests_local = false + + # Turn on fragment caching in view templates. config.action_controller.perform_caching = true - # Ensures that a master key has been made available in ENV["RAILS_MASTER_KEY"], config/master.key, or an environment - # key such as config/credentials/production.key. This key is used to decrypt credentials (and other encrypted files). - # config.require_master_key = true + # Cache assets for far-future expiry since they are all digest stamped. + config.public_file_server.headers = {"cache-control" => "public, max-age=#{1.year.to_i}"} # Disable serving static files from `public/`, relying on NGINX/Apache to do so instead. # config.public_file_server.enabled = false @@ -35,20 +33,10 @@ # Enable serving of images, stylesheets, and JavaScripts from an asset server. # config.asset_host = "http://assets.example.com" - # Specifies the header that your server uses for sending files. - # config.action_dispatch.x_sendfile_header = "X-Sendfile" # for Apache - # config.action_dispatch.x_sendfile_header = "X-Accel-Redirect" # for NGINX - # Store uploaded files on the local file system (see config/storage.yml for options). config.active_storage.service = :local - # Mount Action Cable outside main process or domain. - # config.action_cable.mount_path = nil - # config.action_cable.url = "wss://example.com/cable" - # config.action_cable.allowed_request_origins = [ "http://example.com", /http:\/\/example.*/ ] - # Assume all access to the app is happening through a SSL-terminating reverse proxy. - # Can be used together with config.force_ssl for Strict-Transport-Security and secure cookies. # config.assume_ssl = true # Force all access to the app over SSL, use Strict-Transport-Security, and use secure cookies. @@ -57,34 +45,38 @@ # Skip http-to-https redirect for the default health check endpoint. # config.ssl_options = { redirect: { exclude: ->(request) { request.path == "/up" } } } - # Log to STDOUT by default - config.logger = ActiveSupport::Logger.new($stdout) - .tap { |logger| logger.formatter = ::Logger::Formatter.new } - .then { |logger| ActiveSupport::TaggedLogging.new(logger) } - - # Prepend all log lines with the following tags. + # Log to STDOUT with the current request id as a default log tag. config.log_tags = [:request_id] + config.logger = ActiveSupport::TaggedLogging.logger($stdout) - # "info" includes generic and useful information about system operation, but avoids logging too much - # information to avoid inadvertent exposure of personally identifiable information (PII). If you - # want to log everything, set the level to "debug". + # Change to "debug" to log everything (including potentially personally-identifiable information!). config.log_level = ENV.fetch("RAILS_LOG_LEVEL", "info") - # Use a different cache store in production. + # Prevent health checks from clogging up the logs. + config.silence_healthcheck_path = "/up" + + # Replace the default in-process memory cache store with a durable alternative. # config.cache_store = :mem_cache_store - # Use a real queuing backend for Active Job (and separate queues per environment). + # Replace the default in-process and non-durable queuing backend for Active Job. # config.active_job.queue_adapter = :resque - # config.active_job.queue_name_prefix = "home_cms_production" - - # Disable caching for Action Mailer templates even if Action Controller - # caching is enabled. - config.action_mailer.perform_caching = false # Ignore bad email addresses and do not raise email delivery errors. # Set this to true and configure the email server for immediate delivery to raise delivery errors. # config.action_mailer.raise_delivery_errors = false + # Set host to be used by links generated in mailer templates. + config.action_mailer.default_url_options = {host: "example.com"} + + # Specify outgoing SMTP server. Remember to add smtp/* credentials via bin/rails credentials:edit. + # config.action_mailer.smtp_settings = { + # user_name: Rails.application.credentials.dig(:smtp, :user_name), + # password: Rails.application.credentials.dig(:smtp, :password), + # address: "smtp.example.com", + # port: 587, + # authentication: :plain + # } + # Enable locale fallbacks for I18n (makes lookups for any locale fall back to # the I18n.default_locale when a translation cannot be found). config.i18n.fallbacks = true @@ -103,6 +95,7 @@ # "example.com", # Allow requests from example.com # /.*\.example\.com/ # Allow requests from subdomains like `www.example.com` # ] + # # Skip DNS rebinding protection for the default health check endpoint. # config.host_authorization = { exclude: ->(request) { request.path == "/up" } } end diff --git a/config/environments/staging.rb b/config/environments/staging.rb index 90a7a88a..13e5be08 100644 --- a/config/environments/staging.rb +++ b/config/environments/staging.rb @@ -1,55 +1,42 @@ # frozen_string_literal: true +require "active_support/core_ext/integer/time" + Rails.application.configure do # Settings specified here will take precedence over those in config/application.rb. # Code is not reloaded between requests. config.enable_reloading = false - # Eager load code on boot. This eager loads most of Rails and - # your application in memory, allowing both threaded web servers - # and those relying on copy on write to perform better. - # Rake tasks automatically ignore this option for performance. + # Eager load code on boot for better performance and memory savings (ignored by Rake tasks). config.eager_load = true - # Full error reports are disabled and caching is turned on. + # Full error reports are disabled. config.consider_all_requests_local = false + + # Turn on fragment caching in view templates. config.action_controller.perform_caching = true - # Ensures that a master key has been made available in ENV["RAILS_MASTER_KEY"], config/master.key, or an environment - # key such as config/credentials/production.key. This key is used to decrypt credentials (and other encrypted files). - # config.require_master_key = true + # Cache assets for far-future expiry since they are all digest stamped. + config.public_file_server.headers = {"cache-control" => "public, max-age=#{1.year.to_i}"} # Disable serving static files from `public/`, relying on NGINX/Apache to do so instead. # config.public_file_server.enabled = false config.public_file_server.enabled = ENV["RAILS_SERVE_STATIC_FILES"].present? - # Compress JavaScripts and CSS. + # Compress CSS using a preprocessor. # config.assets.css_compressor = :sass - config.assets.js_compressor = Uglifier.new(harmony: true) # Do not fall back to assets pipeline if a precompiled asset is missed. config.assets.compile = false - # `config.assets.precompile` and `config.assets.version` have moved to config/initializers/assets.rb - # Enable serving of images, stylesheets, and JavaScripts from an asset server. # config.asset_host = "http://assets.example.com" - # Specifies the header that your server uses for sending files. - # config.action_dispatch.x_sendfile_header = "X-Sendfile" # for Apache - # config.action_dispatch.x_sendfile_header = "X-Accel-Redirect" # for NGINX - # Store uploaded files on the local file system (see config/storage.yml for options). config.active_storage.service = :local - # Mount Action Cable outside main process or domain. - # config.action_cable.mount_path = nil - # config.action_cable.url = "wss://example.com/cable" - # config.action_cable.allowed_request_origins = [ "http://example.com", /http:\/\/example.*/ ] - # Assume all access to the app is happening through a SSL-terminating reverse proxy. - # Can be used together with config.force_ssl for Strict-Transport-Security and secure cookies. # config.assume_ssl = true # Force all access to the app over SSL, use Strict-Transport-Security, and use secure cookies. @@ -58,43 +45,44 @@ # Skip http-to-https redirect for the default health check endpoint. # config.ssl_options = { redirect: { exclude: ->(request) { request.path == "/up" } } } - # Log to STDOUT by default - config.logger = ActiveSupport::Logger.new($stdout) - .tap { |logger| logger.formatter = ::Logger::Formatter.new } - .then { |logger| ActiveSupport::TaggedLogging.new(logger) } - - # Prepend all log lines with the following tags. + # Log to STDOUT with the current request id as a default log tag. config.log_tags = [:request_id] + config.logger = ActiveSupport::TaggedLogging.logger($stdout) - # "info" includes generic and useful information about system operation, but avoids logging too much - # information to avoid inadvertent exposure of personally identifiable information (PII). If you - # want to log everything, set the level to "debug". + # Change to "debug" to log everything (including potentially personally-identifiable information!). config.log_level = ENV.fetch("RAILS_LOG_LEVEL", "debug") - # Use a different cache store in production. + # Prevent health checks from clogging up the logs. + config.silence_healthcheck_path = "/up" + + # Replace the default in-process memory cache store with a durable alternative. # config.cache_store = :mem_cache_store - # Use a real queuing backend for Active Job (and separate queues per environment). + # Replace the default in-process and non-durable queuing backend for Active Job. # config.active_job.queue_adapter = :resque - # config.active_job.queue_name_prefix = "home-cms_#{Rails.env}" - - # Disable caching for Action Mailer templates even if Action Controller - # caching is enabled. - config.action_mailer.perform_caching = false # Ignore bad email addresses and do not raise email delivery errors. # Set this to true and configure the email server for immediate delivery to raise delivery errors. # config.action_mailer.raise_delivery_errors = false + # Set host to be used by links generated in mailer templates. + config.action_mailer.default_url_options = {host: "example.com"} + + # Specify outgoing SMTP server. Remember to add smtp/* credentials via bin/rails credentials:edit. + # config.action_mailer.smtp_settings = { + # user_name: Rails.application.credentials.dig(:smtp, :user_name), + # password: Rails.application.credentials.dig(:smtp, :password), + # address: "smtp.example.com", + # port: 587, + # authentication: :plain + # } + # Enable locale fallbacks for I18n (makes lookups for any locale fall back to # the I18n.default_locale when a translation cannot be found). config.i18n.fallbacks = true # Don't log any deprecations. - # config.active_support.report_deprecations = false - - # Send deprecation notices to registered listeners. - config.active_support.deprecation = :notify + config.active_support.report_deprecations = true # Do not dump schema after migrations. config.active_record.dump_schema_after_migration = false @@ -107,6 +95,7 @@ # "example.com", # Allow requests from example.com # /.*\.example\.com/ # Allow requests from subdomains like `www.example.com` # ] + # # Skip DNS rebinding protection for the default health check endpoint. # config.host_authorization = { exclude: ->(request) { request.path == "/up" } } end diff --git a/config/environments/test.rb b/config/environments/test.rb index a8c122f8..6674dc17 100644 --- a/config/environments/test.rb +++ b/config/environments/test.rb @@ -19,21 +19,17 @@ # loading is working properly before deploying your code. config.eager_load = ENV["CI"].present? - # Configure public file server for tests with Cache-Control for performance. + # Configure public file server for tests with cache-control for performance. config.public_file_server.enabled = true - config.public_file_server.headers = { - "Cache-Control" => "public, max-age=#{1.hour.to_i}" - } + config.public_file_server.headers = {"cache-control" => "public, max-age=3600"} - # Show full error reports and disable caching. + # Show full error reports. config.consider_all_requests_local = true config.action_controller.perform_caching = false config.cache_store = :null_store # Render exception templates for rescuable exceptions and raise for other exceptions. - # config.action_dispatch.show_exceptions = :rescuable - # Raise exceptions instead of rendering exception templates. - config.action_dispatch.show_exceptions = false + config.action_dispatch.show_exceptions = :rescuable # Disable request forgery protection in test environment. config.action_controller.allow_forgery_protection = false @@ -41,18 +37,13 @@ # Store uploaded files on the local file system in a temporary directory. config.active_storage.service = :test - # Disable caching for Action Mailer templates even if Action Controller - # caching is enabled. - config.action_mailer.perform_caching = false - # Tell Action Mailer not to deliver emails to the real world. # The :test delivery method accumulates sent emails in the # ActionMailer::Base.deliveries array. config.action_mailer.delivery_method = :test - # Unlike controllers, the mailer instance doesn't have any context about the - # incoming request so you'll need to provide the :host parameter yourself. - # config.action_mailer.default_url_options = { host: "www.example.com" } + # Set host to be used by links generated in mailer templates. + # config.action_mailer.default_url_options = { host: "example.com" } # Print deprecation notices to the stderr. config.active_support.deprecation = :stderr diff --git a/config/initializers/assets.rb b/config/initializers/assets.rb index b97057ec..ac798051 100644 --- a/config/initializers/assets.rb +++ b/config/initializers/assets.rb @@ -8,8 +8,3 @@ # Add additional assets to the asset load path. # Rails.application.config.assets.paths << Emoji.images_path Rails.application.config.assets.paths << Rails.root.join("node_modules/bootstrap-icons/font") - -# Precompile additional assets. -# application.js, application.css, and all non-JS/CSS in the app/assets -# folder are already added. -# Rails.application.config.assets.precompile += %w[ admin.js admin.css ] diff --git a/config/initializers/content_security_policy.rb b/config/initializers/content_security_policy.rb index 35ab3fd6..74b18c5a 100644 --- a/config/initializers/content_security_policy.rb +++ b/config/initializers/content_security_policy.rb @@ -22,6 +22,10 @@ # config.content_security_policy_nonce_generator = ->(request) { request.session.id.to_s } # config.content_security_policy_nonce_directives = %w(script-src style-src) # +# # Automatically add `nonce` to `javascript_tag`, `javascript_include_tag`, and `stylesheet_link_tag` +# # if the corresponding directives are specified in `content_security_policy_nonce_directives`. +# # config.content_security_policy_nonce_auto = true +# # # Report violations without enforcing the policy. # # config.content_security_policy_report_only = true # end diff --git a/config/initializers/filter_parameter_logging.rb b/config/initializers/filter_parameter_logging.rb index e88b020f..497ac132 100644 --- a/config/initializers/filter_parameter_logging.rb +++ b/config/initializers/filter_parameter_logging.rb @@ -6,5 +6,5 @@ # Use this to limit dissemination of sensitive information. # See the ActiveSupport::ParameterFilter documentation for supported notations and behaviors. Rails.application.config.filter_parameters += [ - :passw, :email, :secret, :token, :_key, :crypt, :salt, :certificate, :otp, :ssn + :passw, :email, :secret, :token, :_key, :crypt, :salt, :certificate, :otp, :ssn, :cvv, :cvc ] diff --git a/config/puma.rb b/config/puma.rb index e52c10e6..b853cd6c 100644 --- a/config/puma.rb +++ b/config/puma.rb @@ -7,13 +7,18 @@ # This configuration file will be evaluated by Puma. The top-level methods that # are invoked here are part of Puma's configuration DSL. For more information # about methods provided by the DSL, see https://puma.io/puma/Puma/DSL.html. - +# # Puma starts a configurable number of processes (workers) and each process # serves each request in a thread from an internal thread pool. # +# You can control the number of workers using ENV["WEB_CONCURRENCY"]. You +# should only set this value when you want to run 2 or more workers. The +# default is already 1. You can set it to `auto` to automatically start a worker +# for each available processor. +# # The ideal number of threads per worker depends both on how much time the # application spends waiting for IO operations and on how much you wish to -# to prioritize throughput over latency. +# prioritize throughput over latency. # # As a rule of thumb, increasing the number of threads will increase how much # traffic a given process can handle (throughput), but due to CRuby's @@ -35,6 +40,9 @@ # Allow puma to be restarted by `bin/rails restart` command. plugin :tmp_restart +# Run the Solid Queue supervisor inside of Puma for single-server deployments. +plugin :solid_queue if ENV["SOLID_QUEUE_IN_PUMA"] + # Specify the PID file. Defaults to tmp/pids/server.pid in development. # In other environments, only set the PID file if requested. pidfile ENV["PIDFILE"] if ENV["PIDFILE"] diff --git a/db/schema.rb b/db/schema.rb index de98c181..16ab50af 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -10,25 +10,25 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema[7.1].define(version: 2024_07_25_183306) do +ActiveRecord::Schema[8.1].define(version: 2024_07_25_183306) do create_table "active_storage_attachments", charset: "utf8mb3", collation: "utf8mb3_general_ci", force: :cascade do |t| - t.string "name", null: false - t.string "record_type", null: false - t.bigint "record_id", null: false t.bigint "blob_id", null: false t.datetime "created_at", precision: nil, null: false + t.string "name", null: false + t.bigint "record_id", null: false + t.string "record_type", null: false t.index ["blob_id"], name: "index_active_storage_attachments_on_blob_id" t.index ["record_type", "record_id", "name", "blob_id"], name: "index_active_storage_attachments_uniqueness", unique: true end create_table "active_storage_blobs", charset: "utf8mb3", collation: "utf8mb3_general_ci", force: :cascade do |t| - t.string "key", null: false - t.string "filename", null: false - t.string "content_type" - t.text "metadata" t.bigint "byte_size", null: false t.string "checksum" + t.string "content_type" t.datetime "created_at", precision: nil, null: false + t.string "filename", null: false + t.string "key", null: false + t.text "metadata" t.string "service_name", null: false t.index ["key"], name: "index_active_storage_blobs_on_key", unique: true end @@ -40,38 +40,38 @@ end create_table "comfy_cms_categories", charset: "utf8mb3", collation: "utf8mb3_general_ci", force: :cascade do |t| - t.integer "site_id", null: false - t.string "label", null: false t.string "categorized_type", null: false + t.string "label", null: false + t.integer "site_id", null: false t.index ["site_id", "categorized_type", "label"], name: "index_cms_categories_on_site_id_and_cat_type_and_label", unique: true end create_table "comfy_cms_categorizations", charset: "utf8mb3", collation: "utf8mb3_general_ci", force: :cascade do |t| - t.integer "category_id", null: false - t.string "categorized_type", null: false t.integer "categorized_id", null: false + t.string "categorized_type", null: false + t.integer "category_id", null: false t.index ["category_id", "categorized_type", "categorized_id"], name: "index_cms_categorizations_on_cat_id_and_catd_type_and_catd_id", unique: true end create_table "comfy_cms_files", charset: "utf8mb3", collation: "utf8mb3_general_ci", force: :cascade do |t| - t.integer "site_id", null: false - t.string "label", default: "", null: false + t.datetime "created_at", precision: nil, null: false t.text "description" + t.string "label", default: "", null: false t.integer "position", default: 0, null: false - t.datetime "created_at", precision: nil, null: false + t.integer "site_id", null: false t.datetime "updated_at", precision: nil, null: false t.index ["site_id", "position"], name: "index_comfy_cms_files_on_site_id_and_position" end create_table "comfy_cms_fragments", charset: "utf8mb3", collation: "utf8mb3_general_ci", force: :cascade do |t| - t.string "record_type" - t.bigint "record_id" - t.string "identifier", null: false - t.string "tag", default: "text", null: false - t.text "content", size: :medium t.boolean "boolean", default: false, null: false - t.datetime "datetime", precision: nil + t.text "content", size: :medium t.datetime "created_at", precision: nil, null: false + t.datetime "datetime", precision: nil + t.string "identifier", null: false + t.bigint "record_id" + t.string "record_type" + t.string "tag", default: "text", null: false t.datetime "updated_at", precision: nil, null: false t.index ["boolean"], name: "index_comfy_cms_fragments_on_boolean" t.index ["datetime"], name: "index_comfy_cms_fragments_on_datetime" @@ -80,34 +80,34 @@ end create_table "comfy_cms_layouts", charset: "utf8mb3", collation: "utf8mb3_general_ci", force: :cascade do |t| - t.integer "site_id", null: false - t.integer "parent_id" t.string "app_layout" - t.string "label", null: false - t.string "identifier", null: false t.text "content", size: :medium + t.datetime "created_at", precision: nil, null: false t.text "css", size: :medium + t.string "identifier", null: false t.text "js", size: :medium + t.string "label", null: false + t.integer "parent_id" t.integer "position", default: 0, null: false - t.datetime "created_at", precision: nil, null: false + t.integer "site_id", null: false t.datetime "updated_at", precision: nil, null: false t.index ["parent_id", "position"], name: "index_comfy_cms_layouts_on_parent_id_and_position" t.index ["site_id", "identifier"], name: "index_comfy_cms_layouts_on_site_id_and_identifier", unique: true end create_table "comfy_cms_pages", charset: "utf8mb3", collation: "utf8mb3_general_ci", force: :cascade do |t| - t.integer "site_id", null: false + t.integer "children_count", default: 0, null: false + t.text "content_cache", size: :medium + t.datetime "created_at", precision: nil, null: false + t.string "full_path", null: false + t.boolean "is_published", default: true, null: false + t.string "label", null: false t.integer "layout_id" t.integer "parent_id" - t.integer "target_page_id" - t.string "label", null: false - t.string "slug" - t.string "full_path", null: false - t.text "content_cache", size: :medium t.integer "position", default: 0, null: false - t.integer "children_count", default: 0, null: false - t.boolean "is_published", default: true, null: false - t.datetime "created_at", precision: nil, null: false + t.integer "site_id", null: false + t.string "slug" + t.integer "target_page_id" t.datetime "updated_at", precision: nil, null: false t.index ["is_published"], name: "index_comfy_cms_pages_on_is_published" t.index ["parent_id", "position"], name: "index_comfy_cms_pages_on_parent_id_and_position" @@ -115,44 +115,44 @@ end create_table "comfy_cms_revisions", charset: "utf8mb3", collation: "utf8mb3_general_ci", force: :cascade do |t| - t.string "record_type", null: false - t.integer "record_id", null: false - t.text "data", size: :medium t.datetime "created_at", precision: nil + t.text "data", size: :medium + t.integer "record_id", null: false + t.string "record_type", null: false t.index ["record_type", "record_id", "created_at"], name: "index_cms_revisions_on_rtype_and_rid_and_created_at" end create_table "comfy_cms_sites", charset: "utf8mb3", collation: "utf8mb3_general_ci", force: :cascade do |t| - t.string "label", null: false - t.string "identifier", null: false + t.datetime "created_at", precision: nil, null: false t.string "hostname", null: false - t.string "path" + t.string "identifier", null: false + t.string "label", null: false t.string "locale", default: "en", null: false - t.datetime "created_at", precision: nil, null: false + t.string "path" t.datetime "updated_at", precision: nil, null: false t.index ["hostname"], name: "index_comfy_cms_sites_on_hostname" end create_table "comfy_cms_snippets", charset: "utf8mb3", collation: "utf8mb3_general_ci", force: :cascade do |t| - t.integer "site_id", null: false - t.string "label", null: false - t.string "identifier", null: false t.text "content", size: :medium - t.integer "position", default: 0, null: false t.datetime "created_at", precision: nil, null: false + t.string "identifier", null: false + t.string "label", null: false + t.integer "position", default: 0, null: false + t.integer "site_id", null: false t.datetime "updated_at", precision: nil, null: false t.index ["site_id", "identifier"], name: "index_comfy_cms_snippets_on_site_id_and_identifier", unique: true t.index ["site_id", "position"], name: "index_comfy_cms_snippets_on_site_id_and_position" end create_table "comfy_cms_translations", charset: "utf8mb3", collation: "utf8mb3_general_ci", force: :cascade do |t| - t.string "locale", null: false - t.integer "page_id", null: false - t.integer "layout_id" - t.string "label", null: false t.text "content_cache", size: :medium - t.boolean "is_published", default: true, null: false t.datetime "created_at", precision: nil, null: false + t.boolean "is_published", default: true, null: false + t.string "label", null: false + t.integer "layout_id" + t.string "locale", null: false + t.integer "page_id", null: false t.datetime "updated_at", precision: nil, null: false t.index ["is_published"], name: "index_comfy_cms_translations_on_is_published" t.index ["locale"], name: "index_comfy_cms_translations_on_locale"