aboutsummaryrefslogtreecommitdiffstats
path: root/activerecord/lib/active_record/model_schema.rb
diff options
context:
space:
mode:
Diffstat (limited to 'activerecord/lib/active_record/model_schema.rb')
-rw-r--r--activerecord/lib/active_record/model_schema.rb139
1 files changed, 77 insertions, 62 deletions
diff --git a/activerecord/lib/active_record/model_schema.rb b/activerecord/lib/active_record/model_schema.rb
index 54216caaaf..694ff85fa1 100644
--- a/activerecord/lib/active_record/model_schema.rb
+++ b/activerecord/lib/active_record/model_schema.rb
@@ -1,3 +1,7 @@
+# frozen_string_literal: true
+
+require "monitor"
+
module ActiveRecord
module ModelSchema
extend ActiveSupport::Concern
@@ -83,19 +87,6 @@ module ActiveRecord
# Sets the name of the internal metadata table.
##
- # :singleton-method: protected_environments
- # :call-seq: protected_environments
- #
- # The array of names of environments where destructive actions should be prohibited. By default,
- # the value is <tt>["production"]</tt>.
-
- ##
- # :singleton-method: protected_environments=
- # :call-seq: protected_environments=(environments)
- #
- # Sets an array of names of environments where destructive actions should be prohibited.
-
- ##
# :singleton-method: pluralize_table_names
# :call-seq: pluralize_table_names
#
@@ -111,47 +102,22 @@ module ActiveRecord
# If true, the default table name for a Product class will be "products". If false, it would just be "product".
# See table_name for the full rules on table/class naming. This is true, by default.
- ##
- # :singleton-method: ignored_columns
- # :call-seq: ignored_columns
- #
- # The list of columns names the model should ignore. Ignored columns won't have attribute
- # accessors defined, and won't be referenced in SQL queries.
-
- ##
- # :singleton-method: ignored_columns=
- # :call-seq: ignored_columns=(columns)
- #
- # Sets the columns names the model should ignore. Ignored columns won't have attribute
- # accessors defined, and won't be referenced in SQL queries.
-
included do
mattr_accessor :primary_key_prefix_type, instance_writer: false
- class_attribute :table_name_prefix, instance_writer: false
- self.table_name_prefix = ""
-
- class_attribute :table_name_suffix, instance_writer: false
- self.table_name_suffix = ""
-
- class_attribute :schema_migrations_table_name, instance_accessor: false
- self.schema_migrations_table_name = "schema_migrations"
-
- class_attribute :internal_metadata_table_name, instance_accessor: false
- self.internal_metadata_table_name = "ar_internal_metadata"
+ class_attribute :table_name_prefix, instance_writer: false, default: ""
+ class_attribute :table_name_suffix, instance_writer: false, default: ""
+ class_attribute :schema_migrations_table_name, instance_accessor: false, default: "schema_migrations"
+ class_attribute :internal_metadata_table_name, instance_accessor: false, default: "ar_internal_metadata"
+ class_attribute :pluralize_table_names, instance_writer: false, default: true
- class_attribute :protected_environments, instance_accessor: false
self.protected_environments = ["production"]
-
- class_attribute :pluralize_table_names, instance_writer: false
- self.pluralize_table_names = true
-
- class_attribute :ignored_columns, instance_accessor: false
- self.ignored_columns = [].freeze
-
self.inheritance_column = "type"
+ self.ignored_columns = [].freeze
delegate :type_for_attribute, to: :class
+
+ initialize_load_schema_monitor
end
# Derives the join table name for +first_table+ and +second_table+. The
@@ -259,6 +225,21 @@ module ActiveRecord
(parents.detect { |p| p.respond_to?(:table_name_suffix) } || self).table_name_suffix
end
+ # The array of names of environments where destructive actions should be prohibited. By default,
+ # the value is <tt>["production"]</tt>.
+ def protected_environments
+ if defined?(@protected_environments)
+ @protected_environments
+ else
+ superclass.protected_environments
+ end
+ end
+
+ # Sets an array of names of environments where destructive actions should be prohibited.
+ def protected_environments=(environments)
+ @protected_environments = environments.map(&:to_s)
+ end
+
# Defines the name of the table column which will store the class name on single-table
# inheritance situations.
#
@@ -278,8 +259,24 @@ module ActiveRecord
@explicit_inheritance_column = true
end
+ # The list of columns names the model should ignore. Ignored columns won't have attribute
+ # accessors defined, and won't be referenced in SQL queries.
+ def ignored_columns
+ if defined?(@ignored_columns)
+ @ignored_columns
+ else
+ superclass.ignored_columns
+ end
+ end
+
+ # Sets the columns names the model should ignore. Ignored columns won't have attribute
+ # accessors defined, and won't be referenced in SQL queries.
+ def ignored_columns=(columns)
+ @ignored_columns = columns.map(&:to_s)
+ end
+
def sequence_name
- if base_class == self
+ if base_class?
@sequence_name ||= reset_sequence_name
else
(@sequence_name ||= nil) || base_class.sequence_name
@@ -328,11 +325,11 @@ module ActiveRecord
end
def attributes_builder # :nodoc:
- @attributes_builder ||= AttributeSet::Builder.new(attribute_types, primary_key) do |name|
- unless columns_hash.key?(name)
- _default_attributes[name].dup
- end
+ unless defined?(@attributes_builder) && @attributes_builder
+ defaults = _default_attributes.except(*(column_names - [primary_key]))
+ @attributes_builder = ActiveModel::AttributeSet::Builder.new(attribute_types, defaults)
end
+ @attributes_builder
end
def columns_hash # :nodoc:
@@ -351,7 +348,7 @@ module ActiveRecord
end
def yaml_encoder # :nodoc:
- @yaml_encoder ||= AttributeSet::YAMLEncoder.new(attribute_types)
+ @yaml_encoder ||= ActiveModel::AttributeSet::YAMLEncoder.new(attribute_types)
end
# Returns the type of the attribute with the given name, after applying
@@ -364,8 +361,9 @@ module ActiveRecord
# it).
#
# +attr_name+ The name of the attribute to retrieve the type for. Must be
- # a string
+ # a string or a symbol.
def type_for_attribute(attr_name, &block)
+ attr_name = attr_name.to_s
if block
attribute_types.fetch(attr_name, &block)
else
@@ -377,11 +375,12 @@ module ActiveRecord
# default values when instantiating the Active Record object for this table.
def column_defaults
load_schema
- _default_attributes.to_hash
+ @column_defaults ||= _default_attributes.to_hash
end
def _default_attributes # :nodoc:
- @default_attributes ||= AttributeSet.new({})
+ load_schema
+ @default_attributes ||= ActiveModel::AttributeSet.new({})
end
# Returns an array of column names as strings.
@@ -428,22 +427,38 @@ module ActiveRecord
# end
def reset_column_information
connection.clear_cache!
- undefine_attribute_methods
+ ([self] + descendants).each(&:undefine_attribute_methods)
connection.schema_cache.clear_data_source_cache!(table_name)
reload_schema_from_cache
initialize_find_by_cache
end
+ protected
+
+ def initialize_load_schema_monitor
+ @load_schema_monitor = Monitor.new
+ end
+
private
+ def inherited(child_class)
+ super
+ child_class.initialize_load_schema_monitor
+ end
+
def schema_loaded?
- defined?(@columns_hash) && @columns_hash
+ defined?(@schema_loaded) && @schema_loaded
end
def load_schema
- unless schema_loaded?
+ return if schema_loaded?
+ @load_schema_monitor.synchronize do
+ return if defined?(@columns_hash) && @columns_hash
+
load_schema!
+
+ @schema_loaded = true
end
end
@@ -460,16 +475,17 @@ module ActiveRecord
end
def reload_schema_from_cache
- @arel_engine = nil
@arel_table = nil
@column_names = nil
@attribute_types = nil
@content_columns = nil
@default_attributes = nil
+ @column_defaults = nil
@inheritance_column = nil unless defined?(@explicit_inheritance_column) && @explicit_inheritance_column
@attributes_builder = nil
@columns = nil
@columns_hash = nil
+ @schema_loaded = false
@attribute_names = nil
@yaml_encoder = nil
direct_descendants.each do |descendant|
@@ -485,8 +501,7 @@ module ActiveRecord
# Computes and returns a table name according to default conventions.
def compute_table_name
- base = base_class
- if self == base
+ if base_class?
# Nested classes are prefixed with singular parent table name.
if parent < Base && !parent.abstract_class?
contained = parent.table_name
@@ -497,7 +512,7 @@ module ActiveRecord
"#{full_table_name_prefix}#{contained}#{undecorated_table_name(name)}#{full_table_name_suffix}"
else
# STI subclasses always use their superclass' table.
- base.table_name
+ base_class.table_name
end
end
end