diff options
Diffstat (limited to 'activerecord')
25 files changed, 117 insertions, 60 deletions
diff --git a/activerecord/CHANGELOG.md b/activerecord/CHANGELOG.md index c02de2e979..6bdb53ac5a 100644 --- a/activerecord/CHANGELOG.md +++ b/activerecord/CHANGELOG.md @@ -1,8 +1,19 @@ +* Honor overridden `rack.test` in Rack environment for the connection + management middleware. + + *Simon Eskildsen* + +* Add a truncate method to the connection. + + *Aaron Patterson* + * Don't autosave unchanged has_one through records. *Alan Kennedy*, *Steve Parrington* -* Do not dump foreign keys for ignored tables. *Yves Senn* +* Do not dump foreign keys for ignored tables. + + *Yves Senn* * PostgreSQL adapter correctly dumps foreign keys targeting tables outside the schema search path. @@ -202,7 +213,7 @@ *Kenn Ejima* -* Add support for Postgresql JSONB. +* Add support for PostgreSQL JSONB. Example: diff --git a/activerecord/Rakefile b/activerecord/Rakefile index b1069e5dcc..976b559da9 100644 --- a/activerecord/Rakefile +++ b/activerecord/Rakefile @@ -55,6 +55,7 @@ end t.warning = true t.verbose = true + t.ruby_opts = ["--dev"] if defined?(JRUBY_VERSION) } namespace :isolated do diff --git a/activerecord/lib/active_record/associations/builder/has_and_belongs_to_many.rb b/activerecord/lib/active_record/associations/builder/has_and_belongs_to_many.rb index 34a555dfd4..815e8eb97f 100644 --- a/activerecord/lib/active_record/associations/builder/has_and_belongs_to_many.rb +++ b/activerecord/lib/active_record/associations/builder/has_and_belongs_to_many.rb @@ -11,7 +11,7 @@ module ActiveRecord::Associations::Builder end def join_table - @join_table ||= [@lhs_class.table_name, klass.table_name].sort.join("\0").gsub(/^(.*[._])(.+)\0\1(.+)/, '\1\2_\3').gsub("\0", "_") + @join_table ||= [@lhs_class.table_name, klass.table_name].sort.join("\0").gsub(/^(.*[._])(.+)\0\1(.+)/, '\1\2_\3').tr("\0", "_") end private diff --git a/activerecord/lib/active_record/associations/collection_proxy.rb b/activerecord/lib/active_record/associations/collection_proxy.rb index 8c7b0b4be9..060b2278d9 100644 --- a/activerecord/lib/active_record/associations/collection_proxy.rb +++ b/activerecord/lib/active_record/associations/collection_proxy.rb @@ -355,14 +355,15 @@ module ActiveRecord @association.replace(other_array) end - # Deletes all the records from the collection. For +has_many+ associations, - # the deletion is done according to the strategy specified by the <tt>:dependent</tt> - # option. + # Deletes all the records from the collection according to the strategy + # specified by the +:dependent+ option. If no +:dependent+ option is given, + # then it will follow the default strategy. # - # If no <tt>:dependent</tt> option is given, then it will follow the - # default strategy. The default strategy is <tt>:nullify</tt>. This - # sets the foreign keys to <tt>NULL</tt>. For, +has_many+ <tt>:through</tt>, - # the default strategy is +delete_all+. + # For +has_many :through+ associations, the default deletion strategy is + # +:delete_all+. + # + # For +has_many+ associations, the default deletion strategy is +:nullify+. + # This sets the foreign keys to +NULL+. # # class Person < ActiveRecord::Base # has_many :pets # dependent: :nullify option by default @@ -393,9 +394,9 @@ module ActiveRecord # # #<Pet id: 3, name: "Choo-Choo", person_id: nil> # # ] # - # If it is set to <tt>:destroy</tt> all the objects from the collection - # are removed by calling their +destroy+ method. See +destroy+ for more - # information. + # Both +has_many+ and +has_many :through+ dependencies default to the + # +:delete_all+ strategy if the +:dependent+ option is set to +:destroy+. + # Records are not instantiated and callbacks will not be fired. # # class Person < ActiveRecord::Base # has_many :pets, dependent: :destroy @@ -410,11 +411,6 @@ module ActiveRecord # # ] # # person.pets.delete_all - # # => [ - # # #<Pet id: 1, name: "Fancy-Fancy", person_id: 1>, - # # #<Pet id: 2, name: "Spook", person_id: 1>, - # # #<Pet id: 3, name: "Choo-Choo", person_id: 1> - # # ] # # Pet.find(1, 2, 3) # # => ActiveRecord::RecordNotFound @@ -443,8 +439,9 @@ module ActiveRecord end # Deletes the records of the collection directly from the database - # ignoring the +:dependent+ option. It invokes +before_remove+, - # +after_remove+ , +before_destroy+ and +after_destroy+ callbacks. + # ignoring the +:dependent+ option. Records are instantiated and it + # invokes +before_remove+, +after_remove+ , +before_destroy+ and + # +after_destroy+ callbacks. # # class Person < ActiveRecord::Base # has_many :pets diff --git a/activerecord/lib/active_record/associations/has_many_through_association.rb b/activerecord/lib/active_record/associations/has_many_through_association.rb index 0968b0068e..455a540bdb 100644 --- a/activerecord/lib/active_record/associations/has_many_through_association.rb +++ b/activerecord/lib/active_record/associations/has_many_through_association.rb @@ -159,7 +159,7 @@ module ActiveRecord count = scope.destroy_all.length else scope.to_a.each do |record| - record.run_callbacks :destroy + record.run_destroy_callbacks end arel = scope.arel diff --git a/activerecord/lib/active_record/associations/join_dependency/join_part.rb b/activerecord/lib/active_record/associations/join_dependency/join_part.rb index 91e1c6a9d7..9c6573f913 100644 --- a/activerecord/lib/active_record/associations/join_dependency/join_part.rb +++ b/activerecord/lib/active_record/associations/join_dependency/join_part.rb @@ -19,7 +19,6 @@ module ActiveRecord def initialize(base_klass, children) @base_klass = base_klass - @column_names_with_alias = nil @children = children end diff --git a/activerecord/lib/active_record/attribute_set/builder.rb b/activerecord/lib/active_record/attribute_set/builder.rb index 1e146a07da..d4a787f2fe 100644 --- a/activerecord/lib/active_record/attribute_set/builder.rb +++ b/activerecord/lib/active_record/attribute_set/builder.rb @@ -23,8 +23,11 @@ module ActiveRecord end def add_uninitialized_attributes(attributes) - types.except(*attributes.keys).each do |name, type| - attributes[name] = Attribute.uninitialized(name, type) + types.each_key do |name| + next if attributes.key? name + type = types[name] + attributes[name] = + Attribute.uninitialized(name, type) end end end diff --git a/activerecord/lib/active_record/callbacks.rb b/activerecord/lib/active_record/callbacks.rb index 5955673b42..1aa760157a 100644 --- a/activerecord/lib/active_record/callbacks.rb +++ b/activerecord/lib/active_record/callbacks.rb @@ -289,25 +289,25 @@ module ActiveRecord end def destroy #:nodoc: - run_callbacks(:destroy) { super } + run_destroy_callbacks { super } end def touch(*) #:nodoc: - run_callbacks(:touch) { super } + run_touch_callbacks { super } end private def create_or_update #:nodoc: - run_callbacks(:save) { super } + run_save_callbacks { super } end def _create_record #:nodoc: - run_callbacks(:create) { super } + run_create_callbacks { super } end def _update_record(*) #:nodoc: - run_callbacks(:update) { super } + run_update_callbacks { super } end end end diff --git a/activerecord/lib/active_record/connection_adapters/abstract/connection_pool.rb b/activerecord/lib/active_record/connection_adapters/abstract/connection_pool.rb index bc1a670b42..da43e5bb10 100644 --- a/activerecord/lib/active_record/connection_adapters/abstract/connection_pool.rb +++ b/activerecord/lib/active_record/connection_adapters/abstract/connection_pool.rb @@ -360,7 +360,7 @@ module ActiveRecord synchronize do owner = conn.owner - conn.run_callbacks :checkin do + conn.run_checkin_callbacks do conn.expire end @@ -449,7 +449,7 @@ module ActiveRecord end def checkout_and_verify(c) - c.run_callbacks :checkout do + c.run_checkout_callbacks do c.verify! end c @@ -640,7 +640,7 @@ module ActiveRecord end def call(env) - testing = env.key?('rack.test') + testing = env['rack.test'] response = @app.call(env) response[2] = ::Rack::BodyProxy.new(response[2]) do diff --git a/activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb b/activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb index 98e96099cb..ff8b3e9890 100644 --- a/activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb +++ b/activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb @@ -83,6 +83,11 @@ module ActiveRecord exec_query(sql, name, binds) end + # Executes the truncate statement. + def truncate(table_name, name = nil) + raise NotImplementedError + end + # Executes update +sql+ statement in the context of this connection using # +binds+ as the bind substitutes. +name+ is logged along with # the executed +sql+ statement. 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 037fb69dfb..e4cfe843a8 100644 --- a/activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +++ b/activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb @@ -389,6 +389,10 @@ module ActiveRecord end end + def truncate(table_name, name = nil) + execute "TRUNCATE TABLE #{quote_table_name(table_name)}", name + end + def table_exists?(name) return false unless name.present? return true if tables(nil, nil, name).any? diff --git a/activerecord/lib/active_record/connection_adapters/connection_specification.rb b/activerecord/lib/active_record/connection_adapters/connection_specification.rb index d28a54b8f9..e02824b33d 100644 --- a/activerecord/lib/active_record/connection_adapters/connection_specification.rb +++ b/activerecord/lib/active_record/connection_adapters/connection_specification.rb @@ -33,7 +33,7 @@ module ActiveRecord def initialize(url) raise "Database URL cannot be empty" if url.blank? @uri = uri_parser.parse(url) - @adapter = @uri.scheme.gsub('-', '_') + @adapter = @uri.scheme.tr('-', '_') @adapter = "postgresql" if @adapter == "postgres" if @uri.opaque diff --git a/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb b/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb index 80461f3910..0d74cb6707 100644 --- a/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb +++ b/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb @@ -255,6 +255,10 @@ module ActiveRecord @statements.clear end + def truncate(table_name, name = nil) + exec_query "TRUNCATE TABLE #{quote_table_name(table_name)}", name, [] + end + # Is this connection alive and ready for queries? def active? @connection.query 'SELECT 1' diff --git a/activerecord/lib/active_record/core.rb b/activerecord/lib/active_record/core.rb index 069aa977bf..5571a2d297 100644 --- a/activerecord/lib/active_record/core.rb +++ b/activerecord/lib/active_record/core.rb @@ -272,7 +272,7 @@ module ActiveRecord init_attributes(attributes, options) if attributes yield self if block_given? - run_callbacks :initialize unless _initialize_callbacks.empty? + run_initialize_callbacks end # Initialize an empty model object from +coder+. +coder+ must contain @@ -294,8 +294,8 @@ module ActiveRecord self.class.define_attribute_methods - run_callbacks :find - run_callbacks :initialize + run_find_callbacks + run_initialize_callbacks self end @@ -331,7 +331,7 @@ module ActiveRecord @attributes = @attributes.dup @attributes.reset(self.class.primary_key) - run_callbacks(:initialize) unless _initialize_callbacks.empty? + run_initialize_callbacks @aggregation_cache = {} @association_cache = {} diff --git a/activerecord/lib/active_record/fixtures.rb b/activerecord/lib/active_record/fixtures.rb index 9cf9c13771..125a119b5f 100644 --- a/activerecord/lib/active_record/fixtures.rb +++ b/activerecord/lib/active_record/fixtures.rb @@ -525,7 +525,7 @@ module ActiveRecord conn = fs.model_class.respond_to?(:connection) ? fs.model_class.connection : connection table_rows = fs.table_rows - table_rows.keys.each do |table| + table_rows.each_key do |table| conn.delete "DELETE FROM #{conn.quote_table_name(table)}", 'Fixture Delete' end diff --git a/activerecord/lib/active_record/gem_version.rb b/activerecord/lib/active_record/gem_version.rb index 15c9dee712..91747d2ccf 100644 --- a/activerecord/lib/active_record/gem_version.rb +++ b/activerecord/lib/active_record/gem_version.rb @@ -8,7 +8,7 @@ module ActiveRecord MAJOR = 4 MINOR = 2 TINY = 0 - PRE = "beta1" + PRE = "beta2" STRING = [MAJOR, MINOR, TINY, PRE].compact.join(".") end diff --git a/activerecord/lib/active_record/model_schema.rb b/activerecord/lib/active_record/model_schema.rb index 850220babd..48e82d28d9 100644 --- a/activerecord/lib/active_record/model_schema.rb +++ b/activerecord/lib/active_record/model_schema.rb @@ -63,7 +63,7 @@ module ActiveRecord # records, artists => artists_records # music_artists, music_records => music_artists_records def self.derive_join_table_name(first_table, second_table) # :nodoc: - [first_table.to_s, second_table.to_s].sort.join("\0").gsub(/^(.*_)(.+)\0\1(.+)/, '\1\2_\3').gsub("\0", "_") + [first_table.to_s, second_table.to_s].sort.join("\0").gsub(/^(.*_)(.+)\0\1(.+)/, '\1\2_\3').tr("\0", "_") end module ClassMethods @@ -297,16 +297,13 @@ module ActiveRecord undefine_attribute_methods connection.schema_cache.clear_table_cache!(table_name) if table_exists? - @arel_engine = nil - @column_names = nil - @column_types = nil - @content_columns = nil - @default_attributes = nil - @dynamic_methods_hash = nil - @inheritance_column = nil unless defined?(@explicit_inheritance_column) && @explicit_inheritance_column - @relation = nil - @time_zone_column_names = nil - @cached_time_zone = nil + @arel_engine = nil + @column_names = nil + @column_types = nil + @content_columns = nil + @default_attributes = nil + @inheritance_column = nil unless defined?(@explicit_inheritance_column) && @explicit_inheritance_column + @relation = nil end private diff --git a/activerecord/lib/active_record/querying.rb b/activerecord/lib/active_record/querying.rb index a9ddd9141f..45b6b1c925 100644 --- a/activerecord/lib/active_record/querying.rb +++ b/activerecord/lib/active_record/querying.rb @@ -37,7 +37,8 @@ module ActiveRecord # Post.find_by_sql ["SELECT body FROM comments WHERE author = :user_id OR approved_by = :user_id", { :user_id => user_id }] def find_by_sql(sql, binds = []) result_set = connection.select_all(sanitize_sql(sql), "#{name} Load", binds) - column_types = result_set.column_types.except(*columns_hash.keys) + column_types = result_set.column_types.dup + columns_hash.each_key { |k| column_types.delete k } result_set.map { |record| instantiate(record, column_types) } end diff --git a/activerecord/lib/active_record/railties/databases.rake b/activerecord/lib/active_record/railties/databases.rake index 458862a538..44765bd050 100644 --- a/activerecord/lib/active_record/railties/databases.rake +++ b/activerecord/lib/active_record/railties/databases.rake @@ -215,7 +215,7 @@ db_namespace = namespace :db do Dir["#{base_dir}/**/*.yml"].each do |file| if data = YAML::load(ERB.new(IO.read(file)).result) - data.keys.each do |key| + data.each_key do |key| key_id = ActiveRecord::FixtureSet.identify(key) if key == label || key_id == id.to_i diff --git a/activerecord/lib/active_record/transactions.rb b/activerecord/lib/active_record/transactions.rb index 45bc10b9b0..e53297d0ab 100644 --- a/activerecord/lib/active_record/transactions.rb +++ b/activerecord/lib/active_record/transactions.rb @@ -309,7 +309,7 @@ module ActiveRecord # Ensure that it is not called if the object was never persisted (failed create), # but call it after the commit of a destroyed object. def committed!(should_run_callbacks = true) #:nodoc: - run_callbacks :commit if should_run_callbacks && destroyed? || persisted? + run_commit_callbacks if should_run_callbacks && destroyed? || persisted? ensure force_clear_transaction_record_state end @@ -317,7 +317,7 @@ module ActiveRecord # Call the +after_rollback+ callbacks. The +force_restore_state+ argument indicates if the record # state should be rolled back to the beginning or just to the last savepoint. def rolledback!(force_restore_state = false, should_run_callbacks = true) #:nodoc: - run_callbacks :rollback if should_run_callbacks + run_rollback_callbacks if should_run_callbacks ensure restore_transaction_record_state(force_restore_state) clear_transaction_record_state diff --git a/activerecord/lib/active_record/validations/associated.rb b/activerecord/lib/active_record/validations/associated.rb index b4785d3ba4..47ccef31a5 100644 --- a/activerecord/lib/active_record/validations/associated.rb +++ b/activerecord/lib/active_record/validations/associated.rb @@ -29,9 +29,11 @@ module ActiveRecord # Configuration options: # # * <tt>:message</tt> - A custom error message (default is: "is invalid"). - # * <tt>:on</tt> - Specifies when this validation is active. Runs in all - # validation contexts by default (+nil+), other options are <tt>:create</tt> - # and <tt>:update</tt>. + # * <tt>:on</tt> - Specifies the contexts where this validation is active. + # Runs in all validation contexts by default (nil). You can pass a symbol + # or an array of symbols. (e.g. <tt>on: :create</tt> or + # <tt>on: :custom_validation_context</tt> or + # <tt>on: [:create, :custom_validation_context]</tt>) # * <tt>:if</tt> - Specifies a method, proc or string to call to determine # if the validation should occur (e.g. <tt>if: :allow_validation</tt>, # or <tt>if: Proc.new { |user| user.signup_step > 2 }</tt>). The method, diff --git a/activerecord/lib/active_record/validations/presence.rb b/activerecord/lib/active_record/validations/presence.rb index e586744818..c7aa814ba8 100644 --- a/activerecord/lib/active_record/validations/presence.rb +++ b/activerecord/lib/active_record/validations/presence.rb @@ -44,9 +44,11 @@ module ActiveRecord # # Configuration options: # * <tt>:message</tt> - A custom error message (default is: "can't be blank"). - # * <tt>:on</tt> - Specifies when this validation is active. Runs in all - # validation contexts by default (+nil+), other options are <tt>:create</tt> - # and <tt>:update</tt>. + # * <tt>:on</tt> - Specifies the contexts where this validation is active. + # Runs in all validation contexts by default (nil). You can pass a symbol + # or an array of symbols. (e.g. <tt>on: :create</tt> or + # <tt>on: :custom_validation_context</tt> or + # <tt>on: [:create, :custom_validation_context]</tt>) # * <tt>:if</tt> - Specifies a method, proc or string to call to determine if # the validation should occur (e.g. <tt>if: :allow_validation</tt>, or # <tt>if: Proc.new { |user| user.signup_step > 2 }</tt>). The method, proc diff --git a/activerecord/test/cases/adapters/mysql2/connection_test.rb b/activerecord/test/cases/adapters/mysql2/connection_test.rb index 0b2f59b0eb..62c5abbf41 100644 --- a/activerecord/test/cases/adapters/mysql2/connection_test.rb +++ b/activerecord/test/cases/adapters/mysql2/connection_test.rb @@ -4,6 +4,8 @@ require 'support/connection_helper' class MysqlConnectionTest < ActiveRecord::TestCase include ConnectionHelper + fixtures :comments + def setup super @subscriber = SQLSubscriber.new @@ -24,6 +26,17 @@ class MysqlConnectionTest < ActiveRecord::TestCase end end + def test_truncate + rows = ActiveRecord::Base.connection.exec_query("select count(*) from comments") + count = rows.first.values.first + assert_operator count, :>, 0 + + ActiveRecord::Base.connection.truncate("comments") + rows = ActiveRecord::Base.connection.exec_query("select count(*) from comments") + count = rows.first.values.first + assert_equal 0, count + end + def test_no_automatic_reconnection_after_timeout assert @connection.active? @connection.update('set @@wait_timeout=1') diff --git a/activerecord/test/cases/adapters/postgresql/connection_test.rb b/activerecord/test/cases/adapters/postgresql/connection_test.rb index d26cda46fa..7d179944d4 100644 --- a/activerecord/test/cases/adapters/postgresql/connection_test.rb +++ b/activerecord/test/cases/adapters/postgresql/connection_test.rb @@ -8,6 +8,8 @@ module ActiveRecord class NonExistentTable < ActiveRecord::Base end + fixtures :comments + def setup super @subscriber = SQLSubscriber.new @@ -20,6 +22,14 @@ module ActiveRecord super end + def test_truncate + count = ActiveRecord::Base.connection.execute("select count(*) from comments").first['count'].to_i + assert_operator count, :>, 0 + ActiveRecord::Base.connection.truncate("comments") + count = ActiveRecord::Base.connection.execute("select count(*) from comments").first['count'].to_i + assert_equal 0, count + end + def test_encoding assert_not_nil @connection.encoding end diff --git a/activerecord/test/cases/connection_management_test.rb b/activerecord/test/cases/connection_management_test.rb index 77d9ae9b8e..f53c496ecd 100644 --- a/activerecord/test/cases/connection_management_test.rb +++ b/activerecord/test/cases/connection_management_test.rb @@ -96,6 +96,14 @@ module ActiveRecord assert ActiveRecord::Base.connection_handler.active_connections? end + def test_connections_closed_if_exception_and_explicitly_not_test + @env['rack.test'] = false + app = Class.new(App) { def call(env); raise NotImplementedError; end }.new + explosive = ConnectionManagement.new(app) + assert_raises(NotImplementedError) { explosive.call(@env) } + assert !ActiveRecord::Base.connection_handler.active_connections? + end + test "doesn't clear active connections when running in a test case" do @env['rack.test'] = true @management.call(@env) |