1
0
Fork 0
mirror of https://github.com/rails/rails.git synced 2022-11-09 12:12:34 -05:00

Eagerly define attribute methods in production

The attribute methods for a model are currently defined lazily the first
time that model is instantiated, even when `config.eager_load` is true.
This means the first request to use each model incurs the cost, which
usually involves a database round trip to fetch the schema definition.

By defining the attribute methods for all models while the application
is booting, we move that work out of any individual request. When using
a forking web server, this also reduces the number of times the schema
definition is queried by doing it once in the parent process instead of
from each forked process during their first request.
This commit is contained in:
Eugene Kenny 2018-09-24 03:20:35 +01:00
parent baffadaec9
commit 3b954786e7
2 changed files with 55 additions and 0 deletions

View file

@ -137,6 +137,14 @@ end_error
end
end
initializer "active_record.define_attribute_methods" do |app|
config.after_initialize do
ActiveSupport.on_load(:active_record) do
descendants.each(&:define_attribute_methods) if app.config.eager_load
end
end
end
initializer "active_record.warn_on_records_fetched_greater_than" do
if config.active_record.warn_on_records_fetched_greater_than
ActiveSupport.on_load(:active_record) do

View file

@ -310,6 +310,53 @@ module ApplicationTests
assert_equal %w(noop_email).to_set, PostsMailer.instance_variable_get(:@action_methods)
end
test "does not eager load attribute methods in development" do
app_file "app/models/post.rb", <<-RUBY
class Post < ActiveRecord::Base
end
RUBY
app_file "config/initializers/active_record.rb", <<-RUBY
ActiveRecord::Base.establish_connection(adapter: "sqlite3", database: ":memory:")
ActiveRecord::Migration.verbose = false
ActiveRecord::Schema.define(version: 1) do
create_table :posts do |t|
t.string :title
end
end
RUBY
app "development"
assert_not_includes Post.instance_methods, :title
end
test "eager loads attribute methods in production" do
app_file "app/models/post.rb", <<-RUBY
class Post < ActiveRecord::Base
end
RUBY
app_file "config/initializers/active_record.rb", <<-RUBY
ActiveRecord::Base.establish_connection(adapter: "sqlite3", database: ":memory:")
ActiveRecord::Migration.verbose = false
ActiveRecord::Schema.define(version: 1) do
create_table :posts do |t|
t.string :title
end
end
RUBY
add_to_config <<-RUBY
config.eager_load = true
config.cache_classes = true
RUBY
app "production"
assert_includes Post.instance_methods, :title
end
test "initialize an eager loaded, cache classes app" do
add_to_config <<-RUBY
config.eager_load = true