DEV: Upgrade Rails to version 7.2

This commit is contained in:
Loïc Guitaut 2024-08-19 14:44:17 +02:00 committed by Loïc Guitaut
parent f4d0a77d5f
commit d6bec460a8
30 changed files with 93 additions and 151 deletions

14
Gemfile
View File

@ -6,13 +6,13 @@ source "https://rubygems.org"
gem "bootsnap", require: false, platform: :mri gem "bootsnap", require: false, platform: :mri
gem "actionmailer", "~> 7.1.0" gem "actionmailer", "~> 7.2.0"
gem "actionpack", "~> 7.1.0" gem "actionpack", "~> 7.2.0"
gem "actionview", "~> 7.1.0" gem "actionview", "~> 7.2.0"
gem "activemodel", "~> 7.1.0" gem "activemodel", "~> 7.2.0"
gem "activerecord", "~> 7.1.0" gem "activerecord", "~> 7.2.0"
gem "activesupport", "~> 7.1.0" gem "activesupport", "~> 7.2.0"
gem "railties", "~> 7.1.0" gem "railties", "~> 7.2.0"
gem "sprockets-rails" gem "sprockets-rails"
gem "json" gem "json"

View File

@ -1,28 +1,26 @@
GEM GEM
remote: https://rubygems.org/ remote: https://rubygems.org/
specs: specs:
actionmailer (7.1.5) actionmailer (7.2.2)
actionpack (= 7.1.5) actionpack (= 7.2.2)
actionview (= 7.1.5) actionview (= 7.2.2)
activejob (= 7.1.5) activejob (= 7.2.2)
activesupport (= 7.1.5) activesupport (= 7.2.2)
mail (~> 2.5, >= 2.5.4) mail (>= 2.8.0)
net-imap
net-pop
net-smtp
rails-dom-testing (~> 2.2) rails-dom-testing (~> 2.2)
actionpack (7.1.5) actionpack (7.2.2)
actionview (= 7.1.5) actionview (= 7.2.2)
activesupport (= 7.1.5) activesupport (= 7.2.2)
nokogiri (>= 1.8.5) nokogiri (>= 1.8.5)
racc racc
rack (>= 2.2.4) rack (>= 2.2.4, < 3.2)
rack-session (>= 1.0.1) rack-session (>= 1.0.1)
rack-test (>= 0.6.3) rack-test (>= 0.6.3)
rails-dom-testing (~> 2.2) rails-dom-testing (~> 2.2)
rails-html-sanitizer (~> 1.6) rails-html-sanitizer (~> 1.6)
actionview (7.1.5) useragent (~> 0.16)
activesupport (= 7.1.5) actionview (7.2.2)
activesupport (= 7.2.2)
builder (~> 3.1) builder (~> 3.1)
erubi (~> 1.11) erubi (~> 1.11)
rails-dom-testing (~> 2.2) rails-dom-testing (~> 2.2)
@ -31,28 +29,27 @@ GEM
actionview (>= 6.0.a) actionview (>= 6.0.a)
active_model_serializers (0.8.4) active_model_serializers (0.8.4)
activemodel (>= 3.0) activemodel (>= 3.0)
activejob (7.1.5) activejob (7.2.2)
activesupport (= 7.1.5) activesupport (= 7.2.2)
globalid (>= 0.3.6) globalid (>= 0.3.6)
activemodel (7.1.5) activemodel (7.2.2)
activesupport (= 7.1.5) activesupport (= 7.2.2)
activerecord (7.1.5) activerecord (7.2.2)
activemodel (= 7.1.5) activemodel (= 7.2.2)
activesupport (= 7.1.5) activesupport (= 7.2.2)
timeout (>= 0.4.0) timeout (>= 0.4.0)
activesupport (7.1.5) activesupport (7.2.2)
base64 base64
benchmark (>= 0.3) benchmark (>= 0.3)
bigdecimal bigdecimal
concurrent-ruby (~> 1.0, >= 1.0.2) concurrent-ruby (~> 1.0, >= 1.3.1)
connection_pool (>= 2.2.5) connection_pool (>= 2.2.5)
drb drb
i18n (>= 1.6, < 2) i18n (>= 1.6, < 2)
logger (>= 1.4.2) logger (>= 1.4.2)
minitest (>= 5.1) minitest (>= 5.1)
mutex_m
securerandom (>= 0.3) securerandom (>= 0.3)
tzinfo (~> 2.0) tzinfo (~> 2.0, >= 2.0.5)
addressable (2.8.7) addressable (2.8.7)
public_suffix (>= 2.0.2, < 7.0) public_suffix (>= 2.0.2, < 7.0)
annotate (3.2.0) annotate (3.2.0)
@ -263,7 +260,6 @@ GEM
multi_xml (0.7.1) multi_xml (0.7.1)
bigdecimal (~> 3.1) bigdecimal (~> 3.1)
mustache (1.1.1) mustache (1.1.1)
mutex_m (0.3.0)
net-http (0.5.0) net-http (0.5.0)
uri uri
net-imap (0.5.1) net-imap (0.5.1)
@ -363,7 +359,7 @@ GEM
rack (< 3) rack (< 3)
rack-test (2.1.0) rack-test (2.1.0)
rack (>= 1.3) rack (>= 1.3)
rackup (1.0.0) rackup (1.0.1)
rack (< 3) rack (< 3)
webrick webrick
rails-dom-testing (2.2.0) rails-dom-testing (2.2.0)
@ -380,10 +376,10 @@ GEM
rails_multisite (6.1.0) rails_multisite (6.1.0)
activerecord (>= 6.0) activerecord (>= 6.0)
railties (>= 6.0) railties (>= 6.0)
railties (7.1.5) railties (7.2.2)
actionpack (= 7.1.5) actionpack (= 7.2.2)
activesupport (= 7.1.5) activesupport (= 7.2.2)
irb irb (~> 1.13)
rackup (>= 1.0.0) rackup (>= 1.0.0)
rake (>= 12.2) rake (>= 12.2)
thor (~> 1.0, >= 1.2.2) thor (~> 1.0, >= 1.2.2)
@ -571,6 +567,7 @@ GEM
raindrops (~> 0.7) raindrops (~> 0.7)
uniform_notifier (1.16.0) uniform_notifier (1.16.0)
uri (1.0.2) uri (1.0.2)
useragent (0.16.10)
version_gem (1.1.4) version_gem (1.1.4)
web-push (3.0.1) web-push (3.0.1)
jwt (~> 2.0) jwt (~> 2.0)
@ -603,14 +600,14 @@ PLATFORMS
x86_64-linux x86_64-linux
DEPENDENCIES DEPENDENCIES
actionmailer (~> 7.1.0) actionmailer (~> 7.2.0)
actionpack (~> 7.1.0) actionpack (~> 7.2.0)
actionview (~> 7.1.0) actionview (~> 7.2.0)
actionview_precompiler actionview_precompiler
active_model_serializers (~> 0.8.3) active_model_serializers (~> 0.8.3)
activemodel (~> 7.1.0) activemodel (~> 7.2.0)
activerecord (~> 7.1.0) activerecord (~> 7.2.0)
activesupport (~> 7.1.0) activesupport (~> 7.2.0)
addressable addressable
annotate annotate
aws-sdk-s3 aws-sdk-s3
@ -699,7 +696,7 @@ DEPENDENCIES
rails-dom-testing rails-dom-testing
rails_failover rails_failover
rails_multisite rails_multisite
railties (~> 7.1.0) railties (~> 7.2.0)
rake rake
rb-fsevent rb-fsevent
rbtrace rbtrace

