diff options
Diffstat (limited to 'activerecord/lib/active_record')
13 files changed, 118 insertions, 111 deletions
diff --git a/activerecord/lib/active_record/associations/join_dependency/join_association.rb b/activerecord/lib/active_record/associations/join_dependency/join_association.rb index a9d1099871..c3bbdccad8 100644 --- a/activerecord/lib/active_record/associations/join_dependency/join_association.rb +++ b/activerecord/lib/active_record/associations/join_dependency/join_association.rb @@ -90,7 +90,7 @@ module ActiveRecord # end # # If I execute `Physician.joins(:appointments).to_a` then - # reflection # => #<ActiveRecord::Reflection::HasManyReflection ...> + # klass # => Physician # table # => #<Arel::Table @name="appointments" ...> # key # => physician_id # foreign_table # => #<Arel::Table @name="physicians" ...> diff --git a/activerecord/lib/active_record/associations/through_association.rb b/activerecord/lib/active_record/associations/through_association.rb index 24cb5ab545..611d471e62 100644 --- a/activerecord/lib/active_record/associations/through_association.rb +++ b/activerecord/lib/active_record/associations/through_association.rb @@ -3,7 +3,7 @@ module ActiveRecord module Associations module ThroughAssociation #:nodoc: - delegate :source_reflection, :through_reflection, :chain, :to => :reflection + delegate :source_reflection, :through_reflection, :to => :reflection protected @@ -13,7 +13,7 @@ module ActiveRecord # 2. To get the type conditions for any STI models in the chain def target_scope scope = super - chain.drop(1).each do |reflection| + reflection.chain.drop(1).each do |reflection| relation = reflection.klass.all relation.merge!(reflection.scope) if reflection.scope diff --git a/activerecord/lib/active_record/connection_adapters/abstract/transaction.rb b/activerecord/lib/active_record/connection_adapters/abstract/transaction.rb index 46aaaae2ec..4a7f2aaca8 100644 --- a/activerecord/lib/active_record/connection_adapters/abstract/transaction.rb +++ b/activerecord/lib/active_record/connection_adapters/abstract/transaction.rb @@ -30,49 +30,24 @@ module ActiveRecord end end - class Transaction #:nodoc: - attr_reader :connection, :state - - def initialize(connection) - @connection = connection - @state = TransactionState.new - end - - def savepoint_name - nil - end - end - - class NullTransaction < Transaction #:nodoc: + class NullTransaction #:nodoc: def initialize; end def closed?; true; end def open?; false; end def joinable?; false; end - # This is a noop when there are no open transactions def add_record(record); end end - class OpenTransaction < Transaction #:nodoc: - attr_reader :records - attr_writer :joinable - - def initialize(connection, options = {}) - super connection - - @records = [] - @joinable = options.fetch(:joinable, true) - end - - def joinable? - @joinable - end + class Transaction #:nodoc: - def rollback - perform_rollback - end + attr_reader :connection, :state, :records, :savepoint_name + attr_writer :joinable - def commit - perform_commit + def initialize(connection, options) + @connection = connection + @state = TransactionState.new + @records = [] + @joinable = options.fetch(:joinable, true) end def add_record(record) @@ -83,19 +58,25 @@ module ActiveRecord end end - def rollback_records + def rollback @state.set_state(:rolledback) + end + + def rollback_records records.uniq.each do |record| begin - record.rolledback!(self.is_a?(RealTransaction)) + record.rolledback! full_rollback? rescue => e record.logger.error(e) if record.respond_to?(:logger) && record.logger end end end - def commit_records + def commit @state.set_state(:committed) + end + + def commit_records records.uniq.each do |record| begin record.committed! @@ -105,57 +86,57 @@ module ActiveRecord end end - def closed? - false - end - - def open? - true - end + def full_rollback?; true; end + def joinable?; @joinable; end + def closed?; false; end + def open?; !closed?; end end - class RealTransaction < OpenTransaction #:nodoc: - def initialize(connection, _, options = {}) - super(connection, options) + class SavepointTransaction < Transaction + def initialize(connection, savepoint_name, options) + super(connection, options) if options[:isolation] - connection.begin_isolated_db_transaction(options[:isolation]) - else - connection.begin_db_transaction + raise ActiveRecord::TransactionIsolationError, "cannot set transaction isolation in a nested transaction" end + connection.create_savepoint(@savepoint_name = savepoint_name) end - def perform_rollback - connection.rollback_db_transaction + def rollback + super + connection.rollback_to_savepoint(savepoint_name) rollback_records end - def perform_commit - connection.commit_db_transaction - commit_records + def commit + super + connection.release_savepoint(savepoint_name) end + + def full_rollback?; false; end end - class SavepointTransaction < OpenTransaction #:nodoc: - attr_reader :savepoint_name + class RealTransaction < Transaction - def initialize(connection, savepoint_name, options = {}) + def initialize(connection, options) + super if options[:isolation] - raise ActiveRecord::TransactionIsolationError, "cannot set transaction isolation in a nested transaction" + connection.begin_isolated_db_transaction(options[:isolation]) + else + connection.begin_db_transaction end - - super(connection, options) - connection.create_savepoint(@savepoint_name = savepoint_name) end - def perform_rollback - connection.rollback_to_savepoint(savepoint_name) + def rollback + super + connection.rollback_db_transaction rollback_records end - def perform_commit - @state.set_state(:committed) - connection.release_savepoint(savepoint_name) + def commit + super + connection.commit_db_transaction + commit_records end end @@ -166,9 +147,12 @@ module ActiveRecord end def begin_transaction(options = {}) - transaction_class = @stack.empty? ? RealTransaction : SavepointTransaction - transaction = transaction_class.new(@connection, "active_record_#{@stack.size}", options) - + transaction = + if @stack.empty? + RealTransaction.new(@connection, options) + else + SavepointTransaction.new(@connection, "active_record_#{@stack.size}", options) + end @stack.push(transaction) transaction end diff --git a/activerecord/lib/active_record/connection_adapters/column.rb b/activerecord/lib/active_record/connection_adapters/column.rb index 1f1e2c46f4..5f9cc6edd0 100644 --- a/activerecord/lib/active_record/connection_adapters/column.rb +++ b/activerecord/lib/active_record/connection_adapters/column.rb @@ -16,7 +16,7 @@ module ActiveRecord attr_reader :name, :cast_type, :null, :sql_type, :default, :default_function delegate :type, :precision, :scale, :limit, :klass, :accessor, - :text?, :number?, :binary?, :changed?, + :number?, :binary?, :changed?, :type_cast_from_user, :type_cast_from_database, :type_cast_for_database, :type_cast_for_schema, to: :cast_type diff --git a/activerecord/lib/active_record/connection_adapters/postgresql/oid/xml.rb b/activerecord/lib/active_record/connection_adapters/postgresql/oid/xml.rb index 7323f12763..334af7c598 100644 --- a/activerecord/lib/active_record/connection_adapters/postgresql/oid/xml.rb +++ b/activerecord/lib/active_record/connection_adapters/postgresql/oid/xml.rb @@ -7,10 +7,6 @@ module ActiveRecord :xml end - def text? - false - end - def type_cast_for_database(value) return unless value Data.new(super) diff --git a/activerecord/lib/active_record/migration.rb b/activerecord/lib/active_record/migration.rb index 7c4dad21a0..a6847e28c2 100644 --- a/activerecord/lib/active_record/migration.rb +++ b/activerecord/lib/active_record/migration.rb @@ -399,7 +399,7 @@ module ActiveRecord def load_schema_if_pending! if ActiveRecord::Migrator.needs_migration? - ActiveRecord::Tasks::DatabaseTasks.load_schema + ActiveRecord::Tasks::DatabaseTasks.load_schema_current check_pending! end end diff --git a/activerecord/lib/active_record/persistence.rb b/activerecord/lib/active_record/persistence.rb index 96e44c2f59..f35865f54c 100644 --- a/activerecord/lib/active_record/persistence.rb +++ b/activerecord/lib/active_record/persistence.rb @@ -36,6 +36,18 @@ module ActiveRecord end end + # Creates an object just like Base.create but calls <tt>save!</tt> instead of +save+ + # so an exception is raised if the record is invalid. + def create!(attributes = nil, &block) + if attributes.is_a?(Array) + attributes.collect { |attr| create!(attr, &block) } + else + object = new(attributes, &block) + object.save! + object + end + end + # Given an attributes hash, +instantiate+ returns a new instance of # the appropriate class. Accepts only keys as strings. # diff --git a/activerecord/lib/active_record/railties/databases.rake b/activerecord/lib/active_record/railties/databases.rake index ac385817e4..458862a538 100644 --- a/activerecord/lib/active_record/railties/databases.rake +++ b/activerecord/lib/active_record/railties/databases.rake @@ -240,7 +240,7 @@ db_namespace = namespace :db do desc 'Load a schema.rb file into the database' task :load => [:environment, :load_config] do - ActiveRecord::Tasks::DatabaseTasks.load_schema(:ruby, ENV['SCHEMA']) + ActiveRecord::Tasks::DatabaseTasks.load_schema_current(:ruby, ENV['SCHEMA']) end task :load_if_ruby => ['db:create', :environment] do @@ -286,7 +286,7 @@ db_namespace = namespace :db do desc "Recreate the databases from the structure.sql file" task :load => [:environment, :load_config] do - ActiveRecord::Tasks::DatabaseTasks.load_schema(:sql, ENV['DB_STRUCTURE']) + ActiveRecord::Tasks::DatabaseTasks.load_schema_current(:sql, ENV['DB_STRUCTURE']) end task :load_if_sql => ['db:create', :environment] do @@ -317,9 +317,8 @@ db_namespace = namespace :db do task :load_schema => %w(db:test:deprecated db:test:purge) do begin should_reconnect = ActiveRecord::Base.connection_pool.active_connection? - ActiveRecord::Base.establish_connection(ActiveRecord::Base.configurations['test']) ActiveRecord::Schema.verbose = false - db_namespace["schema:load"].invoke + ActiveRecord::Tasks::DatabaseTasks.load_schema_for ActiveRecord::Base.configurations['test'], :ruby, ENV['SCHEMA'] ensure if should_reconnect ActiveRecord::Base.establish_connection(ActiveRecord::Base.configurations[ActiveRecord::Tasks::DatabaseTasks.env]) @@ -329,12 +328,7 @@ db_namespace = namespace :db do # desc "Recreate the test database from an existent structure.sql file" task :load_structure => %w(db:test:deprecated db:test:purge) do - begin - ActiveRecord::Tasks::DatabaseTasks.current_config(:config => ActiveRecord::Base.configurations['test']) - db_namespace["structure:load"].invoke - ensure - ActiveRecord::Tasks::DatabaseTasks.current_config(:config => nil) - end + ActiveRecord::Tasks::DatabaseTasks.load_schema_for ActiveRecord::Base.configurations['test'], :sql, ENV['SCHEMA'] end # desc "Recreate the test database from a fresh schema" diff --git a/activerecord/lib/active_record/reflection.rb b/activerecord/lib/active_record/reflection.rb index 10a75530fd..1547c8e3f4 100644 --- a/activerecord/lib/active_record/reflection.rb +++ b/activerecord/lib/active_record/reflection.rb @@ -38,7 +38,7 @@ module ActiveRecord ar.aggregate_reflections = ar.aggregate_reflections.merge(name.to_s => reflection) end - # \Reflection enables to interrogate Active Record classes and objects + # \Reflection enables interrogating Active Record classes and objects # about their associations and aggregations. This information can, # for example, be used in a form builder that takes an Active Record object # and creates input fields for all of the attributes depending on their type diff --git a/activerecord/lib/active_record/tasks/database_tasks.rb b/activerecord/lib/active_record/tasks/database_tasks.rb index 72e0cf3723..892c78e479 100644 --- a/activerecord/lib/active_record/tasks/database_tasks.rb +++ b/activerecord/lib/active_record/tasks/database_tasks.rb @@ -184,20 +184,39 @@ module ActiveRecord end def load_schema(format = ActiveRecord::Base.schema_format, file = nil) + ActiveSupport::Deprecation.warn(<<-MESSAGE.strip_heredoc) + This method will act on a specific connection in the future. + To act on the current connection, use `load_schema_current` instead. + MESSAGE + load_schema_current(format, file) + end + + # This method is the successor of +load_schema+. We should rename it + # after +load_schema+ went through a deprecation cycle. (Rails > 4.2) + def load_schema_for(configuration, format = ActiveRecord::Base.schema_format, file = nil) # :nodoc: case format when :ruby file ||= File.join(db_dir, "schema.rb") check_schema_file(file) + purge(configuration) + ActiveRecord::Base.establish_connection(configuration) load(file) when :sql file ||= File.join(db_dir, "structure.sql") check_schema_file(file) - structure_load(current_config, file) + purge(configuration) + structure_load(configuration, file) else raise ArgumentError, "unknown format #{format.inspect}" end end + def load_schema_current(format = ActiveRecord::Base.schema_format, file = nil, environment = env) + each_current_configuration(environment) { |configuration| + load_schema_for configuration, format, file + } + end + def check_schema_file(filename) unless File.exist?(filename) message = %{#{filename} doesn't exist yet. Run `rake db:migrate` to create it, then try again.} diff --git a/activerecord/lib/active_record/tasks/sqlite_database_tasks.rb b/activerecord/lib/active_record/tasks/sqlite_database_tasks.rb index 5688931db2..9ab64d0325 100644 --- a/activerecord/lib/active_record/tasks/sqlite_database_tasks.rb +++ b/activerecord/lib/active_record/tasks/sqlite_database_tasks.rb @@ -21,7 +21,11 @@ module ActiveRecord FileUtils.rm(file) if File.exist?(file) end - alias :purge :drop + + def purge + drop + create + end def charset connection.encoding diff --git a/activerecord/lib/active_record/type/decimal.rb b/activerecord/lib/active_record/type/decimal.rb index ba5d244729..d10778eeb6 100644 --- a/activerecord/lib/active_record/type/decimal.rb +++ b/activerecord/lib/active_record/type/decimal.rb @@ -14,12 +14,25 @@ module ActiveRecord private def cast_value(value) - if value.is_a?(::Numeric) || value.is_a?(::String) + case value + when ::Float + BigDecimal(value, float_precision) + when ::Numeric, ::String BigDecimal(value, precision.to_i) - elsif value.respond_to?(:to_d) - value.to_d else - cast_value(value.to_s) + if value.respond_to?(:to_d) + value.to_d + else + cast_value(value.to_s) + end + end + end + + def float_precision + if precision.to_i > ::Float::DIG + 1 + ::Float::DIG + 1 + else + precision.to_i end end end diff --git a/activerecord/lib/active_record/validations.rb b/activerecord/lib/active_record/validations.rb index b4b33804de..7f7d49cdb4 100644 --- a/activerecord/lib/active_record/validations.rb +++ b/activerecord/lib/active_record/validations.rb @@ -29,21 +29,6 @@ module ActiveRecord extend ActiveSupport::Concern include ActiveModel::Validations - module ClassMethods - # Creates an object just like Base.create but calls <tt>save!</tt> instead of +save+ - # so an exception is raised if the record is invalid. - def create!(attributes = nil, &block) - if attributes.is_a?(Array) - attributes.collect { |attr| create!(attr, &block) } - else - object = new(attributes) - yield(object) if block_given? - object.save! - object - end - end - end - # The validation process on save can be skipped by passing <tt>validate: false</tt>. # The regular Base#save method is replaced with this when the validations # module is mixed in, which it is by default. |