aboutsummaryrefslogtreecommitdiffstats
path: root/activerecord/lib
diff options
context:
space:
mode:
Diffstat (limited to 'activerecord/lib')
-rw-r--r--activerecord/lib/active_record/associations/builder/association.rb28
-rw-r--r--activerecord/lib/active_record/associations/builder/collection_association.rb12
-rw-r--r--activerecord/lib/active_record/attribute_methods/before_type_cast.rb2
-rw-r--r--activerecord/lib/active_record/attribute_methods/query.rb2
-rw-r--r--activerecord/lib/active_record/attribute_methods/write.rb2
-rw-r--r--activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb25
-rw-r--r--activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb17
-rw-r--r--activerecord/lib/active_record/connection_adapters/mysql/type_metadata.rb3
-rw-r--r--activerecord/lib/active_record/connection_adapters/postgresql/column.rb12
-rw-r--r--activerecord/lib/active_record/connection_adapters/postgresql/schema_statements.rb27
-rw-r--r--activerecord/lib/active_record/connection_adapters/postgresql/type_metadata.rb51
-rw-r--r--activerecord/lib/active_record/core.rb3
-rw-r--r--activerecord/lib/active_record/persistence.rb1
-rw-r--r--activerecord/lib/active_record/touch_later.rb2
-rw-r--r--activerecord/lib/active_record/transactions.rb41
15 files changed, 94 insertions, 134 deletions
diff --git a/activerecord/lib/active_record/associations/builder/association.rb b/activerecord/lib/active_record/associations/builder/association.rb
index 7c69cd65ee..3b4b243148 100644
--- a/activerecord/lib/active_record/associations/builder/association.rb
+++ b/activerecord/lib/active_record/associations/builder/association.rb
@@ -27,40 +27,32 @@ module ActiveRecord::Associations::Builder # :nodoc:
"Please choose a different association name."
end
- extension = define_extensions model, name, &block
- reflection = create_reflection model, name, scope, options, extension
+ reflection = create_reflection(model, name, scope, options, &block)
define_accessors model, reflection
define_callbacks model, reflection
define_validations model, reflection
reflection
end
- def self.create_reflection(model, name, scope, options, extension = nil)
+ def self.create_reflection(model, name, scope, options, &block)
raise ArgumentError, "association names must be a Symbol" unless name.kind_of?(Symbol)
validate_options(options)
- scope = build_scope(scope, extension)
+ extension = define_extensions(model, name, &block)
+ options[:extend] = [*options[:extend], extension] if extension
+
+ scope = build_scope(scope)
ActiveRecord::Reflection.create(macro, name, scope, options, model)
end
- def self.build_scope(scope, extension)
- new_scope = scope
-
+ def self.build_scope(scope)
if scope && scope.arity == 0
- new_scope = proc { instance_exec(&scope) }
- end
-
- if extension
- new_scope = wrap_scope new_scope, extension
+ proc { instance_exec(&scope) }
+ else
+ scope
end
-
- new_scope
- end
-
- def self.wrap_scope(scope, extension)
- scope
end
def self.macro
diff --git a/activerecord/lib/active_record/associations/builder/collection_association.rb b/activerecord/lib/active_record/associations/builder/collection_association.rb
index 5848cd9112..9fccfcce0c 100644
--- a/activerecord/lib/active_record/associations/builder/collection_association.rb
+++ b/activerecord/lib/active_record/associations/builder/collection_association.rb
@@ -66,17 +66,5 @@ module ActiveRecord::Associations::Builder # :nodoc:
end
CODE
end
-
- def self.wrap_scope(scope, mod)
- if scope
- if scope.arity > 0
- proc { |owner| instance_exec(owner, &scope).extending(mod) }
- else
- proc { instance_exec(&scope).extending(mod) }
- end
- else
- proc { extending(mod) }
- end
- end
end
end
diff --git a/activerecord/lib/active_record/attribute_methods/before_type_cast.rb b/activerecord/lib/active_record/attribute_methods/before_type_cast.rb
index 5941f51a1a..dc239ff9ea 100644
--- a/activerecord/lib/active_record/attribute_methods/before_type_cast.rb
+++ b/activerecord/lib/active_record/attribute_methods/before_type_cast.rb
@@ -65,7 +65,7 @@ module ActiveRecord
private
- # Handle *_before_type_cast for method_missing.
+ # Dispatch target for <tt>*_before_type_cast</tt> attribute methods.
def attribute_before_type_cast(attribute_name)
read_attribute_before_type_cast(attribute_name)
end
diff --git a/activerecord/lib/active_record/attribute_methods/query.rb b/activerecord/lib/active_record/attribute_methods/query.rb
index 6811f54b10..0cf67644af 100644
--- a/activerecord/lib/active_record/attribute_methods/query.rb
+++ b/activerecord/lib/active_record/attribute_methods/query.rb
@@ -32,7 +32,7 @@ module ActiveRecord
end
private
- # Handle *? for method_missing.
+ # Dispatch target for <tt>*?</tt> attribute methods.
def attribute?(attribute_name)
query_attribute(attribute_name)
end
diff --git a/activerecord/lib/active_record/attribute_methods/write.rb b/activerecord/lib/active_record/attribute_methods/write.rb
index 455e67e19b..d5ba2f42cb 100644
--- a/activerecord/lib/active_record/attribute_methods/write.rb
+++ b/activerecord/lib/active_record/attribute_methods/write.rb
@@ -58,7 +58,7 @@ module ActiveRecord
value
end
- # Handle *= for method_missing.
+ # Dispatch target for <tt>*=</tt> attribute methods.
def attribute=(attribute_name, value)
_write_attribute(attribute_name, value)
end
diff --git a/activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb b/activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb
index 4840307094..8ba9943f75 100644
--- a/activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb
+++ b/activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb
@@ -1379,6 +1379,31 @@ module ActiveRecord
options.is_a?(Hash) && options.key?(:name) && options.except(:name, :algorithm).empty?
end
+ def bulk_change_table(table_name, operations)
+ sql_fragments = []
+ non_combinable_operations = []
+
+ operations.each do |command, args|
+ table, arguments = args.shift, args
+ method = :"#{command}_for_alter"
+
+ if respond_to?(method, true)
+ sqls, procs = Array(send(method, table, *arguments)).partition { |v| v.is_a?(String) }
+ sql_fragments << sqls
+ non_combinable_operations.concat(procs)
+ else
+ execute "ALTER TABLE #{quote_table_name(table_name)} #{sql_fragments.join(", ")}" unless sql_fragments.empty?
+ non_combinable_operations.each(&:call)
+ sql_fragments = []
+ non_combinable_operations = []
+ send(command, table, *arguments)
+ end
+ end
+
+ execute "ALTER TABLE #{quote_table_name(table_name)} #{sql_fragments.join(", ")}" unless sql_fragments.empty?
+ non_combinable_operations.each(&:call)
+ end
+
def add_column_for_alter(table_name, column_name, type, options = {})
td = create_table_definition(table_name)
cd = td.new_column_definition(column_name, type, options)
diff --git a/activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb b/activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb
index ca8bbc14da..2a2b234ef8 100644
--- a/activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb
+++ b/activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb
@@ -63,7 +63,7 @@ module ActiveRecord
/mariadb/i.match?(full_version)
end
- def supports_bulk_alter? #:nodoc:
+ def supports_bulk_alter?
true
end
@@ -285,21 +285,6 @@ module ActiveRecord
SQL
end
- def bulk_change_table(table_name, operations) #:nodoc:
- sqls = operations.flat_map do |command, args|
- table, arguments = args.shift, args
- method = :"#{command}_for_alter"
-
- if respond_to?(method, true)
- send(method, table, *arguments)
- else
- raise "Unknown method called : #{method}(#{arguments.inspect})"
- end
- end.join(", ")
-
- execute("ALTER TABLE #{quote_table_name(table_name)} #{sqls}")
- end
-
def change_table_comment(table_name, comment) #:nodoc:
comment = "" if comment.nil?
execute("ALTER TABLE #{quote_table_name(table_name)} COMMENT #{quote(comment)}")
diff --git a/activerecord/lib/active_record/connection_adapters/mysql/type_metadata.rb b/activerecord/lib/active_record/connection_adapters/mysql/type_metadata.rb
index 56479f27bf..9167593064 100644
--- a/activerecord/lib/active_record/connection_adapters/mysql/type_metadata.rb
+++ b/activerecord/lib/active_record/connection_adapters/mysql/type_metadata.rb
@@ -10,12 +10,11 @@ module ActiveRecord
def initialize(type_metadata, extra: "")
super(type_metadata)
- @type_metadata = type_metadata
@extra = extra
end
def ==(other)
- other.is_a?(MySQL::TypeMetadata) &&
+ other.is_a?(TypeMetadata) &&
__getobj__ == other.__getobj__ &&
extra == other.extra
end
diff --git a/activerecord/lib/active_record/connection_adapters/postgresql/column.rb b/activerecord/lib/active_record/connection_adapters/postgresql/column.rb
index ef98d2b37a..ec25bb1e19 100644
--- a/activerecord/lib/active_record/connection_adapters/postgresql/column.rb
+++ b/activerecord/lib/active_record/connection_adapters/postgresql/column.rb
@@ -4,8 +4,7 @@ module ActiveRecord
module ConnectionAdapters
module PostgreSQL
class Column < ConnectionAdapters::Column # :nodoc:
- delegate :array, :oid, :fmod, to: :sql_type_metadata
- alias :array? :array
+ delegate :oid, :fmod, to: :sql_type_metadata
def initialize(*, serial: nil, **)
super
@@ -15,6 +14,15 @@ module ActiveRecord
def serial?
@serial
end
+
+ def array
+ sql_type_metadata.sql_type.end_with?("[]")
+ end
+ alias :array? :array
+
+ def sql_type
+ super.sub(/\[\]\z/, "")
+ end
end
end
PostgreSQLColumn = PostgreSQL::Column # :nodoc:
diff --git a/activerecord/lib/active_record/connection_adapters/postgresql/schema_statements.rb b/activerecord/lib/active_record/connection_adapters/postgresql/schema_statements.rb
index c412d1f34c..ec8af73d07 100644
--- a/activerecord/lib/active_record/connection_adapters/postgresql/schema_statements.rb
+++ b/activerecord/lib/active_record/connection_adapters/postgresql/schema_statements.rb
@@ -368,31 +368,6 @@ module ActiveRecord
SQL
end
- def bulk_change_table(table_name, operations)
- sql_fragments = []
- non_combinable_operations = []
-
- operations.each do |command, args|
- table, arguments = args.shift, args
- method = :"#{command}_for_alter"
-
- if respond_to?(method, true)
- sqls, procs = Array(send(method, table, *arguments)).partition { |v| v.is_a?(String) }
- sql_fragments << sqls
- non_combinable_operations.concat(procs)
- else
- execute "ALTER TABLE #{quote_table_name(table_name)} #{sql_fragments.join(", ")}" unless sql_fragments.empty?
- non_combinable_operations.each(&:call)
- sql_fragments = []
- non_combinable_operations = []
- send(command, table, *arguments)
- end
- end
-
- execute "ALTER TABLE #{quote_table_name(table_name)} #{sql_fragments.join(", ")}" unless sql_fragments.empty?
- non_combinable_operations.each(&:call)
- end
-
# Renames a table.
# Also renames a table's primary key sequence if the sequence name exists and
# matches the Active Record default.
@@ -675,7 +650,7 @@ module ActiveRecord
precision: cast_type.precision,
scale: cast_type.scale,
)
- PostgreSQLTypeMetadata.new(simple_type, oid: oid, fmod: fmod)
+ PostgreSQL::TypeMetadata.new(simple_type, oid: oid, fmod: fmod)
end
def sequence_name_from_parts(table_name, column_name, suffix)
diff --git a/activerecord/lib/active_record/connection_adapters/postgresql/type_metadata.rb b/activerecord/lib/active_record/connection_adapters/postgresql/type_metadata.rb
index 403b3ead98..8bdec623af 100644
--- a/activerecord/lib/active_record/connection_adapters/postgresql/type_metadata.rb
+++ b/activerecord/lib/active_record/connection_adapters/postgresql/type_metadata.rb
@@ -3,39 +3,34 @@
module ActiveRecord
# :stopdoc:
module ConnectionAdapters
- class PostgreSQLTypeMetadata < DelegateClass(SqlTypeMetadata)
- undef to_yaml if method_defined?(:to_yaml)
+ module PostgreSQL
+ class TypeMetadata < DelegateClass(SqlTypeMetadata)
+ undef to_yaml if method_defined?(:to_yaml)
- attr_reader :oid, :fmod, :array
+ attr_reader :oid, :fmod
- def initialize(type_metadata, oid: nil, fmod: nil)
- super(type_metadata)
- @type_metadata = type_metadata
- @oid = oid
- @fmod = fmod
- @array = /\[\]$/.match?(type_metadata.sql_type)
- end
-
- def sql_type
- super.gsub(/\[\]$/, "")
- end
+ def initialize(type_metadata, oid: nil, fmod: nil)
+ super(type_metadata)
+ @oid = oid
+ @fmod = fmod
+ end
- def ==(other)
- other.is_a?(PostgreSQLTypeMetadata) &&
- __getobj__ == other.__getobj__ &&
- oid == other.oid &&
- fmod == other.fmod &&
- array == other.array
- end
- alias eql? ==
+ def ==(other)
+ other.is_a?(TypeMetadata) &&
+ __getobj__ == other.__getobj__ &&
+ oid == other.oid &&
+ fmod == other.fmod
+ end
+ alias eql? ==
- def hash
- PostgreSQLTypeMetadata.hash ^
- __getobj__.hash ^
- oid.hash ^
- fmod.hash ^
- array.hash
+ def hash
+ TypeMetadata.hash ^
+ __getobj__.hash ^
+ oid.hash ^
+ fmod.hash
+ end
end
end
+ PostgreSQLTypeMetadata = PostgreSQL::TypeMetadata
end
end
diff --git a/activerecord/lib/active_record/core.rb b/activerecord/lib/active_record/core.rb
index eb4b48bc37..6fed3e5c19 100644
--- a/activerecord/lib/active_record/core.rb
+++ b/activerecord/lib/active_record/core.rb
@@ -466,6 +466,7 @@ module ActiveRecord
# Returns +true+ if the attributes hash has been frozen.
def frozen?
+ sync_with_transaction_state
@attributes.frozen?
end
@@ -583,7 +584,7 @@ module ActiveRecord
end
def thaw
- if frozen?
+ if @attributes.frozen?
@attributes = @attributes.dup
end
end
diff --git a/activerecord/lib/active_record/persistence.rb b/activerecord/lib/active_record/persistence.rb
index e05490753f..bc6d04b7bb 100644
--- a/activerecord/lib/active_record/persistence.rb
+++ b/activerecord/lib/active_record/persistence.rb
@@ -530,7 +530,6 @@ module ActiveRecord
def destroy
_raise_readonly_record_error if readonly?
destroy_associations
- self.class.connection.add_transaction_record(self)
@_trigger_destroy_callback = if persisted?
destroy_row > 0
else
diff --git a/activerecord/lib/active_record/touch_later.rb b/activerecord/lib/active_record/touch_later.rb
index 5dc88fb26c..980e42664b 100644
--- a/activerecord/lib/active_record/touch_later.rb
+++ b/activerecord/lib/active_record/touch_later.rb
@@ -22,7 +22,7 @@ module ActiveRecord
@_touch_time = current_time_from_proper_timezone
surreptitiously_touch @_defer_touch_attrs
- self.class.connection.add_transaction_record self
+ add_to_transaction
# touch the parents as we are not calling the after_save callbacks
self.class.reflect_on_all_associations(:belongs_to).each do |r|
diff --git a/activerecord/lib/active_record/transactions.rb b/activerecord/lib/active_record/transactions.rb
index a45d228298..ffbcf1f8b2 100644
--- a/activerecord/lib/active_record/transactions.rb
+++ b/activerecord/lib/active_record/transactions.rb
@@ -355,18 +355,6 @@ module ActiveRecord
clear_transaction_record_state
end
- # Add the record to the current transaction so that the #after_rollback and #after_commit callbacks
- # can be called.
- def add_to_transaction
- if has_transactional_callbacks?
- self.class.connection.add_transaction_record(self)
- else
- sync_with_transaction_state
- set_transaction_state(self.class.connection.transaction_state)
- end
- remember_transaction_record_state
- end
-
# Executes +method+ within a transaction and captures its return value as a
# status flag. If the status is true the transaction is committed, otherwise
# a ROLLBACK is issued. In any case the status flag is returned.
@@ -376,15 +364,26 @@ module ActiveRecord
def with_transaction_returning_status
status = nil
self.class.transaction do
- add_to_transaction
+ unless has_transactional_callbacks?
+ sync_with_transaction_state
+ @transaction_state = self.class.connection.transaction_state
+ end
+ remember_transaction_record_state
+
status = yield
raise ActiveRecord::Rollback unless status
+ ensure
+ if has_transactional_callbacks? &&
+ (@_new_record_before_last_commit && !new_record? || _trigger_update_callback || _trigger_destroy_callback)
+ add_to_transaction
+ end
end
status
end
private
- attr_reader :_committed_already_called, :_trigger_update_callback, :_trigger_destroy_callback
+ attr_reader :_committed_already_called, :_trigger_update_callback, :_trigger_destroy_callback,
+ :transaction_state
# Save the new record state and id of a record so it can be restored later if a transaction fails.
def remember_transaction_record_state
@@ -449,8 +448,10 @@ module ActiveRecord
end
end
- def set_transaction_state(state)
- @transaction_state = state
+ # Add the record to the current transaction so that the #after_rollback and #after_commit
+ # callbacks can be called.
+ def add_to_transaction
+ self.class.connection.add_transaction_record(self)
end
def has_transactional_callbacks?
@@ -470,15 +471,7 @@ module ActiveRecord
# This method checks to see if the ActiveRecord object's state reflects
# the TransactionState, and rolls back or commits the Active Record object
# as appropriate.
- #
- # Since Active Record objects can be inside multiple transactions, this
- # method recursively goes through the parent of the TransactionState and
- # checks if the Active Record object reflects the state of the object.
def sync_with_transaction_state
- update_attributes_from_transaction_state(@transaction_state)
- end
-
- def update_attributes_from_transaction_state(transaction_state)
if transaction_state && transaction_state.finalized?
restore_transaction_record_state(transaction_state.fully_rolledback?) if transaction_state.rolledback?
force_clear_transaction_record_state if transaction_state.fully_committed?