View File

@ -1,6 +1,7 @@
# frozen_string_literal: true # frozen_string_literal: true
class ApplicationRequest < ActiveRecord::Base class ApplicationRequest < ActiveRecord::Base
enum req_type: { enum :req_type,
{
http_total: 0, http_total: 0,
http_2xx: 1, http_2xx: 1,
http_background: 2, http_background: 2,

View File

@ -4,7 +4,7 @@ class DirectoryColumn < ActiveRecord::Base
self.ignored_columns = ["automatic"] # TODO: Remove when 20240212034010_drop_deprecated_columns has been promoted to pre-deploy self.ignored_columns = ["automatic"] # TODO: Remove when 20240212034010_drop_deprecated_columns has been promoted to pre-deploy
self.inheritance_column = nil self.inheritance_column = nil
enum type: { automatic: 0, user_field: 1, plugin: 2 }, _scopes: false enum :type, { automatic: 0, user_field: 1, plugin: 2 }, scopes: false
def self.automatic_column_names def self.automatic_column_names
@automatic_column_names ||= %i[ @automatic_column_names ||= %i[

View File

@ -3,7 +3,8 @@
class PostHotlinkedMedia < ActiveRecord::Base class PostHotlinkedMedia < ActiveRecord::Base
belongs_to :post belongs_to :post
belongs_to :upload belongs_to :upload
enum status: { enum :status,
{
downloaded: "downloaded", downloaded: "downloaded",
too_large: "too_large", too_large: "too_large",
download_failed: "download_failed", download_failed: "download_failed",

View File

@ -417,7 +417,7 @@ class RemoteTheme < ActiveRecord::Base
self.commits_behind = 0 self.commits_behind = 0
end end
transaction_block = -> do transaction_block = ->(*) do
# Destroy fields that no longer exist in the remote theme # Destroy fields that no longer exist in the remote theme
field_ids_to_destroy = theme.theme_fields.pluck(:id) - updated_fields.map { |tf| tf&.id } field_ids_to_destroy = theme.theme_fields.pluck(:id) - updated_fields.map { |tf| tf&.id }
ThemeField.where(id: field_ids_to_destroy).destroy_all ThemeField.where(id: field_ids_to_destroy).destroy_all

View File

@ -4,10 +4,10 @@ class ReviewableHistory < ActiveRecord::Base
belongs_to :reviewable belongs_to :reviewable
belongs_to :created_by, class_name: "User" belongs_to :created_by, class_name: "User"
enum status: { pending: 0, approved: 1, rejected: 2, ignored: 3, deleted: 4 } enum :status, { pending: 0, approved: 1, rejected: 2, ignored: 3, deleted: 4 }
alias_attribute :type, :reviewable_history_type alias_attribute :type, :reviewable_history_type
enum type: { created: 0, transitioned: 1, edited: 2, claimed: 3, unclaimed: 4 } enum :type, { created: 0, transitioned: 1, edited: 2, claimed: 3, unclaimed: 4 }
end end
# == Schema Information # == Schema Information

View File

@ -6,7 +6,7 @@ class ReviewableScore < ActiveRecord::Base
belongs_to :reviewed_by, class_name: "User" belongs_to :reviewed_by, class_name: "User"
belongs_to :meta_topic, class_name: "Topic" belongs_to :meta_topic, class_name: "Topic"
enum status: { pending: 0, agreed: 1, disagreed: 2, ignored: 3 } enum :status, { pending: 0, agreed: 1, disagreed: 2, ignored: 3 }
# To keep things simple the types correspond to `PostActionType` for backwards # To keep things simple the types correspond to `PostActionType` for backwards
# compatibility, but we can add extra reasons for scores. # compatibility, but we can add extra reasons for scores.

View File

@ -863,7 +863,7 @@ class Theme < ActiveRecord::Base
end end
def migrate_settings(start_transaction: true, fields: nil, allow_out_of_sequence_migration: false) def migrate_settings(start_transaction: true, fields: nil, allow_out_of_sequence_migration: false)
block = -> do block = ->(*) do
runner = ThemeSettingsMigrationsRunner.new(self) runner = ThemeSettingsMigrationsRunner.new(self)
results = results =
runner.run(fields:, raise_error_on_out_of_sequence: !allow_out_of_sequence_migration) runner.run(fields:, raise_error_on_out_of_sequence: !allow_out_of_sequence_migration)

View File

@ -238,31 +238,34 @@ class TopicTrackingState
end end
def self.new_filter_sql def self.new_filter_sql
TopicQuery ActiveRecord::Base.connection.to_sql(
.new_filter(Topic, treat_as_new_topic_clause_sql: treat_as_new_topic_clause) TopicQuery
.where_clause .new_filter(Topic, treat_as_new_topic_clause_sql: treat_as_new_topic_clause)
.ast .where_clause
.to_sql + " AND topics.created_at > :min_new_topic_date" + .ast,
" AND dismissed_topic_users.id IS NULL" ) + " AND topics.created_at > :min_new_topic_date" + " AND dismissed_topic_users.id IS NULL"
end end
def self.unread_filter_sql(whisperer: false) def self.unread_filter_sql(whisperer: false)
TopicQuery.unread_filter(Topic, whisperer: whisperer).where_clause.ast.to_sql ActiveRecord::Base.connection.to_sql(
TopicQuery.unread_filter(Topic, whisperer: whisperer).where_clause.ast,
)
end end
def self.treat_as_new_topic_clause def self.treat_as_new_topic_clause
User ActiveRecord::Base.connection.to_sql(
.where( User
"GREATEST(CASE .where(
"GREATEST(CASE
WHEN COALESCE(uo.new_topic_duration_minutes, :default_duration) = :always THEN u.created_at WHEN COALESCE(uo.new_topic_duration_minutes, :default_duration) = :always THEN u.created_at
WHEN COALESCE(uo.new_topic_duration_minutes, :default_duration) = :last_visit THEN COALESCE(u.previous_visit_at,u.created_at) WHEN COALESCE(uo.new_topic_duration_minutes, :default_duration) = :last_visit THEN COALESCE(u.previous_visit_at,u.created_at)
ELSE (:now::timestamp - INTERVAL '1 MINUTE' * COALESCE(uo.new_topic_duration_minutes, :default_duration)) ELSE (:now::timestamp - INTERVAL '1 MINUTE' * COALESCE(uo.new_topic_duration_minutes, :default_duration))
END, u.created_at, :min_date)", END, u.created_at, :min_date)",
treat_as_new_topic_params, treat_as_new_topic_params,
) )
.where_clause .where_clause
.ast .ast,
.to_sql )
end end
def self.treat_as_new_topic_params def self.treat_as_new_topic_params

View File

@ -52,7 +52,7 @@ class TranslationOverride < ActiveRecord::Base
validate :check_MF_string, if: :message_format? validate :check_MF_string, if: :message_format?
attribute :status, :integer attribute :status, :integer
enum status: { up_to_date: 0, outdated: 1, invalid_interpolation_keys: 2, deprecated: 3 } enum :status, { up_to_date: 0, outdated: 1, invalid_interpolation_keys: 2, deprecated: 3 }
scope :mf_locales, scope :mf_locales,
->(locale) { not_deprecated.where(locale: locale).where("translation_key LIKE '%_MF'") } ->(locale) { not_deprecated.where(locale: locale).where("translation_key LIKE '%_MF'") }

View File

@ -26,7 +26,7 @@ class UserOption < ActiveRecord::Base
scope :human_users, -> { where("user_id > 0") } scope :human_users, -> { where("user_id > 0") }
enum default_calendar: { none_selected: 0, ics: 1, google: 2 }, _scopes: false enum :default_calendar, { none_selected: 0, ics: 1, google: 2 }, scopes: false
def self.ensure_consistency! def self.ensure_consistency!
sql = <<~SQL sql = <<~SQL

View File

@ -18,7 +18,8 @@ class WebHookEventType < ActiveRecord::Base
TOPIC_VOTING = 17 TOPIC_VOTING = 17
CHAT_MESSAGE = 18 CHAT_MESSAGE = 18
enum group: { enum :group,
{
topic: 0, topic: 0,
post: 1, post: 1,
user: 2, user: 2,
@ -37,7 +38,7 @@ class WebHookEventType < ActiveRecord::Base
chat: 15, chat: 15,
custom: 16, custom: 16,
}, },
_scopes: false scopes: false
TYPES = { TYPES = {
topic_created: 101, topic_created: 101,

View File

@ -90,7 +90,8 @@ module Discourse
# tiny file needed by site settings # tiny file needed by site settings
require "highlight_js" require "highlight_js"
config.load_defaults 7.1 config.load_defaults 7.2
config.yjit = GlobalSetting.yjit_enabled
config.active_record.cache_versioning = false # our custom cache class doesn’t support this config.active_record.cache_versioning = false # our custom cache class doesn’t support this
config.action_controller.forgery_protection_origin_check = false config.action_controller.forgery_protection_origin_check = false
config.active_record.belongs_to_required_by_default = false config.active_record.belongs_to_required_by_default = false

View File

@ -405,3 +405,6 @@ log_line_max_chars = 160000
# Updating the value will allow site operators to invalidate all asset urls # Updating the value will allow site operators to invalidate all asset urls
# to recover from configuration issues which may have been cached by CDNs/browsers. # to recover from configuration issues which may have been cached by CDNs/browsers.
asset_url_salt = asset_url_salt =
# Enable Ruby YJIT to get better performances at the cost of using more memory.
yjit_enabled = false

View File

@ -2,10 +2,7 @@
# Multisite freedom patch defines RailsMultisite::DiscoursePatches.config which is used by 200-first_middlewares.rb # Multisite freedom patch defines RailsMultisite::DiscoursePatches.config which is used by 200-first_middlewares.rb
# Therefore it can not be postponed with .to_prepare # Therefore it can not be postponed with .to_prepare
RUN_WITHOUT_PREPARE = [ RUN_WITHOUT_PREPARE = ["#{Rails.root}/lib/freedom_patches/rails_multisite.rb"]
"#{Rails.root}/lib/freedom_patches/rails_multisite.rb",
"#{Rails.root}/lib/freedom_patches/rails_rack_logger_from_rails_7_2.rb",
]
RUN_WITHOUT_PREPARE.each { |path| require(path) } RUN_WITHOUT_PREPARE.each { |path| require(path) }
Rails.application.reloader.to_prepare do Rails.application.reloader.to_prepare do

View File

@ -44,7 +44,7 @@ if defined?(RailsFailover::ActiveRecord)
# Test connection to the master, and trigger master failover if needed # Test connection to the master, and trigger master failover if needed
ActiveRecord::Base.connected_to(role: ActiveRecord.writing_role) do ActiveRecord::Base.connected_to(role: ActiveRecord.writing_role) do
ActiveRecord::Base.connection.active? ActiveRecord::Base.connection.connect!.active?
rescue PG::ConnectionBad, PG::UnableToSend, PG::ServerError rescue PG::ConnectionBad, PG::UnableToSend, PG::ServerError
RailsFailover::ActiveRecord.verify_primary(ActiveRecord.writing_role) RailsFailover::ActiveRecord.verify_primary(ActiveRecord.writing_role)
end end

View File

@ -3,7 +3,7 @@
# On initialize, reset flags cache # On initialize, reset flags cache
Rails.application.config.to_prepare do Rails.application.config.to_prepare do
if Discourse.cache.is_a?(Cache) && if Discourse.cache.is_a?(Cache) &&
!ActiveRecord::Base.connection.migration_context.needs_migration? !ActiveRecord::Base.connection_pool.migration_context.needs_migration?
Flag.reset_flag_settings! Flag.reset_flag_settings!
end end
end end

View File

@ -1,58 +0,0 @@
# frozen_string_literal: true
# TODO: Drop this patch when upgrading to Rails 7.2
#
# Here we use the code from Rails 7.2 because the code from Rails 7.1 has a
# nasty bug that happens when there is more than one tagged logger in the
# broadcast logger.
# The Rails 7.1 implementation calls `#call_app` as many times as there are
# tagged loggers, which leads to all sort of strange behaviors.
module RailsRackLoggerFromRails7_2
extend ActiveSupport::Concern
def call(env)
request = ActionDispatch::Request.new(env)
env["rails.rack_logger_tag_count"] = if logger.respond_to?(:push_tags)
logger.push_tags(*compute_tags(request)).size
else
0
end
call_app(request, env)
end
private
def call_app(request, env) # :doc:
logger_tag_pop_count = env["rails.rack_logger_tag_count"]
instrumenter = ActiveSupport::Notifications.instrumenter
handle = instrumenter.build_handle("request.action_dispatch", { request: request })
handle.start
logger.info { started_request_message(request) }
status, headers, body = response = @app.call(env)
body =
::Rack::BodyProxy.new(body) { finish_request_instrumentation(handle, logger_tag_pop_count) }
if response.frozen?
[status, headers, body]
else
response[2] = body
response
end
rescue Exception
finish_request_instrumentation(handle, logger_tag_pop_count)
raise
end
def finish_request_instrumentation(handle, logger_tag_pop_count)
handle.finish
if logger.respond_to?(:pop_tags) && logger_tag_pop_count > 0
logger.pop_tags(logger_tag_pop_count)
end
ActiveSupport::LogSubscriber.flush_all!
end
end
Rails::Rack::Logger.prepend(RailsRackLoggerFromRails7_2)

View File

@ -70,7 +70,7 @@ end
task "db:rollback" => %w[environment set_locale] do |_, args| task "db:rollback" => %w[environment set_locale] do |_, args|
step = ENV["STEP"] ? ENV["STEP"].to_i : 1 step = ENV["STEP"] ? ENV["STEP"].to_i : 1
ActiveRecord::Base.connection.migration_context.rollback(step) ActiveRecord::Base.connection_pool.migration_context.rollback(step)
Rake::Task["db:_dump"].invoke Rake::Task["db:_dump"].invoke
end end
@ -236,7 +236,7 @@ task "db:migrate" => %w[
redis: Discourse.redis.without_namespace, redis: Discourse.redis.without_namespace,
validity: 300, validity: 300,
) do ) do
migrations = ActiveRecord::Base.connection.migration_context.migrations migrations = ActiveRecord::Base.connection_pool.migration_context.migrations
now_timestamp = Time.now.utc.strftime("%Y%m%d%H%M%S").to_i now_timestamp = Time.now.utc.strftime("%Y%m%d%H%M%S").to_i
epoch_timestamp = Time.at(0).utc.strftime("%Y%m%d%H%M%S").to_i epoch_timestamp = Time.at(0).utc.strftime("%Y%m%d%H%M%S").to_i

View File

@ -9,15 +9,11 @@ class Poll < ActiveRecord::Base
has_many :poll_options, -> { order(:id) }, dependent: :destroy has_many :poll_options, -> { order(:id) }, dependent: :destroy
has_many :poll_votes has_many :poll_votes
enum type: { regular: 0, multiple: 1, number: 2, ranked_choice: 3 }, _scopes: false enum :type, { regular: 0, multiple: 1, number: 2, ranked_choice: 3 }, scopes: false
enum :status, { open: 0, closed: 1 }, scopes: false
enum status: { open: 0, closed: 1 }, _scopes: false enum :results, { always: 0, on_vote: 1, on_close: 2, staff_only: 3 }, scopes: false
enum :visibility, { secret: 0, everyone: 1 }, scopes: false
enum results: { always: 0, on_vote: 1, on_close: 2, staff_only: 3 }, _scopes: false enum :chart_type, { bar: 0, pie: 1 }, scopes: false
enum visibility: { secret: 0, everyone: 1 }, _scopes: false
enum chart_type: { bar: 0, pie: 1 }, _scopes: false
validates :min, numericality: { allow_nil: true, only_integer: true, greater_than_or_equal_to: 0 } validates :min, numericality: { allow_nil: true, only_integer: true, greater_than_or_equal_to: 0 }
validates :max, numericality: { allow_nil: true, only_integer: true, greater_than: 0 } validates :max, numericality: { allow_nil: true, only_integer: true, greater_than: 0 }

View File

@ -13,8 +13,8 @@ RSpec.describe Migration::SafeMigrate do
ActiveRecord::Migrator.new( ActiveRecord::Migrator.new(
:up, :up,
migrations, migrations,
ActiveRecord::Base.connection.schema_migration, ActiveRecord::Base.connection_pool.schema_migration,
ActiveRecord::Base.connection.internal_metadata, ActiveRecord::Base.connection_pool.internal_metadata,
migrations.first.version, migrations.first.version,
).run ).run
end end