DEV: Upgrade Discourse to Rails 6 (#8083)

* Adjustments to pass specs on Rails 6.0.0
* Use classic autoloader instead of Zeitwerk
* Update Rails 6.0.0 deprecated methods
* Rails 6.0.0 not allowing column with integer name
* Drop freedom_patches/rails6.rb
* Default value for trigger_transactional_callbacks? is true
* Bump rspec-rails version to 4.0.0.beta2
This commit is contained in:
Krzysztof Kotlarek 2019-09-12 10:41:50 +10:00 committed by Sam
parent eeb84806bc
commit 32b8a2ccff
17 changed files with 80 additions and 185 deletions

16
Gemfile
View File

@ -16,13 +16,13 @@ if rails_master?
else else
# until rubygems gives us optional dependencies we are stuck with this # until rubygems gives us optional dependencies we are stuck with this
# bundle update actionmailer actionpack actionview activemodel activerecord activesupport railties # bundle update actionmailer actionpack actionview activemodel activerecord activesupport railties
gem 'actionmailer', '5.2.3' gem 'actionmailer', '6.0.0'
gem 'actionpack', '5.2.3' gem 'actionpack', '6.0.0'
gem 'actionview', '5.2.3' gem 'actionview', '6.0.0'
gem 'activemodel', '5.2.3' gem 'activemodel', '6.0.0'
gem 'activerecord', '5.2.3' gem 'activerecord', '6.0.0'
gem 'activesupport', '5.2.3' gem 'activesupport', '6.0.0'
gem 'railties', '5.2.3' gem 'railties', '6.0.0'
gem 'sprockets-rails' gem 'sprockets-rails'
end end
@ -140,7 +140,7 @@ group :test, :development do
gem 'mocha', require: false gem 'mocha', require: false
gem 'rb-fsevent', require: RUBY_PLATFORM =~ /darwin/i ? 'rb-fsevent' : false gem 'rb-fsevent', require: RUBY_PLATFORM =~ /darwin/i ? 'rb-fsevent' : false
gem 'rb-inotify', '~> 0.9', require: RUBY_PLATFORM =~ /linux/i ? 'rb-inotify' : false gem 'rb-inotify', '~> 0.9', require: RUBY_PLATFORM =~ /linux/i ? 'rb-inotify' : false
gem 'rspec-rails', require: false gem 'rspec-rails', '4.0.0.beta2', require: false
gem 'shoulda-matchers', '~> 3.1', '>= 3.1.3', require: false gem 'shoulda-matchers', '~> 3.1', '>= 3.1.3', require: false
gem 'rspec-html-matchers' gem 'rspec-html-matchers'
gem 'pry-nav' gem 'pry-nav'

View File

@ -1,47 +1,46 @@
GEM GEM
remote: https://rubygems.org/ remote: https://rubygems.org/
specs: specs:
actionmailer (5.2.3) actionmailer (6.0.0)
actionpack (= 5.2.3) actionpack (= 6.0.0)
actionview (= 5.2.3) actionview (= 6.0.0)
activejob (= 5.2.3) activejob (= 6.0.0)
mail (~> 2.5, >= 2.5.4) mail (~> 2.5, >= 2.5.4)
rails-dom-testing (~> 2.0) rails-dom-testing (~> 2.0)
actionpack (5.2.3) actionpack (6.0.0)
actionview (= 5.2.3) actionview (= 6.0.0)
activesupport (= 5.2.3) activesupport (= 6.0.0)
rack (~> 2.0) rack (~> 2.0)
rack-test (>= 0.6.3) rack-test (>= 0.6.3)
rails-dom-testing (~> 2.0) rails-dom-testing (~> 2.0)
rails-html-sanitizer (~> 1.0, >= 1.0.2) rails-html-sanitizer (~> 1.0, >= 1.2.0)
actionview (5.2.3) actionview (6.0.0)
activesupport (= 5.2.3) activesupport (= 6.0.0)
builder (~> 3.1) builder (~> 3.1)
erubi (~> 1.4) erubi (~> 1.4)
rails-dom-testing (~> 2.0) rails-dom-testing (~> 2.0)
rails-html-sanitizer (~> 1.0, >= 1.0.3) rails-html-sanitizer (~> 1.1, >= 1.2.0)
active_model_serializers (0.8.4) active_model_serializers (0.8.4)
activemodel (>= 3.0) activemodel (>= 3.0)
activejob (5.2.3) activejob (6.0.0)
activesupport (= 5.2.3) activesupport (= 6.0.0)
globalid (>= 0.3.6) globalid (>= 0.3.6)
activemodel (5.2.3) activemodel (6.0.0)
activesupport (= 5.2.3) activesupport (= 6.0.0)
activerecord (5.2.3) activerecord (6.0.0)
activemodel (= 5.2.3) activemodel (= 6.0.0)
activesupport (= 5.2.3) activesupport (= 6.0.0)
arel (>= 9.0) activesupport (6.0.0)
activesupport (5.2.3)
concurrent-ruby (~> 1.0, >= 1.0.2) concurrent-ruby (~> 1.0, >= 1.0.2)
i18n (>= 0.7, < 2) i18n (>= 0.7, < 2)
minitest (~> 5.1) minitest (~> 5.1)
tzinfo (~> 1.1) tzinfo (~> 1.1)
zeitwerk (~> 2.1, >= 2.1.8)
addressable (2.5.2) addressable (2.5.2)
public_suffix (>= 2.0.2, < 4.0) public_suffix (>= 2.0.2, < 4.0)
annotate (2.7.5) annotate (2.7.5)
activerecord (>= 3.2, < 7.0) activerecord (>= 3.2, < 7.0)
rake (>= 10.4, < 13.0) rake (>= 10.4, < 13.0)
arel (9.0.0)
ast (2.4.0) ast (2.4.0)
aws-eventstream (1.0.3) aws-eventstream (1.0.3)
aws-partitions (1.154.0) aws-partitions (1.154.0)
@ -183,7 +182,7 @@ GEM
rack (>= 1.1.3) rack (>= 1.1.3)
metaclass (0.0.4) metaclass (0.0.4)
method_source (0.9.2) method_source (0.9.2)
mini_mime (1.0.1) mini_mime (1.0.2)
mini_portile2 (2.4.0) mini_portile2 (2.4.0)
mini_racer (0.2.6) mini_racer (0.2.6)
libv8 (>= 6.9.411) libv8 (>= 6.9.411)
@ -282,20 +281,20 @@ GEM
rails-dom-testing (2.0.3) rails-dom-testing (2.0.3)
activesupport (>= 4.2.0) activesupport (>= 4.2.0)
nokogiri (>= 1.6) nokogiri (>= 1.6)
rails-html-sanitizer (1.0.4) rails-html-sanitizer (1.2.0)
loofah (~> 2.2, >= 2.2.2) loofah (~> 2.2, >= 2.2.2)
rails_multisite (2.0.7) rails_multisite (2.0.7)
activerecord (> 4.2, < 7) activerecord (> 4.2, < 7)
railties (> 4.2, < 7) railties (> 4.2, < 7)
railties (5.2.3) railties (6.0.0)
actionpack (= 5.2.3) actionpack (= 6.0.0)
activesupport (= 5.2.3) activesupport (= 6.0.0)
method_source method_source
rake (>= 0.8.7) rake (>= 0.8.7)
thor (>= 0.19.0, < 2.0) thor (>= 0.20.3, < 2.0)
rainbow (3.0.0) rainbow (3.0.0)
raindrops (0.19.0) raindrops (0.19.0)
rake (12.3.2) rake (12.3.3)
rake-compiler (1.0.7) rake-compiler (1.0.7)
rake rake
rb-fsevent (0.10.3) rb-fsevent (0.10.3)
@ -330,14 +329,14 @@ GEM
rspec-mocks (3.8.0) rspec-mocks (3.8.0)
diff-lcs (>= 1.2.0, < 2.0) diff-lcs (>= 1.2.0, < 2.0)
rspec-support (~> 3.8.0) rspec-support (~> 3.8.0)
rspec-rails (3.8.2) rspec-rails (4.0.0.beta2)
actionpack (>= 3.0) actionpack (>= 4.2)
activesupport (>= 3.0) activesupport (>= 4.2)
railties (>= 3.0) railties (>= 4.2)
rspec-core (~> 3.8.0) rspec-core (~> 3.8)
rspec-expectations (~> 3.8.0) rspec-expectations (~> 3.8)
rspec-mocks (~> 3.8.0) rspec-mocks (~> 3.8)
rspec-support (~> 3.8.0) rspec-support (~> 3.8)
rspec-support (3.8.0) rspec-support (3.8.0)
rtlit (0.0.5) rtlit (0.0.5)
rubocop (0.69.0) rubocop (0.69.0)
@ -417,18 +416,19 @@ GEM
hkdf (~> 0.2) hkdf (~> 0.2)
jwt (~> 2.0) jwt (~> 2.0)
yaml-lint (0.0.10) yaml-lint (0.0.10)
zeitwerk (2.1.10)
PLATFORMS PLATFORMS
ruby ruby
DEPENDENCIES DEPENDENCIES
actionmailer (= 5.2.3) actionmailer (= 6.0.0)
actionpack (= 5.2.3) actionpack (= 6.0.0)
actionview (= 5.2.3) actionview (= 6.0.0)
active_model_serializers (~> 0.8.3) active_model_serializers (~> 0.8.3)
activemodel (= 5.2.3) activemodel (= 6.0.0)
activerecord (= 5.2.3) activerecord (= 6.0.0)
activesupport (= 5.2.3) activesupport (= 6.0.0)
annotate annotate
aws-sdk-s3 aws-sdk-s3
aws-sdk-sns aws-sdk-sns
@ -504,7 +504,7 @@ DEPENDENCIES
rack-mini-profiler rack-mini-profiler
rack-protection rack-protection
rails_multisite rails_multisite
railties (= 5.2.3) railties (= 6.0.0)
rake rake
rb-fsevent rb-fsevent
rb-inotify (~> 0.9) rb-inotify (~> 0.9)
@ -517,7 +517,7 @@ DEPENDENCIES
rqrcode rqrcode
rspec rspec
rspec-html-matchers rspec-html-matchers
rspec-rails rspec-rails (= 4.0.0.beta2)
rtlit rtlit
rubocop rubocop
ruby-prof ruby-prof

View File

@ -1,5 +1,5 @@
<div class="user-crawler"> <div class="user-crawler">
<img src='<%= UrlHelper.local_cdn_url(get_absolute_image_url(@user.small_avatar_url)) %>' alt='<%= @user.username %>' title='<%= @user.username %>' /> <img src='<%= ::UrlHelper.local_cdn_url(get_absolute_image_url(@user.small_avatar_url)) %>' alt='<%= @user.username %>' title='<%= @user.username %>' />
<h2 class='username'><%= @user.username %></h2> <h2 class='username'><%= @user.username %></h2>
</div> </div>

View File

@ -93,6 +93,8 @@ module Discourse
# issue is image_optim crashes on missing dependencies # issue is image_optim crashes on missing dependencies
config.assets.image_optim = false config.assets.image_optim = false
config.autoloader = :classic
# Custom directories with classes and modules you want to be autoloadable. # Custom directories with classes and modules you want to be autoloadable.
config.autoload_paths += Dir["#{config.root}/app/serializers"] config.autoload_paths += Dir["#{config.root}/app/serializers"]
config.autoload_paths += Dir["#{config.root}/lib/validators/"] config.autoload_paths += Dir["#{config.root}/lib/validators/"]

View File

@ -4,8 +4,8 @@ class AddTopicAllowedGroups < ActiveRecord::Migration[4.2]
def change def change
create_table :topic_allowed_groups, force: true do |t| create_table :topic_allowed_groups, force: true do |t|
# oops # oops
t.integer :group_id, :integer, null: false t.integer :group_id, null: false
t.integer :topic_id, :integer, null: false t.integer :topic_id, null: false
end end
add_index :topic_allowed_groups, [:group_id, :topic_id], unique: true add_index :topic_allowed_groups, [:group_id, :topic_id], unique: true

View File

@ -3,6 +3,6 @@
class FixTopicAllowedGroups < ActiveRecord::Migration[4.2] class FixTopicAllowedGroups < ActiveRecord::Migration[4.2]
def change def change
# big oops # big oops
remove_column :topic_allowed_groups, :integer remove_column :topic_allowed_groups, :integer if column_exists?(:topic_allowed_groups, :integer)
end end
end end

View File

@ -1,110 +0,0 @@
# frozen_string_literal: true
# this is a quick backport of a new method introduced in Rails 6
# to be removed after we upgrade to Rails 6
if ! defined? ActionView::Base.with_view_paths
class ActionView::Base
class << self
alias with_view_paths new
end
end
end
# backport of https://github.com/rails/rails/commit/890485cfce4c361c03a41ec23b0ba187007818cc
if !defined? ActionDispatch::Http::ContentDisposition
module ActionDispatch
module Http
class ContentDisposition
def self.format(disposition:, filename:)
new(disposition: disposition, filename: filename).to_s
end
attr_reader :disposition, :filename
def initialize(disposition:, filename:)
@disposition = disposition
@filename = filename
end
TRADITIONAL_ESCAPED_CHAR = /[^ A-Za-z0-9!#$+.^_`|~-]/
def ascii_filename
'filename="' + percent_escape(I18n.transliterate(filename), TRADITIONAL_ESCAPED_CHAR) + '"'
end
RFC_5987_ESCAPED_CHAR = /[^A-Za-z0-9!#$&+.^_`|~-]/
def utf8_filename
"filename*=UTF-8''" + percent_escape(filename, RFC_5987_ESCAPED_CHAR)
end
def to_s
if filename
"#{disposition}; #{ascii_filename}; #{utf8_filename}"
else
"#{disposition}"
end
end
private
def percent_escape(string, pattern)
string.gsub(pattern) do |char|
char.bytes.map { |byte| "%%%02X" % byte }.join
end
end
end
end
end
module ActionController
module DataStreaming
private
def send_file_headers!(options)
type_provided = options.has_key?(:type)
content_type = options.fetch(:type, DEFAULT_SEND_FILE_TYPE)
self.content_type = content_type
response.sending_file = true
raise ArgumentError, ":type option required" if content_type.nil?
if content_type.is_a?(Symbol)
extension = Mime[content_type]
raise ArgumentError, "Unknown MIME type #{options[:type]}" unless extension
self.content_type = extension
else
if !type_provided && options[:filename]
# If type wasn't provided, try guessing from file extension.
content_type = Mime::Type.lookup_by_extension(File.extname(options[:filename]).downcase.delete(".")) || content_type
end
self.content_type = content_type
end
disposition = options.fetch(:disposition, DEFAULT_SEND_FILE_DISPOSITION)
if disposition
headers["Content-Disposition"] = ActionDispatch::Http::ContentDisposition.format(disposition: disposition, filename: options[:filename])
end
headers["Content-Transfer-Encoding"] = "binary"
# Fix a problem with IE 6.0 on opening downloaded files:
# If Cache-Control: no-cache is set (which Rails does by default),
# IE removes the file it just downloaded from its cache immediately
# after it displays the "open/save" dialog, which means that if you
# hit "open" the file isn't there anymore when the application that
# is called for handling the download is run, so let's workaround that
response.cache_control[:public] ||= false
end
end
end
module ActiveStorage
class Service
private
def content_disposition_with(type: "inline", filename:)
disposition = (type.to_s.presence_in(%w( attachment inline )) || "inline")
ActionDispatch::Http::ContentDisposition.format(disposition: disposition, filename: filename.sanitized)
end
end
end
end

View File

@ -36,6 +36,9 @@ class MiniSqlMultisiteConnection < MiniSql::Postgres::Connection
def before_committed!(*); end def before_committed!(*); end
def rolledback!(*); end def rolledback!(*); end
def trigger_transactional_callbacks?
true
end
end end
# Allows running arbitrary code after the current transaction has been committed. # Allows running arbitrary code after the current transaction has been committed.

View File

@ -14,8 +14,8 @@ describe Migration::SafeMigrate do
end end
def migrate_up(path) def migrate_up(path)
migrations = ActiveRecord::MigrationContext.new(path).migrations migrations = ActiveRecord::MigrationContext.new(path, ActiveRecord::SchemaMigration).migrations
ActiveRecord::Migrator.new(:up, migrations, migrations.first.version).run ActiveRecord::Migrator.new(:up, migrations, ActiveRecord::SchemaMigration, migrations.first.version).run
end end
it "bans all table removal" do it "bans all table removal" do

View File

@ -734,7 +734,7 @@ describe PostRevisor do
let(:bumped_at) { 1.day.ago } let(:bumped_at) { 1.day.ago }
before do before do
topic.update_attributes!(bumped_at: bumped_at) topic.update!(bumped_at: bumped_at)
create_hidden_tags(['important', 'secret']) create_hidden_tags(['important', 'secret'])
topic = post.topic topic = post.topic
topic.tags = [Fabricate(:tag, name: "super"), Tag.where(name: "important").first, Fabricate(:tag, name: "stuff")] topic.tags = [Fabricate(:tag, name: "super"), Tag.where(name: "important").first, Fabricate(:tag, name: "stuff")]

View File

@ -344,7 +344,7 @@ describe UserNotifications do
] ]
SiteSetting.post_excerpts_in_emails = true SiteSetting.post_excerpts_in_emails = true
SiteSetting.post_excerpt_maxlength = paragraphs.first.length SiteSetting.post_excerpt_maxlength = paragraphs.first.length
response.update_attributes!(raw: paragraphs.join("\n\n")) response.update!(raw: paragraphs.join("\n\n"))
mail = UserNotifications.user_replied( mail = UserNotifications.user_replied(
user, user,
post: response, post: response,

View File

@ -39,7 +39,7 @@ describe BadgesController do
it 'renders rss feed of a badge' do it 'renders rss feed of a badge' do
get "/badges/#{badge.id}.rss" get "/badges/#{badge.id}.rss"
expect(response.status).to eq(200) expect(response.status).to eq(200)
expect(response.content_type).to eq('application/rss+xml') expect(response.media_type).to eq('application/rss+xml')
end end
end end
end end

View File

@ -426,7 +426,7 @@ describe GroupsController do
get "/groups/#{group.name}/posts.rss" get "/groups/#{group.name}/posts.rss"
expect(response.status).to eq(200) expect(response.status).to eq(200)
expect(response.content_type).to eq('application/rss+xml') expect(response.media_type).to eq('application/rss+xml')
end end
end end
@ -435,7 +435,7 @@ describe GroupsController do
get "/groups/#{group.name}/mentions.rss" get "/groups/#{group.name}/mentions.rss"
expect(response.status).to eq(200) expect(response.status).to eq(200)
expect(response.content_type).to eq('application/rss+xml') expect(response.media_type).to eq('application/rss+xml')
end end
it 'fails when disabled' do it 'fails when disabled' do

View File

@ -320,7 +320,7 @@ RSpec.describe ListController do
it 'renders latest RSS' do it 'renders latest RSS' do
get "/latest.rss" get "/latest.rss"
expect(response.status).to eq(200) expect(response.status).to eq(200)
expect(response.content_type).to eq('application/rss+xml') expect(response.media_type).to eq('application/rss+xml')
end end
it 'renders links correctly with subfolder' do it 'renders links correctly with subfolder' do
@ -337,14 +337,14 @@ RSpec.describe ListController do
it 'renders top RSS' do it 'renders top RSS' do
get "/top.rss" get "/top.rss"
expect(response.status).to eq(200) expect(response.status).to eq(200)
expect(response.content_type).to eq('application/rss+xml') expect(response.media_type).to eq('application/rss+xml')
end end
TopTopic.periods.each do |period| TopTopic.periods.each do |period|
it "renders #{period} top RSS" do it "renders #{period} top RSS" do
get "/top/#{period}.rss" get "/top/#{period}.rss"
expect(response.status).to eq(200) expect(response.status).to eq(200)
expect(response.content_type).to eq('application/rss+xml') expect(response.media_type).to eq('application/rss+xml')
end end
end end
end end
@ -433,7 +433,7 @@ RSpec.describe ListController do
it 'renders RSS' do it 'renders RSS' do
get "/c/#{category.slug}.rss" get "/c/#{category.slug}.rss"
expect(response.status).to eq(200) expect(response.status).to eq(200)
expect(response.content_type).to eq('application/rss+xml') expect(response.media_type).to eq('application/rss+xml')
end end
it "renders RSS in subfolder correctly" do it "renders RSS in subfolder correctly" do

View File

@ -20,7 +20,7 @@ RSpec.describe MetadataController do
get "/manifest.webmanifest" get "/manifest.webmanifest"
expect(response.status).to eq(200) expect(response.status).to eq(200)
expect(response.content_type).to eq('application/manifest+json') expect(response.media_type).to eq('application/manifest+json')
manifest = JSON.parse(response.body) manifest = JSON.parse(response.body)
expect(manifest["name"]).to eq(title) expect(manifest["name"]).to eq(title)
@ -98,7 +98,7 @@ RSpec.describe MetadataController do
expect(response.body).to include("/search?q={searchTerms}") expect(response.body).to include("/search?q={searchTerms}")
expect(response.body).to include('image/png') expect(response.body).to include('image/png')
expect(response.body).to include(UrlHelper.absolute(upload.url)) expect(response.body).to include(UrlHelper.absolute(upload.url))
expect(response.content_type).to eq('application/xml') expect(response.media_type).to eq('application/xml')
end end
end end
@ -121,7 +121,7 @@ RSpec.describe MetadataController do
expect(response.status).to eq(200) expect(response.status).to eq(200)
expect(response.body).to include("hash_of_app_certificate") expect(response.body).to include("hash_of_app_certificate")
expect(response.body).to include("com.example.app") expect(response.body).to include("com.example.app")
expect(response.content_type).to eq('application/json') expect(response.media_type).to eq('application/json')
end end
end end
@ -143,7 +143,7 @@ RSpec.describe MetadataController do
expect(response.status).to eq(200) expect(response.status).to eq(200)
expect(response.body).to include("applinks") expect(response.body).to include("applinks")
expect(response.content_type).to eq('application/json') expect(response.media_type).to eq('application/json')
get "/apple-app-site-association.json" get "/apple-app-site-association.json"
expect(response.status).to eq(404) expect(response.status).to eq(404)

View File

@ -26,7 +26,7 @@ describe StaticController do
get '/favicon/proxied' get '/favicon/proxied'
expect(response.status).to eq(200) expect(response.status).to eq(200)
expect(response.content_type).to eq('image/png') expect(response.media_type).to eq('image/png')
expect(response.body.bytesize).to eq(SiteIconManager.favicon.filesize) expect(response.body.bytesize).to eq(SiteIconManager.favicon.filesize)
end end
@ -36,7 +36,7 @@ describe StaticController do
get '/favicon/proxied' get '/favicon/proxied'
expect(response.status).to eq(200) expect(response.status).to eq(200)
expect(response.content_type).to eq('image/png') expect(response.media_type).to eq('image/png')
expect(response.body.bytesize).to eq(upload.filesize) expect(response.body.bytesize).to eq(upload.filesize)
end end
end end
@ -66,7 +66,7 @@ describe StaticController do
get '/favicon/proxied' get '/favicon/proxied'
expect(response.status).to eq(200) expect(response.status).to eq(200)
expect(response.content_type).to eq('image/png') expect(response.media_type).to eq('image/png')
expect(response.body.bytesize).to eq(upload.filesize) expect(response.body.bytesize).to eq(upload.filesize)
end end
end end

View File

@ -1998,7 +1998,7 @@ RSpec.describe TopicsController do
it 'renders rss of the topic' do it 'renders rss of the topic' do
get "/t/foo/#{topic.id}.rss" get "/t/foo/#{topic.id}.rss"
expect(response.status).to eq(200) expect(response.status).to eq(200)
expect(response.content_type).to eq('application/rss+xml') expect(response.media_type).to eq('application/rss+xml')
end end
it 'renders rss of the topic correctly with subfolder' do it 'renders rss of the topic correctly with subfolder' do