Load the model schema when running test in eager load context

Some protections like the one that checks if an enum is pointing to
a valid column in the table only works when the database schema is
loaded to the model.

Before this change, if schema cache wasn't present and the right
combinations of configurations were not set, developers would only see
this exception in production.

With this change, those errors would be caught on CI, as soon the
tests are loaded.
This commit is contained in:
Rafael Mendonça França 2023-10-03 13:20:40 +00:00
parent 7d58fe941a
commit 70843ff7b2
No known key found for this signature in database
GPG Key ID: FC23B6D0F1EEE948
3 changed files with 53 additions and 14 deletions

@ -553,6 +553,20 @@ def reset_column_information
initialize_find_by_cache
end
def load_schema # :nodoc:
return if schema_loaded?
@load_schema_monitor.synchronize do
return if @columns_hash
load_schema!
@schema_loaded = true
rescue
reload_schema_from_cache # If the schema loading failed half way through, we must reset the state.
raise
end
end
protected
def initialize_load_schema_monitor
@load_schema_monitor = Monitor.new
@ -594,20 +608,6 @@ def schema_loaded?
defined?(@schema_loaded) && @schema_loaded
end
def load_schema
return if schema_loaded?
@load_schema_monitor.synchronize do
return if @columns_hash
load_schema!
@schema_loaded = true
rescue
reload_schema_from_cache # If the schema loading failed half way through, we must reset the state.
raise
end
end
def load_schema!
unless table_name
raise ActiveRecord::TableNotSpecified, "#{self} has no table configured. Set one with #{self}.table_name="

@ -22,6 +22,12 @@
exit 1
end
if Rails.configuration.eager_load
ActiveRecord::Base.descendants.each do |model|
model.load_schema unless model.abstract_class?
end
end
ActiveSupport.on_load(:active_support_test_case) do
include ActiveRecord::TestDatabases
include ActiveRecord::TestFixtures

@ -317,6 +317,39 @@ class UserTest < ActiveSupport::TestCase
assert_not_includes output, "after:"
end
test "schema for all the models is loaded when tests are run in eager load context" do
output = rails("generate", "model", "user", "name:string")
version = output.match(/(\d+)_create_users\.rb/)[1]
app_file "db/schema.rb", <<-RUBY
ActiveRecord::Schema.define(version: #{version}) do
create_table :users do |t|
t.string :name
end
create_table :action_text_rich_texts
create_table :active_storage_variant_records
create_table :active_storage_blobs
create_table :active_storage_attachments
create_table :action_mailbox_inbound_emails do |t|
t.integer :status
end
end
RUBY
app_file "config/initializers/enable_eager_load.rb", <<-RUBY
Rails.application.config.eager_load = true
RUBY
app_file "app/models/user.rb", <<-RUBY
class User < ApplicationRecord
enum :type, [:admin, :user]
end
RUBY
assert_unsuccessful_run "models/user_test.rb", "Unknown enum attribute 'type' for User"
end
private
def assert_unsuccessful_run(name, message)
result = run_test_file(name)