diff options
Diffstat (limited to 'activerecord')
42 files changed, 466 insertions, 214 deletions
diff --git a/activerecord/lib/active_record/autosave_association.rb b/activerecord/lib/active_record/autosave_association.rb index fd1082a268..c553e95bad 100644 --- a/activerecord/lib/active_record/autosave_association.rb +++ b/activerecord/lib/active_record/autosave_association.rb @@ -214,6 +214,12 @@ module ActiveRecord @marked_for_destruction end + # Returns whether or not this record has been changed in any way (including whether + # any of its nested autosave associations are likewise changed) + def changed_for_autosave? + new_record? || changed? || marked_for_destruction? || nested_records_changed_for_autosave? + end + private # Returns the record for an association collection that should be validated @@ -223,12 +229,27 @@ module ActiveRecord if new_record association elsif autosave - association.target.find_all { |record| record.new_record? || record.changed? || record.marked_for_destruction? } + association.target.find_all { |record| record.changed_for_autosave? } else association.target.find_all { |record| record.new_record? } end end + # go through nested autosave associations that are loaded in memory (without loading + # any new ones), and return true if is changed for autosave + def nested_records_changed_for_autosave? + self.class.reflect_on_all_autosave_associations.each do |reflection| + if association = association_instance_get(reflection.name) + if [:belongs_to, :has_one].include?(reflection.macro) + return true if association.target && association.target.changed_for_autosave? + else + association.target.each {|record| return true if record.changed_for_autosave? } + end + end + end + false + end + # Validate the association if <tt>:validate</tt> or <tt>:autosave</tt> is # turned on for the association specified by +reflection+. def validate_single_association(reflection) diff --git a/activerecord/lib/active_record/base.rb b/activerecord/lib/active_record/base.rb index c02af328c1..1b76f357e3 100755 --- a/activerecord/lib/active_record/base.rb +++ b/activerecord/lib/active_record/base.rb @@ -1193,10 +1193,6 @@ module ActiveRecord #:nodoc: self.default_scoping << construct_finder_arel(options, default_scoping.pop) end - def clear_default_scope - self.default_scoping.clear - end - def scoped_methods #:nodoc: key = :"#{self}_scoped_methods" Thread.current[key] = Thread.current[key].presence || self.default_scoping.dup @@ -1362,7 +1358,8 @@ module ActiveRecord #:nodoc: def replace_bind_variables(statement, values) #:nodoc: raise_if_bind_arity_mismatch(statement, statement.count('?'), values.size) bound = values.dup - statement.gsub('?') { quote_bound_value(bound.shift) } + c = connection + statement.gsub('?') { quote_bound_value(bound.shift, c) } end def replace_named_bind_variables(statement, bind_vars) #:nodoc: @@ -1394,15 +1391,15 @@ module ActiveRecord #:nodoc: expanded end - def quote_bound_value(value) #:nodoc: + def quote_bound_value(value, c = connection) #:nodoc: if value.respond_to?(:map) && !value.acts_like?(:string) if value.respond_to?(:empty?) && value.empty? - connection.quote(nil) + c.quote(nil) else - value.map { |v| connection.quote(v) }.join(',') + value.map { |v| c.quote(v) }.join(',') end else - connection.quote(value) + c.quote(value) end end @@ -1462,12 +1459,18 @@ module ActiveRecord #:nodoc: callback(:after_initialize) if respond_to_without_attributes?(:after_initialize) cloned_attributes = other.clone_attributes(:read_attribute_before_type_cast) cloned_attributes.delete(self.class.primary_key) + @attributes = cloned_attributes + + @changed_attributes = {} + attributes_from_column_definition.each do |attr, orig_value| + @changed_attributes[attr] = orig_value if field_changed?(attr, orig_value, @attributes[attr]) + end + clear_aggregation_cache @attributes_cache = {} @new_record = true ensure_proper_type - @changed_attributes = other.changed_attributes.dup if scope = self.class.send(:current_scoped_methods) create_with = scope.scope_for_create diff --git a/activerecord/lib/active_record/connection_adapters/abstract/database_limits.rb b/activerecord/lib/active_record/connection_adapters/abstract/database_limits.rb new file mode 100644 index 0000000000..4118ea7b31 --- /dev/null +++ b/activerecord/lib/active_record/connection_adapters/abstract/database_limits.rb @@ -0,0 +1,57 @@ +module ActiveRecord + module ConnectionAdapters # :nodoc: + module DatabaseLimits + + # the maximum length of a table alias + def table_alias_length + 255 + end + + # the maximum length of a column name + def column_name_length + 64 + end + + # the maximum length of a table name + def table_name_length + 64 + end + + # the maximum length of an index name + def index_name_length + 64 + end + + # the maximum number of columns per table + def columns_per_table + 1024 + end + + # the maximum number of indexes per table + def indexes_per_table + 16 + end + + # the maximum number of columns in a multicolumn index + def columns_per_multicolumn_index + 16 + end + + # the maximum number of elements in an IN (x,y,z) clause + def in_clause_length + 65535 + end + + # the maximum length of a SQL query + def sql_query_length + 1048575 + end + + # maximum number of joins in a single query + def joins_per_query + 256 + end + + end + end +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 1255ef09be..d3499cea72 100644 --- a/activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb +++ b/activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb @@ -10,11 +10,6 @@ module ActiveRecord {} end - # This is the maximum length a table alias can be - def table_alias_length - 255 - end - # Truncates a table alias according to the limits of the current adapter. def table_alias_for(table_name) table_name[0..table_alias_length-1].gsub(/\./, '_') @@ -293,6 +288,14 @@ module ActiveRecord index_type = options end + if index_name.length > index_name_length + @logger.warn("Index name '#{index_name}' on table '#{table_name}' is too long; the limit is #{index_name_length} characters. Skipping.") + return + end + if index_exists?(table_name, index_name, false) + @logger.warn("Index name '#{index_name}' on table '#{table_name}' already exists. Skipping.") + return + end quoted_column_names = quoted_columns_for_index(column_names, options).join(", ") execute "CREATE #{index_type} INDEX #{quote_column_name(index_name)} ON #{quote_table_name(table_name)} (#{quoted_column_names})" @@ -309,7 +312,28 @@ module ActiveRecord # Remove the index named by_branch_party in the accounts table. # remove_index :accounts, :name => :by_branch_party def remove_index(table_name, options = {}) - execute "DROP INDEX #{quote_column_name(index_name(table_name, options))} ON #{quote_table_name(table_name)}" + index_name = index_name(table_name, options) + unless index_exists?(table_name, index_name, true) + @logger.warn("Index name '#{index_name}' on table '#{table_name}' does not exist. Skipping.") + return + end + remove_index!(table_name, index_name) + end + + def remove_index!(table_name, index_name) #:nodoc: + execute "DROP INDEX #{quote_column_name(index_name)} ON #{table_name}" + end + + # Rename an index. + # + # Rename the index_people_on_last_name index to index_users_on_last_name + # rename_index :people, 'index_people_on_last_name', 'index_users_on_last_name' + def rename_index(table_name, old_name, new_name) + # this is a naive implementation; some DBs may support this more efficiently (Postgres, for instance) + old_index_def = indexes(table_name).detect { |i| i.name == old_name } + return unless old_index_def + remove_index(table_name, :name => old_name) + add_index(table_name, old_index_def.columns, :name => new_name, :unique => old_index_def.unique) end def index_name(table_name, options) #:nodoc: @@ -326,6 +350,15 @@ module ActiveRecord end end + # Verify the existence of an index. + # + # The default argument is returned if the underlying implementation does not define the indexes method, + # as there's no way to determine the correct answer in that case. + def index_exists?(table_name, index_name, default) + return default unless respond_to?(:indexes) + indexes(table_name).detect { |i| i.name == index_name } + end + # Returns a string of <tt>CREATE TABLE</tt> SQL statement(s) for recreating the # entire structure of the database. def structure_dump diff --git a/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb b/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb index 28a59c1e62..fecd4d590e 100755 --- a/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb +++ b/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb @@ -11,6 +11,7 @@ require 'active_record/connection_adapters/abstract/quoting' require 'active_record/connection_adapters/abstract/connection_pool' require 'active_record/connection_adapters/abstract/connection_specification' require 'active_record/connection_adapters/abstract/query_cache' +require 'active_record/connection_adapters/abstract/database_limits' module ActiveRecord module ConnectionAdapters # :nodoc: @@ -29,6 +30,7 @@ module ActiveRecord # notably, the instance methods provided by SchemaStatement are very useful. class AbstractAdapter include Quoting, DatabaseStatements, SchemaStatements + include DatabaseLimits include QueryCache include ActiveSupport::Callbacks diff --git a/activerecord/lib/active_record/connection_adapters/mysql_adapter.rb b/activerecord/lib/active_record/connection_adapters/mysql_adapter.rb index e12924e63f..ec25bbf18e 100644 --- a/activerecord/lib/active_record/connection_adapters/mysql_adapter.rb +++ b/activerecord/lib/active_record/connection_adapters/mysql_adapter.rb @@ -513,7 +513,7 @@ module ActiveRecord def change_column(table_name, column_name, type, options = {}) #:nodoc: column = column_for(table_name, column_name) - if has_default?(type) && !options_include_default?(options) + unless options_include_default?(options) options[:default] = column.default end @@ -675,10 +675,6 @@ module ActiveRecord end column end - - def has_default?(sql_type) - sql_type =~ :binary || sql_type == :text #mysql forbids defaults on blob and text columns - end end end end diff --git a/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb b/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb index 6389094b8a..34aaff2b49 100644 --- a/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb +++ b/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb @@ -819,9 +819,12 @@ module ActiveRecord execute "ALTER TABLE #{quote_table_name(table_name)} RENAME COLUMN #{quote_column_name(column_name)} TO #{quote_column_name(new_column_name)}" end - # Drops an index from a table. - def remove_index(table_name, options = {}) - execute "DROP INDEX #{quote_table_name(index_name(table_name, options))}" + def remove_index!(table_name, index_name) #:nodoc: + execute "DROP INDEX #{quote_table_name(index_name)}" + end + + def index_name_length + 63 end # Maps logical Rails types to PostgreSQL-specific data types. diff --git a/activerecord/lib/active_record/connection_adapters/sqlite_adapter.rb b/activerecord/lib/active_record/connection_adapters/sqlite_adapter.rb index 29225b83c5..e8a45bb3c6 100644 --- a/activerecord/lib/active_record/connection_adapters/sqlite_adapter.rb +++ b/activerecord/lib/active_record/connection_adapters/sqlite_adapter.rb @@ -217,8 +217,8 @@ module ActiveRecord column ? column['name'] : nil end - def remove_index(table_name, options={}) #:nodoc: - execute "DROP INDEX #{quote_column_name(index_name(table_name, options))}" + def remove_index!(table_name, index_name) #:nodoc: + execute "DROP INDEX #{quote_column_name(index_name)}" end def rename_table(name, new_name) diff --git a/activerecord/lib/active_record/session_store.rb b/activerecord/lib/active_record/session_store.rb index 9dda3361d8..931872eded 100644 --- a/activerecord/lib/active_record/session_store.rb +++ b/activerecord/lib/active_record/session_store.rb @@ -307,7 +307,7 @@ module ActiveRecord end end - return true + sid end def get_session_model(env, sid) diff --git a/activerecord/test/cases/active_schema_test_mysql.rb b/activerecord/test/cases/active_schema_test_mysql.rb index f4d123be15..3526f49afd 100644 --- a/activerecord/test/cases/active_schema_test_mysql.rb +++ b/activerecord/test/cases/active_schema_test_mysql.rb @@ -16,6 +16,10 @@ class ActiveSchemaTest < ActiveRecord::TestCase end def test_add_index + # add_index calls index_exists? which can't work since execute is stubbed + ActiveRecord::ConnectionAdapters::MysqlAdapter.send(:define_method, :index_exists?) do |*| + false + end expected = "CREATE INDEX `index_people_on_last_name` ON `people` (`last_name`)" assert_equal expected, add_index(:people, :last_name, :length => nil) @@ -30,6 +34,7 @@ class ActiveSchemaTest < ActiveRecord::TestCase expected = "CREATE INDEX `index_people_on_last_name_and_first_name` ON `people` (`last_name`(15), `first_name`(10))" assert_equal expected, add_index(:people, [:last_name, :first_name], :length => {:last_name => 15, :first_name => 10}) + ActiveRecord::ConnectionAdapters::MysqlAdapter.send(:remove_method, :index_exists?) end def test_drop_table diff --git a/activerecord/test/cases/aggregations_test.rb b/activerecord/test/cases/aggregations_test.rb index 8b6ec04018..e5fc1a2046 100644 --- a/activerecord/test/cases/aggregations_test.rb +++ b/activerecord/test/cases/aggregations_test.rb @@ -58,36 +58,36 @@ class AggregationsTest < ActiveRecord::TestCase end def test_gps_equality - assert GpsLocation.new('39x110') == GpsLocation.new('39x110') + assert_equal GpsLocation.new('39x110'), GpsLocation.new('39x110') end def test_gps_inequality - assert GpsLocation.new('39x110') != GpsLocation.new('39x111') + assert_not_equal GpsLocation.new('39x110'), GpsLocation.new('39x111') end def test_allow_nil_gps_is_nil - assert_equal nil, customers(:zaphod).gps_location + assert_nil customers(:zaphod).gps_location end def test_allow_nil_gps_set_to_nil customers(:david).gps_location = nil customers(:david).save customers(:david).reload - assert_equal nil, customers(:david).gps_location + assert_nil customers(:david).gps_location end def test_allow_nil_set_address_attributes_to_nil customers(:zaphod).address = nil - assert_equal nil, customers(:zaphod).attributes[:address_street] - assert_equal nil, customers(:zaphod).attributes[:address_city] - assert_equal nil, customers(:zaphod).attributes[:address_country] + assert_nil customers(:zaphod).attributes[:address_street] + assert_nil customers(:zaphod).attributes[:address_city] + assert_nil customers(:zaphod).attributes[:address_country] end def test_allow_nil_address_set_to_nil customers(:zaphod).address = nil customers(:zaphod).save customers(:zaphod).reload - assert_equal nil, customers(:zaphod).address + assert_nil customers(:zaphod).address end def test_nil_raises_error_when_allow_nil_is_false @@ -104,9 +104,9 @@ class AggregationsTest < ActiveRecord::TestCase def test_nil_assignment_results_in_nil customers(:david).gps_location = GpsLocation.new('39x111') - assert_not_equal nil, customers(:david).gps_location + assert_not_nil customers(:david).gps_location customers(:david).gps_location = nil - assert_equal nil, customers(:david).gps_location + assert_nil customers(:david).gps_location end def test_custom_constructor diff --git a/activerecord/test/cases/associations/belongs_to_associations_test.rb b/activerecord/test/cases/associations/belongs_to_associations_test.rb index be77ee4bf3..9258c987ef 100644 --- a/activerecord/test/cases/associations/belongs_to_associations_test.rb +++ b/activerecord/test/cases/associations/belongs_to_associations_test.rb @@ -403,7 +403,7 @@ class BelongsToAssociationsTest < ActiveRecord::TestCase assert_equal saved_member.id, sponsor.sponsorable_id sponsor.sponsorable = new_member - assert_equal nil, sponsor.sponsorable_id + assert_nil sponsor.sponsorable_id end def test_polymorphic_assignment_with_primary_key_updates_foreign_id_field_for_new_and_saved_records @@ -415,7 +415,7 @@ class BelongsToAssociationsTest < ActiveRecord::TestCase assert_equal saved_writer.name, essay.writer_id essay.writer = new_writer - assert_equal nil, essay.writer_id + assert_nil essay.writer_id end def test_belongs_to_proxy_should_not_respond_to_private_methods diff --git a/activerecord/test/cases/associations/eager_load_includes_full_sti_class_test.rb b/activerecord/test/cases/associations/eager_load_includes_full_sti_class_test.rb index 7c470616a5..b124a2bfc3 100644 --- a/activerecord/test/cases/associations/eager_load_includes_full_sti_class_test.rb +++ b/activerecord/test/cases/associations/eager_load_includes_full_sti_class_test.rb @@ -29,7 +29,7 @@ class EagerLoadIncludeFullStiClassNamesTest < ActiveRecord::TestCase ActiveRecord::Base.store_full_sti_class = true post = Namespaced::Post.find_by_title( 'Great stuff', :include => :tagging ) - assert_equal 'Tagging', post.tagging.class.name + assert_instance_of Tagging, post.tagging ensure ActiveRecord::Base.store_full_sti_class = old end diff --git a/activerecord/test/cases/associations/eager_test.rb b/activerecord/test/cases/associations/eager_test.rb index 79e5ecf4ce..445e6889c0 100644 --- a/activerecord/test/cases/associations/eager_test.rb +++ b/activerecord/test/cases/associations/eager_test.rb @@ -110,7 +110,7 @@ class EagerAssociationTest < ActiveRecord::TestCase author = assert_queries(3) { Author.find(author_id, :include => {:posts_with_comments => :comments}) } # find the author, then find the posts, then find the comments author.posts_with_comments.each do |post_with_comments| assert_equal post_with_comments.comments.length, post_with_comments.comments.count - assert_equal nil, post_with_comments.comments.uniq! + assert_nil post_with_comments.comments.uniq! end end diff --git a/activerecord/test/cases/associations/has_many_associations_test.rb b/activerecord/test/cases/associations/has_many_associations_test.rb index 6e47967696..8e5bc56008 100644 --- a/activerecord/test/cases/associations/has_many_associations_test.rb +++ b/activerecord/test/cases/associations/has_many_associations_test.rb @@ -175,14 +175,7 @@ class HasManyAssociationsTest < ActiveRecord::TestCase c = Client.new assert_nil c.firm - if c.firm - assert false, "belongs_to failed if check" - end - - unless c.firm - else - assert false, "belongs_to failed unless check" - end + flunk "belongs_to failed if check" if c.firm end def test_find_ids @@ -620,7 +613,7 @@ class HasManyAssociationsTest < ActiveRecord::TestCase assert_equal [], Client.destroyed_client_ids[firm.id] # Should be destroyed since the association is exclusively dependent. - assert Client.find_by_id(client_id).nil? + assert_nil Client.find_by_id(client_id) end def test_dependent_association_respects_optional_conditions_on_delete @@ -669,7 +662,7 @@ class HasManyAssociationsTest < ActiveRecord::TestCase old_record = firm.clients_using_primary_key_with_delete_all.first firm = Firm.find(:first) firm.destroy - assert Client.find_by_id(old_record.id).nil? + assert_nil Client.find_by_id(old_record.id) end def test_creation_respects_hash_condition diff --git a/activerecord/test/cases/associations/has_many_through_associations_test.rb b/activerecord/test/cases/associations/has_many_through_associations_test.rb index ff799191c2..e4dd810732 100644 --- a/activerecord/test/cases/associations/has_many_through_associations_test.rb +++ b/activerecord/test/cases/associations/has_many_through_associations_test.rb @@ -63,8 +63,8 @@ class HasManyThroughAssociationsTest < ActiveRecord::TestCase assert_queries(1) { posts(:thinking) } assert_queries(0) do - posts(:thinking).people.build(:first_name=>"Bob") - posts(:thinking).people.new(:first_name=>"Ted") + posts(:thinking).people.build(:first_name => "Bob") + posts(:thinking).people.new(:first_name => "Ted") end # Should only need to load the association once diff --git a/activerecord/test/cases/associations/has_one_associations_test.rb b/activerecord/test/cases/associations/has_one_associations_test.rb index 8f5540950e..469a21b9bf 100644 --- a/activerecord/test/cases/associations/has_one_associations_test.rb +++ b/activerecord/test/cases/associations/has_one_associations_test.rb @@ -149,7 +149,7 @@ class HasOneAssociationsTest < ActiveRecord::TestCase num_accounts = Account.count firm = Firm.find(1) - assert !firm.account.nil? + assert_not_nil firm.account account_id = firm.account.id assert_equal [], Account.destroyed_account_ids[firm.id] @@ -162,7 +162,7 @@ class HasOneAssociationsTest < ActiveRecord::TestCase num_accounts = Account.count firm = ExclusivelyDependentFirm.find(9) - assert !firm.account.nil? + assert_not_nil firm.account account_id = firm.account.id assert_equal [], Account.destroyed_account_ids[firm.id] @@ -181,7 +181,7 @@ class HasOneAssociationsTest < ActiveRecord::TestCase firm = RestrictedFirm.new(:name => 'restrict') firm.save! account = firm.create_account(:credit_limit => 10) - assert !firm.account.nil? + assert_not_nil firm.account assert_raise(ActiveRecord::DeleteRestrictionError) { firm.destroy } end @@ -246,7 +246,7 @@ class HasOneAssociationsTest < ActiveRecord::TestCase def test_dependence_with_missing_association Account.destroy_all firm = Firm.find(1) - assert firm.account.nil? + assert_nil firm.account firm.destroy end diff --git a/activerecord/test/cases/associations/inverse_associations_test.rb b/activerecord/test/cases/associations/inverse_associations_test.rb index 1d7604f52b..34d24a2948 100644 --- a/activerecord/test/cases/associations/inverse_associations_test.rb +++ b/activerecord/test/cases/associations/inverse_associations_test.rb @@ -23,39 +23,39 @@ class InverseAssociationTests < ActiveRecord::TestCase def test_should_be_able_to_ask_a_reflection_if_it_has_an_inverse has_one_with_inverse_ref = Man.reflect_on_association(:face) - assert has_one_with_inverse_ref.respond_to?(:has_inverse?) + assert_respond_to has_one_with_inverse_ref, :has_inverse? assert has_one_with_inverse_ref.has_inverse? has_many_with_inverse_ref = Man.reflect_on_association(:interests) - assert has_many_with_inverse_ref.respond_to?(:has_inverse?) + assert_respond_to has_many_with_inverse_ref, :has_inverse? assert has_many_with_inverse_ref.has_inverse? belongs_to_with_inverse_ref = Face.reflect_on_association(:man) - assert belongs_to_with_inverse_ref.respond_to?(:has_inverse?) + assert_respond_to belongs_to_with_inverse_ref, :has_inverse? assert belongs_to_with_inverse_ref.has_inverse? has_one_without_inverse_ref = Club.reflect_on_association(:sponsor) - assert has_one_without_inverse_ref.respond_to?(:has_inverse?) + assert_respond_to has_one_without_inverse_ref, :has_inverse? assert !has_one_without_inverse_ref.has_inverse? has_many_without_inverse_ref = Club.reflect_on_association(:memberships) - assert has_many_without_inverse_ref.respond_to?(:has_inverse?) + assert_respond_to has_many_without_inverse_ref, :has_inverse? assert !has_many_without_inverse_ref.has_inverse? belongs_to_without_inverse_ref = Sponsor.reflect_on_association(:sponsor_club) - assert belongs_to_without_inverse_ref.respond_to?(:has_inverse?) + assert_respond_to belongs_to_without_inverse_ref, :has_inverse? assert !belongs_to_without_inverse_ref.has_inverse? end def test_should_be_able_to_ask_a_reflection_what_it_is_the_inverse_of has_one_ref = Man.reflect_on_association(:face) - assert has_one_ref.respond_to?(:inverse_of) + assert_respond_to has_one_ref, :inverse_of has_many_ref = Man.reflect_on_association(:interests) - assert has_many_ref.respond_to?(:inverse_of) + assert_respond_to has_many_ref, :inverse_of belongs_to_ref = Face.reflect_on_association(:man) - assert belongs_to_ref.respond_to?(:inverse_of) + assert_respond_to belongs_to_ref, :inverse_of end def test_inverse_of_method_should_supply_the_actual_reflection_instance_it_is_the_inverse_of diff --git a/activerecord/test/cases/associations/join_model_test.rb b/activerecord/test/cases/associations/join_model_test.rb index dca72be4fd..447fe4d275 100644 --- a/activerecord/test/cases/associations/join_model_test.rb +++ b/activerecord/test/cases/associations/join_model_test.rb @@ -280,12 +280,12 @@ class AssociationsJoinModelTest < ActiveRecord::TestCase def test_has_many_find_conditions assert_equal categories(:general), authors(:david).categories.find(:first, :conditions => "categories.name = 'General'") - assert_equal nil, authors(:david).categories.find(:first, :conditions => "categories.name = 'Technology'") + assert_nil authors(:david).categories.find(:first, :conditions => "categories.name = 'Technology'") end def test_has_many_class_methods_called_by_method_missing assert_equal categories(:general), authors(:david).categories.find_all_by_name('General').first - assert_equal nil, authors(:david).categories.find_by_name('Technology') + assert_nil authors(:david).categories.find_by_name('Technology') end def test_has_many_array_methods_called_by_method_missing diff --git a/activerecord/test/cases/attribute_methods_test.rb b/activerecord/test/cases/attribute_methods_test.rb index 055590da0a..d59fa0a632 100644 --- a/activerecord/test/cases/attribute_methods_test.rb +++ b/activerecord/test/cases/attribute_methods_test.rb @@ -310,7 +310,7 @@ class AttributeMethodsTest < ActiveRecord::TestCase end assert !@target.instance_method_already_implemented?(:title) topic = @target.new - assert_equal nil, topic.title + assert_nil topic.title Object.send(:undef_method, :title) # remove test method from object end diff --git a/activerecord/test/cases/autosave_association_test.rb b/activerecord/test/cases/autosave_association_test.rb index 5cc5dff633..063f0f0fb2 100644 --- a/activerecord/test/cases/autosave_association_test.rb +++ b/activerecord/test/cases/autosave_association_test.rb @@ -1236,11 +1236,11 @@ class TestAutosaveAssociationValidationMethodsGeneration < ActiveRecord::TestCas end test "should generate validation methods for has_many associations" do - assert @pirate.respond_to?(:validate_associated_records_for_birds) + assert_respond_to @pirate, :validate_associated_records_for_birds end test "should generate validation methods for has_one associations with :validate => true" do - assert @pirate.respond_to?(:validate_associated_records_for_ship) + assert_respond_to @pirate, :validate_associated_records_for_ship end test "should not generate validation methods for has_one associations without :validate => true" do @@ -1248,7 +1248,7 @@ class TestAutosaveAssociationValidationMethodsGeneration < ActiveRecord::TestCas end test "should generate validation methods for belongs_to associations with :validate => true" do - assert @pirate.respond_to?(:validate_associated_records_for_parrot) + assert_respond_to @pirate, :validate_associated_records_for_parrot end test "should not generate validation methods for belongs_to associations without :validate => true" do @@ -1256,7 +1256,7 @@ class TestAutosaveAssociationValidationMethodsGeneration < ActiveRecord::TestCas end test "should generate validation methods for HABTM associations with :validate => true" do - assert @pirate.respond_to?(:validate_associated_records_for_parrots) + assert_respond_to @pirate, :validate_associated_records_for_parrots end test "should not generate validation methods for HABTM associations without :validate => true" do diff --git a/activerecord/test/cases/base_test.rb b/activerecord/test/cases/base_test.rb index b7ae619787..0c7723c0e6 100755 --- a/activerecord/test/cases/base_test.rb +++ b/activerecord/test/cases/base_test.rb @@ -111,14 +111,14 @@ class BasicsTest < ActiveRecord::TestCase def test_respond_to? topic = Topic.find(1) - assert topic.respond_to?("title") - assert topic.respond_to?("title?") - assert topic.respond_to?("title=") - assert topic.respond_to?(:title) - assert topic.respond_to?(:title?) - assert topic.respond_to?(:title=) - assert topic.respond_to?("author_name") - assert topic.respond_to?("attribute_names") + assert_respond_to topic, "title" + assert_respond_to topic, "title?" + assert_respond_to topic, "title=" + assert_respond_to topic, :title + assert_respond_to topic, :title? + assert_respond_to topic, :title= + assert_respond_to topic, "author_name" + assert_respond_to topic, "attribute_names" assert !topic.respond_to?("nothingness") assert !topic.respond_to?(:nothingness) end @@ -1038,9 +1038,9 @@ class BasicsTest < ActiveRecord::TestCase def test_mass_assignment_protection_against_class_attribute_writers [:logger, :configurations, :primary_key_prefix_type, :table_name_prefix, :table_name_suffix, :pluralize_table_names, :default_timezone, :schema_format, :lock_optimistically, :record_timestamps].each do |method| - assert Task.respond_to?(method) - assert Task.respond_to?("#{method}=") - assert Task.new.respond_to?(method) + assert_respond_to Task, method + assert_respond_to Task, "#{method}=" + assert_respond_to Task.new, method assert !Task.new.respond_to?("#{method}=") end end @@ -1369,37 +1369,37 @@ class BasicsTest < ActiveRecord::TestCase end def test_new_record_returns_boolean - assert_equal Topic.new.new_record?, true - assert_equal Topic.find(1).new_record?, false + assert_equal true, Topic.new.new_record? + assert_equal false, Topic.find(1).new_record? end def test_destroyed_returns_boolean developer = Developer.first - assert_equal developer.destroyed?, false + assert_equal false, developer.destroyed? developer.destroy - assert_equal developer.destroyed?, true + assert_equal true, developer.destroyed? developer = Developer.last - assert_equal developer.destroyed?, false + assert_equal false, developer.destroyed? developer.delete - assert_equal developer.destroyed?, true + assert_equal true, developer.destroyed? end def test_persisted_returns_boolean developer = Developer.new(:name => "Jose") - assert_equal developer.persisted?, false + assert_equal false, developer.persisted? developer.save! - assert_equal developer.persisted?, true + assert_equal true, developer.persisted? developer = Developer.first - assert_equal developer.persisted?, true + assert_equal true, developer.persisted? developer.destroy - assert_equal developer.persisted?, false + assert_equal false, developer.persisted? developer = Developer.last - assert_equal developer.persisted?, true + assert_equal true, developer.persisted? developer.delete - assert_equal developer.persisted?, false + assert_equal false, developer.persisted? end def test_clone @@ -1427,7 +1427,7 @@ class BasicsTest < ActiveRecord::TestCase # test if saved clone object differs from original cloned_topic.save assert !cloned_topic.new_record? - assert cloned_topic.id != topic.id + assert_not_equal cloned_topic.id, topic.id end def test_clone_with_aggregate_of_same_name_as_attribute @@ -1447,7 +1447,7 @@ class BasicsTest < ActiveRecord::TestCase assert clone.save assert !clone.new_record? - assert clone.id != dev.id + assert_not_equal clone.id, dev.id end def test_clone_preserves_subtype @@ -1456,6 +1456,56 @@ class BasicsTest < ActiveRecord::TestCase assert_kind_of Client, clone end + def test_clone_of_new_object_with_defaults + developer = Developer.new + assert !developer.name_changed? + assert !developer.salary_changed? + + cloned_developer = developer.clone + assert !cloned_developer.name_changed? + assert !cloned_developer.salary_changed? + end + + def test_clone_of_new_object_marks_attributes_as_dirty + developer = Developer.new :name => 'Bjorn', :salary => 100000 + assert developer.name_changed? + assert developer.salary_changed? + + cloned_developer = developer.clone + assert cloned_developer.name_changed? + assert cloned_developer.salary_changed? + end + + def test_clone_of_new_object_marks_as_dirty_only_changed_attributes + developer = Developer.new :name => 'Bjorn' + assert developer.name_changed? # obviously + assert !developer.salary_changed? # attribute has non-nil default value, so treated as not changed + + cloned_developer = developer.clone + assert cloned_developer.name_changed? + assert !cloned_developer.salary_changed? # ... and cloned instance should behave same + end + + def test_clone_of_saved_object_marks_attributes_as_dirty + developer = Developer.create! :name => 'Bjorn', :salary => 100000 + assert !developer.name_changed? + assert !developer.salary_changed? + + cloned_developer = developer.clone + assert cloned_developer.name_changed? # both attributes differ from defaults + assert cloned_developer.salary_changed? + end + + def test_clone_of_saved_object_marks_as_dirty_only_changed_attributes + developer = Developer.create! :name => 'Bjorn' + assert !developer.name_changed? # both attributes of saved object should be threated as not changed + assert !developer.salary_changed? + + cloned_developer = developer.clone + assert cloned_developer.name_changed? # ... but on cloned object should be + assert !cloned_developer.salary_changed? # ... BUT salary has non-nil default which should be threated as not changed on cloned instance + end + def test_bignum company = Company.find(1) company.rating = 2147483647 diff --git a/activerecord/test/cases/column_definition_test.rb b/activerecord/test/cases/column_definition_test.rb index 8b6c019d50..b5767344cd 100644 --- a/activerecord/test/cases/column_definition_test.rb +++ b/activerecord/test/cases/column_definition_test.rb @@ -71,17 +71,17 @@ class ColumnDefinitionTest < ActiveRecord::TestCase if current_adapter?(:PostgreSQLAdapter) def test_bigint_column_should_map_to_integer bigint_column = ActiveRecord::ConnectionAdapters::PostgreSQLColumn.new('number', nil, "bigint") - assert_equal bigint_column.type, :integer + assert_equal :integer, bigint_column.type end def test_smallint_column_should_map_to_integer smallint_column = ActiveRecord::ConnectionAdapters::PostgreSQLColumn.new('number', nil, "smallint") - assert_equal smallint_column.type, :integer + assert_equal :integer, smallint_column.type end def test_uuid_column_should_map_to_string uuid_column = ActiveRecord::ConnectionAdapters::PostgreSQLColumn.new('unique_id', nil, "uuid") - assert_equal uuid_column.type, :string + assert_equal :string, uuid_column.type end end end diff --git a/activerecord/test/cases/defaults_test.rb b/activerecord/test/cases/defaults_test.rb index bba216ae19..39aafa1ec7 100644 --- a/activerecord/test/cases/defaults_test.rb +++ b/activerecord/test/cases/defaults_test.rb @@ -67,8 +67,8 @@ if current_adapter?(:MysqlAdapter) assert_equal '', klass.columns_hash['non_null_blob'].default assert_equal '', klass.columns_hash['non_null_text'].default - assert_equal nil, klass.columns_hash['null_blob'].default - assert_equal nil, klass.columns_hash['null_text'].default + assert_nil klass.columns_hash['null_blob'].default + assert_nil klass.columns_hash['null_text'].default assert_nothing_raised do instance = klass.create! diff --git a/activerecord/test/cases/dirty_test.rb b/activerecord/test/cases/dirty_test.rb index 3ea2948f62..75f7453aa9 100644 --- a/activerecord/test/cases/dirty_test.rb +++ b/activerecord/test/cases/dirty_test.rb @@ -103,7 +103,7 @@ class DirtyTest < ActiveRecord::TestCase assert pirate.created_on_changed? # kind_of does not work because # ActiveSupport::TimeWithZone.name == 'Time' - assert_equal Time, pirate.created_on_was.class + assert_instance_of Time, pirate.created_on_was assert_equal old_created_on, pirate.created_on_was end end @@ -132,7 +132,7 @@ class DirtyTest < ActiveRecord::TestCase assert pirate.created_on_changed? # kind_of does not work because # ActiveSupport::TimeWithZone.name == 'Time' - assert_equal Time, pirate.created_on_was.class + assert_instance_of Time, pirate.created_on_was assert_equal old_created_on, pirate.created_on_was end diff --git a/activerecord/test/cases/finder_respond_to_test.rb b/activerecord/test/cases/finder_respond_to_test.rb index 4e6fecf11a..235805a67c 100644 --- a/activerecord/test/cases/finder_respond_to_test.rb +++ b/activerecord/test/cases/finder_respond_to_test.rb @@ -7,53 +7,53 @@ class FinderRespondToTest < ActiveRecord::TestCase def test_should_preserve_normal_respond_to_behaviour_and_respond_to_newly_added_method class << Topic; self; end.send(:define_method, :method_added_for_finder_respond_to_test) { } - assert Topic.respond_to?(:method_added_for_finder_respond_to_test) + assert_respond_to Topic, :method_added_for_finder_respond_to_test ensure class << Topic; self; end.send(:remove_method, :method_added_for_finder_respond_to_test) end def test_should_preserve_normal_respond_to_behaviour_and_respond_to_standard_object_method - assert Topic.respond_to?(:to_s) + assert_respond_to Topic, :to_s end def test_should_respond_to_find_by_one_attribute_before_caching ensure_topic_method_is_not_cached(:find_by_title) - assert Topic.respond_to?(:find_by_title) + assert_respond_to Topic, :find_by_title end def test_should_respond_to_find_all_by_one_attribute ensure_topic_method_is_not_cached(:find_all_by_title) - assert Topic.respond_to?(:find_all_by_title) + assert_respond_to Topic, :find_all_by_title end def test_should_respond_to_find_all_by_two_attributes ensure_topic_method_is_not_cached(:find_all_by_title_and_author_name) - assert Topic.respond_to?(:find_all_by_title_and_author_name) + assert_respond_to Topic, :find_all_by_title_and_author_name end def test_should_respond_to_find_by_two_attributes ensure_topic_method_is_not_cached(:find_by_title_and_author_name) - assert Topic.respond_to?(:find_by_title_and_author_name) + assert_respond_to Topic, :find_by_title_and_author_name end def test_should_respond_to_find_or_initialize_from_one_attribute ensure_topic_method_is_not_cached(:find_or_initialize_by_title) - assert Topic.respond_to?(:find_or_initialize_by_title) + assert_respond_to Topic, :find_or_initialize_by_title end def test_should_respond_to_find_or_initialize_from_two_attributes ensure_topic_method_is_not_cached(:find_or_initialize_by_title_and_author_name) - assert Topic.respond_to?(:find_or_initialize_by_title_and_author_name) + assert_respond_to Topic, :find_or_initialize_by_title_and_author_name end def test_should_respond_to_find_or_create_from_one_attribute ensure_topic_method_is_not_cached(:find_or_create_by_title) - assert Topic.respond_to?(:find_or_create_by_title) + assert_respond_to Topic, :find_or_create_by_title end def test_should_respond_to_find_or_create_from_two_attributes ensure_topic_method_is_not_cached(:find_or_create_by_title_and_author_name) - assert Topic.respond_to?(:find_or_create_by_title_and_author_name) + assert_respond_to Topic, :find_or_create_by_title_and_author_name end def test_should_not_respond_to_find_by_one_missing_attribute @@ -73,4 +73,4 @@ class FinderRespondToTest < ActiveRecord::TestCase class << Topic; self; end.send(:remove_method, method_id) if Topic.public_methods.any? { |m| m.to_s == method_id.to_s } end -end
\ No newline at end of file +end diff --git a/activerecord/test/cases/finder_test.rb b/activerecord/test/cases/finder_test.rb index c73ad50a71..860d330a7f 100644 --- a/activerecord/test/cases/finder_test.rb +++ b/activerecord/test/cases/finder_test.rb @@ -255,7 +255,7 @@ class FinderTest < ActiveRecord::TestCase assert !topic.attribute_present?("title") #assert !topic.respond_to?("title") assert topic.attribute_present?("author_name") - assert topic.respond_to?("author_name") + assert_respond_to topic, "author_name" end def test_find_on_blank_conditions diff --git a/activerecord/test/cases/inheritance_test.rb b/activerecord/test/cases/inheritance_test.rb index 0672fb938b..c1c8f01e46 100644 --- a/activerecord/test/cases/inheritance_test.rb +++ b/activerecord/test/cases/inheritance_test.rb @@ -72,10 +72,10 @@ class InheritanceTest < ActiveRecord::TestCase end def test_inheritance_find - assert Company.find(1).kind_of?(Firm), "37signals should be a firm" - assert Firm.find(1).kind_of?(Firm), "37signals should be a firm" - assert Company.find(2).kind_of?(Client), "Summit should be a client" - assert Client.find(2).kind_of?(Client), "Summit should be a client" + assert_kind_of Firm, Company.find(1), "37signals should be a firm" + assert_kind_of Firm, Firm.find(1), "37signals should be a firm" + assert_kind_of Client, Company.find(2), "Summit should be a client" + assert_kind_of Client, Client.find(2), "Summit should be a client" end def test_alt_inheritance_find @@ -86,8 +86,8 @@ class InheritanceTest < ActiveRecord::TestCase def test_inheritance_find_all companies = Company.find(:all, :order => 'id') - assert companies[0].kind_of?(Firm), "37signals should be a firm" - assert companies[1].kind_of?(Client), "Summit should be a client" + assert_kind_of Firm, companies[0], "37signals should be a firm" + assert_kind_of Client, companies[1], "Summit should be a client" end def test_alt_inheritance_find_all @@ -102,7 +102,7 @@ class InheritanceTest < ActiveRecord::TestCase firm.save next_angle = Company.find(firm.id) - assert next_angle.kind_of?(Firm), "Next Angle should be a firm" + assert_kind_of Firm, next_angle, "Next Angle should be a firm" end def test_alt_inheritance_save diff --git a/activerecord/test/cases/method_scoping_test.rb b/activerecord/test/cases/method_scoping_test.rb index 3a6354ec6d..e93f22bede 100644 --- a/activerecord/test/cases/method_scoping_test.rb +++ b/activerecord/test/cases/method_scoping_test.rb @@ -587,18 +587,6 @@ class HasAndBelongsToManyScopingTest< ActiveRecord::TestCase end end -class ClearDefaultScopeTest < ActiveRecord::TestCase - fixtures :developers - - def test_should_clear_default_scope - klass = Class.new(DeveloperCalledDavid) - klass.__send__ :clear_default_scope - expected = Developer.all.collect { |dev| dev.name } - actual = klass.all.collect { |dev| dev.name } - assert_equal expected, actual - end -end - class DefaultScopingTest < ActiveRecord::TestCase fixtures :developers, :posts @@ -634,7 +622,7 @@ class DefaultScopingTest < ActiveRecord::TestCase assert_equal ['salary DESC'], klass.scoped.order_values # Parent should still have the original scope - assert_equal nil, DeveloperOrderedBySalary.scoped.limit_value + assert_nil DeveloperOrderedBySalary.scoped.limit_value assert_equal ['salary DESC'], DeveloperOrderedBySalary.scoped.order_values end diff --git a/activerecord/test/cases/migration_test.rb b/activerecord/test/cases/migration_test.rb index 768a44f6df..b5fa258f7b 100644 --- a/activerecord/test/cases/migration_test.rb +++ b/activerecord/test/cases/migration_test.rb @@ -119,6 +119,40 @@ if ActiveRecord::Base.connection.supports_migrations? end end + def test_add_index_length_limit + good_index_name = 'x' * Person.connection.index_name_length + too_long_index_name = good_index_name + 'x' + assert_nothing_raised { Person.connection.add_index("people", "first_name", :name => too_long_index_name) } + assert !Person.connection.index_exists?("people", too_long_index_name, false) + assert_nothing_raised { Person.connection.add_index("people", "first_name", :name => good_index_name) } + assert Person.connection.index_exists?("people", good_index_name, false) + end + + def test_remove_nonexistent_index + # we do this by name, so OpenBase is a wash as noted above + unless current_adapter?(:OpenBaseAdapter) + assert_nothing_raised { Person.connection.remove_index("people", "no_such_index") } + end + end + + def test_rename_index + unless current_adapter?(:OpenBaseAdapter) + # keep the names short to make Oracle and similar behave + Person.connection.add_index('people', [:first_name], :name => 'old_idx') + assert_nothing_raised { Person.connection.rename_index('people', 'old_idx', 'new_idx') } + # if the adapter doesn't support the indexes call, pick defaults that let the test pass + assert !Person.connection.index_exists?('people', 'old_idx', false) + assert Person.connection.index_exists?('people', 'new_idx', true) + end + end + + def test_double_add_index + unless current_adapter?(:OpenBaseAdapter) + Person.connection.add_index('people', [:first_name], :name => 'some_idx') + assert_nothing_raised { Person.connection.add_index('people', [:first_name], :name => 'some_idx') } + end + end + def testing_table_with_only_foo_attribute Person.connection.create_table :testings, :id => false do |t| t.column :foo, :string @@ -491,7 +525,7 @@ if ActiveRecord::Base.connection.supports_migrations? end end - assert_equal TrueClass, bob.male?.class + assert_instance_of TrueClass, bob.male? assert_kind_of BigDecimal, bob.wealth end @@ -860,18 +894,6 @@ if ActiveRecord::Base.connection.supports_migrations? assert_equal "Tester", Person.new.first_name end - unless current_adapter?(:PostgreSQLAdapter) - def test_change_column_type_default_should_change - old_columns = Person.connection.columns(Person.table_name, "#{name} Columns") - assert !old_columns.find { |c| c.name == 'data' } - - assert_nothing_raised do - Person.connection.add_column "people", "data", :string, :default => '' - Person.connection.change_column "people", "data", :binary - end - end - end - def test_change_column_quotes_column_names Person.connection.create_table :testings do |t| t.column :select, :string diff --git a/activerecord/test/cases/modules_test.rb b/activerecord/test/cases/modules_test.rb index c924c3dfad..4b635792c7 100644 --- a/activerecord/test/cases/modules_test.rb +++ b/activerecord/test/cases/modules_test.rb @@ -35,7 +35,7 @@ class ModulesTest < ActiveRecord::TestCase def test_module_spanning_has_and_belongs_to_many_associations project = MyApplication::Business::Project.find(:first) project.developers << MyApplication::Business::Developer.create("name" => "John") - assert "John", project.developers.last.name + assert_equal "John", project.developers.last.name end def test_associations_spanning_cross_modules diff --git a/activerecord/test/cases/nested_attributes_test.rb b/activerecord/test/cases/nested_attributes_test.rb index fadd62b5a1..57b66fb312 100644 --- a/activerecord/test/cases/nested_attributes_test.rb +++ b/activerecord/test/cases/nested_attributes_test.rb @@ -1,6 +1,7 @@ require "cases/helper" require "models/pirate" require "models/ship" +require "models/ship_part" require "models/bird" require "models/parrot" require "models/treasure" @@ -732,3 +733,82 @@ class TestNestedAttributesWithNonStandardPrimaryKeys < ActiveRecord::TestCase assert_equal ['Foo', 'Bar'], @owner.pets.map(&:name) end end + +class TestHasOneAutosaveAssoictaionWhichItselfHasAutosaveAssociations < ActiveRecord::TestCase + self.use_transactional_fixtures = false + + def setup + @pirate = Pirate.create!(:catchphrase => "My baby takes tha mornin' train!") + @ship = @pirate.create_ship(:name => "The good ship Dollypop") + @part = @ship.parts.create!(:name => "Mast") + @trinket = @part.trinkets.create!(:name => "Necklace") + end + + test "when great-grandchild changed in memory, saving parent should save great-grandchild" do + @trinket.name = "changed" + @pirate.save + assert_equal "changed", @trinket.reload.name + end + + test "when great-grandchild changed via attributes, saving parent should save great-grandchild" do + @pirate.attributes = {:ship_attributes => {:id => @ship.id, :parts_attributes => [{:id => @part.id, :trinkets_attributes => [{:id => @trinket.id, :name => "changed"}]}]}} + @pirate.save + assert_equal "changed", @trinket.reload.name + end + + test "when great-grandchild marked_for_destruction via attributes, saving parent should destroy great-grandchild" do + @pirate.attributes = {:ship_attributes => {:id => @ship.id, :parts_attributes => [{:id => @part.id, :trinkets_attributes => [{:id => @trinket.id, :_destroy => true}]}]}} + assert_difference('@part.trinkets.count', -1) { @pirate.save } + end + + test "when great-grandchild added via attributes, saving parent should create great-grandchild" do + @pirate.attributes = {:ship_attributes => {:id => @ship.id, :parts_attributes => [{:id => @part.id, :trinkets_attributes => [{:name => "created"}]}]}} + assert_difference('@part.trinkets.count', 1) { @pirate.save } + end + + test "when extra records exist for associations, validate (which calls nested_records_changed_for_autosave?) should not load them up" do + @trinket.name = "changed" + Ship.create!(:pirate => @pirate, :name => "The Black Rock") + ShipPart.create!(:ship => @ship, :name => "Stern") + assert_no_queries { @pirate.valid? } + end +end + +class TestHasManyAutosaveAssoictaionWhichItselfHasAutosaveAssociations < ActiveRecord::TestCase + self.use_transactional_fixtures = false + + def setup + @ship = Ship.create!(:name => "The good ship Dollypop") + @part = @ship.parts.create!(:name => "Mast") + @trinket = @part.trinkets.create!(:name => "Necklace") + end + + test "when grandchild changed in memory, saving parent should save grandchild" do + @trinket.name = "changed" + @ship.save + assert_equal "changed", @trinket.reload.name + end + + test "when grandchild changed via attributes, saving parent should save grandchild" do + @ship.attributes = {:parts_attributes => [{:id => @part.id, :trinkets_attributes => [{:id => @trinket.id, :name => "changed"}]}]} + @ship.save + assert_equal "changed", @trinket.reload.name + end + + test "when grandchild marked_for_destruction via attributes, saving parent should destroy grandchild" do + @ship.attributes = {:parts_attributes => [{:id => @part.id, :trinkets_attributes => [{:id => @trinket.id, :_destroy => true}]}]} + assert_difference('@part.trinkets.count', -1) { @ship.save } + end + + test "when grandchild added via attributes, saving parent should create grandchild" do + @ship.attributes = {:parts_attributes => [{:id => @part.id, :trinkets_attributes => [{:name => "created"}]}]} + assert_difference('@part.trinkets.count', 1) { @ship.save } + end + + test "when extra records exist for associations, validate (which calls nested_records_changed_for_autosave?) should not load them up" do + @trinket.name = "changed" + Ship.create!(:name => "The Black Rock") + ShipPart.create!(:ship => @ship, :name => "Stern") + assert_no_queries { @ship.valid? } + end +end diff --git a/activerecord/test/cases/pk_test.rb b/activerecord/test/cases/pk_test.rb index 33ad5992de..73f4b3848c 100644 --- a/activerecord/test/cases/pk_test.rb +++ b/activerecord/test/cases/pk_test.rb @@ -18,7 +18,7 @@ class PrimaryKeysTest < ActiveRecord::TestCase def test_to_key_with_customized_primary_key keyboard = Keyboard.new - assert keyboard.to_key.nil? + assert_nil keyboard.to_key keyboard.save assert_equal keyboard.to_key, [keyboard.id] end @@ -37,7 +37,7 @@ class PrimaryKeysTest < ActiveRecord::TestCase topic = Topic.new topic.title = "New Topic" - assert_equal(nil, topic.id) + assert_nil topic.id assert_nothing_raised { topic.save! } id = topic.id diff --git a/activerecord/test/cases/pooled_connections_test.rb b/activerecord/test/cases/pooled_connections_test.rb index 94d6663778..e61960059e 100644 --- a/activerecord/test/cases/pooled_connections_test.rb +++ b/activerecord/test/cases/pooled_connections_test.rb @@ -34,8 +34,8 @@ class PooledConnectionsTest < ActiveRecord::TestCase if RUBY_VERSION < '1.9' def test_pooled_connection_checkout checkout_connections - assert_equal @connections.length, 2 - assert_equal @timed_out, 2 + assert_equal 2, @connections.length + assert_equal 2, @timed_out end end @@ -137,4 +137,4 @@ class PooledConnectionsTest < ActiveRecord::TestCase def add_record(name) ActiveRecord::Base.connection_pool.with_connection { Project.create! :name => name } end -end unless %w(FrontBase).include? ActiveRecord::Base.connection.adapter_name
\ No newline at end of file +end unless %w(FrontBase).include? ActiveRecord::Base.connection.adapter_name diff --git a/activerecord/test/cases/query_cache_test.rb b/activerecord/test/cases/query_cache_test.rb index 91349689bc..68abca70b3 100644 --- a/activerecord/test/cases/query_cache_test.rb +++ b/activerecord/test/cases/query_cache_test.rb @@ -58,7 +58,7 @@ class QueryCacheTest < ActiveRecord::TestCase Task.cache do # Oracle adapter returns count() as Fixnum or Float if current_adapter?(:OracleAdapter) - assert Task.connection.select_value("SELECT count(*) AS count_all FROM tasks").is_a?(Numeric) + assert_kind_of Numeric, Task.connection.select_value("SELECT count(*) AS count_all FROM tasks") elsif current_adapter?(:SQLite3Adapter) && SQLite3::Version::VERSION > '1.2.5' # Future versions of the sqlite3 adapter will return numeric assert_instance_of Fixnum, diff --git a/activerecord/test/cases/relations_test.rb b/activerecord/test/cases/relations_test.rb index 7b9e680c02..b6815af67e 100644 --- a/activerecord/test/cases/relations_test.rb +++ b/activerecord/test/cases/relations_test.rb @@ -145,7 +145,7 @@ class RelationTest < ActiveRecord::TestCase relation = Topic.scoped ["map", "uniq", "sort", "insert", "delete", "update"].each do |method| - assert relation.respond_to?(method), "Topic.scoped should respond to #{method.inspect}" + assert_respond_to relation, method, "Topic.scoped should respond to #{method.inspect}" end end @@ -160,7 +160,7 @@ class RelationTest < ActiveRecord::TestCase relation = Topic.scoped ["find_by_title", "find_by_title_and_author_name", "find_or_create_by_title", "find_or_initialize_by_title_and_author_name"].each do |method| - assert relation.respond_to?(method), "Topic.scoped should respond to #{method.inspect}" + assert_respond_to relation, method, "Topic.scoped should respond to #{method.inspect}" end end @@ -238,7 +238,7 @@ class RelationTest < ActiveRecord::TestCase def test_default_scope_with_conditions_string assert_equal Developer.find_all_by_name('David').map(&:id).sort, DeveloperCalledDavid.scoped.map(&:id).sort - assert_equal nil, DeveloperCalledDavid.create!.name + assert_nil DeveloperCalledDavid.create!.name end def test_default_scope_with_conditions_hash diff --git a/activerecord/test/cases/reserved_word_test_mysql.rb b/activerecord/test/cases/reserved_word_test_mysql.rb index ce1622bb20..90d8b0d923 100644 --- a/activerecord/test/cases/reserved_word_test_mysql.rb +++ b/activerecord/test/cases/reserved_word_test_mysql.rb @@ -115,7 +115,7 @@ class MysqlReservedWordTest < ActiveRecord::TestCase create_test_fixtures :select, :distinct, :group, :values, :distincts_selects v = nil assert_nothing_raised { v = Group.find(1).values } - assert_equal v.id, 2 + assert_equal 2, v.id end # belongs_to association with reserved-word table name diff --git a/activerecord/test/cases/schema_test_postgresql.rb b/activerecord/test/cases/schema_test_postgresql.rb index 3ed73786a7..3ed9b1974d 100644 --- a/activerecord/test/cases/schema_test_postgresql.rb +++ b/activerecord/test/cases/schema_test_postgresql.rb @@ -152,11 +152,11 @@ class SchemaTest < ActiveRecord::TestCase def test_with_uppercase_index_name ActiveRecord::Base.connection.execute "CREATE INDEX \"things_Index\" ON #{SCHEMA_NAME}.things (name)" - assert_nothing_raised { ActiveRecord::Base.connection.remove_index :things, :name => "#{SCHEMA_NAME}.things_Index"} + assert_nothing_raised { ActiveRecord::Base.connection.remove_index! "things", "#{SCHEMA_NAME}.things_Index"} ActiveRecord::Base.connection.execute "CREATE INDEX \"things_Index\" ON #{SCHEMA_NAME}.things (name)" ActiveRecord::Base.connection.schema_search_path = SCHEMA_NAME - assert_nothing_raised { ActiveRecord::Base.connection.remove_index :things, :name => "things_Index"} + assert_nothing_raised { ActiveRecord::Base.connection.remove_index! "things", "things_Index"} ActiveRecord::Base.connection.schema_search_path = "public" end diff --git a/activerecord/test/cases/timestamp_test.rb b/activerecord/test/cases/timestamp_test.rb index 24b237a72b..549c4af6b1 100644 --- a/activerecord/test/cases/timestamp_test.rb +++ b/activerecord/test/cases/timestamp_test.rb @@ -15,26 +15,26 @@ class TimestampTest < ActiveRecord::TestCase @developer.name = "Jack Bauer" @developer.save! - assert @previously_updated_at != @developer.updated_at + assert_not_equal @previously_updated_at, @developer.updated_at end def test_saving_a_unchanged_record_doesnt_update_its_timestamp @developer.save! - assert @previously_updated_at == @developer.updated_at + assert_equal @previously_updated_at, @developer.updated_at end def test_touching_a_record_updates_its_timestamp @developer.touch - assert @previously_updated_at != @developer.updated_at + assert_not_equal @previously_updated_at, @developer.updated_at end def test_touching_a_different_attribute previously_created_at = @developer.created_at @developer.touch(:created_at) - assert previously_created_at != @developer.created_at + assert_not_equal previously_created_at, @developer.created_at end def test_saving_a_record_with_a_belongs_to_that_specifies_touching_the_parent_should_update_the_parent_updated_at @@ -45,7 +45,7 @@ class TimestampTest < ActiveRecord::TestCase pet.name = "Fluffy the Third" pet.save - assert previously_owner_updated_at != pet.owner.updated_at + assert_not_equal previously_owner_updated_at, pet.owner.updated_at end def test_destroying_a_record_with_a_belongs_to_that_specifies_touching_the_parent_should_update_the_parent_updated_at @@ -55,7 +55,7 @@ class TimestampTest < ActiveRecord::TestCase pet.destroy - assert previously_owner_updated_at != pet.owner.updated_at + assert_not_equal previously_owner_updated_at, pet.owner.updated_at end def test_saving_a_record_with_a_belongs_to_that_specifies_touching_a_specific_attribute_the_parent_should_update_that_attribute @@ -68,8 +68,8 @@ class TimestampTest < ActiveRecord::TestCase pet.name = "Fluffy the Third" pet.save - assert previously_owner_happy_at != pet.owner.happy_at + assert_not_equal previously_owner_happy_at, pet.owner.happy_at ensure Pet.belongs_to :owner, :touch => true end -end
\ No newline at end of file +end diff --git a/activerecord/test/cases/transaction_callbacks_test.rb b/activerecord/test/cases/transaction_callbacks_test.rb index a07da093f1..ebc16653cb 100644 --- a/activerecord/test/cases/transaction_callbacks_test.rb +++ b/activerecord/test/cases/transaction_callbacks_test.rb @@ -54,33 +54,31 @@ class TransactionCallbacksTest < ActiveRecord::TestCase @first.after_rollback_block{|r| r.history << :after_rollback} @first.save! - assert @first.history, [:after_commit] + assert_equal [:after_commit], @first.history end def test_only_call_after_commit_on_update_after_transaction_commits_for_existing_record - commit_callback = [] @first.after_commit_block(:create){|r| r.history << :commit_on_create} @first.after_commit_block(:update){|r| r.history << :commit_on_update} @first.after_commit_block(:destroy){|r| r.history << :commit_on_destroy} - @first.after_commit_block(:create){|r| r.history << :rollback_on_create} - @first.after_commit_block(:update){|r| r.history << :rollback_on_update} - @first.after_commit_block(:destroy){|r| r.history << :rollback_on_destroy} + @first.after_rollback_block(:create){|r| r.history << :rollback_on_create} + @first.after_rollback_block(:update){|r| r.history << :rollback_on_update} + @first.after_rollback_block(:destroy){|r| r.history << :rollback_on_destroy} @first.save! - assert @first.history, [:commit_on_update] + assert_equal [:commit_on_update], @first.history end def test_only_call_after_commit_on_destroy_after_transaction_commits_for_destroyed_record - commit_callback = [] @first.after_commit_block(:create){|r| r.history << :commit_on_create} @first.after_commit_block(:update){|r| r.history << :commit_on_update} @first.after_commit_block(:destroy){|r| r.history << :commit_on_destroy} - @first.after_commit_block(:create){|r| r.history << :rollback_on_create} - @first.after_commit_block(:update){|r| r.history << :rollback_on_update} - @first.after_commit_block(:destroy){|r| r.history << :rollback_on_destroy} + @first.after_rollback_block(:create){|r| r.history << :rollback_on_create} + @first.after_rollback_block(:update){|r| r.history << :rollback_on_update} + @first.after_rollback_block(:destroy){|r| r.history << :rollback_on_destroy} @first.destroy - assert @first.history, [:commit_on_destroy] + assert_equal [:commit_on_destroy], @first.history end def test_only_call_after_commit_on_create_after_transaction_commits_for_new_record @@ -88,12 +86,12 @@ class TransactionCallbacksTest < ActiveRecord::TestCase @new_record.after_commit_block(:create){|r| r.history << :commit_on_create} @new_record.after_commit_block(:update){|r| r.history << :commit_on_update} @new_record.after_commit_block(:destroy){|r| r.history << :commit_on_destroy} - @new_record.after_commit_block(:create){|r| r.history << :rollback_on_create} - @new_record.after_commit_block(:update){|r| r.history << :rollback_on_update} - @new_record.after_commit_block(:destroy){|r| r.history << :rollback_on_destroy} + @new_record.after_rollback_block(:create){|r| r.history << :rollback_on_create} + @new_record.after_rollback_block(:update){|r| r.history << :rollback_on_update} + @new_record.after_rollback_block(:destroy){|r| r.history << :rollback_on_destroy} @new_record.save! - assert @new_record.history, [:commit_on_create] + assert_equal [:commit_on_create], @new_record.history end def test_call_after_rollback_after_transaction_rollsback @@ -105,41 +103,39 @@ class TransactionCallbacksTest < ActiveRecord::TestCase raise ActiveRecord::Rollback end - assert @first.history, [:after_rollback] + assert_equal [:after_rollback], @first.history end def test_only_call_after_rollback_on_update_after_transaction_rollsback_for_existing_record - commit_callback = [] @first.after_commit_block(:create){|r| r.history << :commit_on_create} @first.after_commit_block(:update){|r| r.history << :commit_on_update} @first.after_commit_block(:destroy){|r| r.history << :commit_on_destroy} - @first.after_commit_block(:create){|r| r.history << :rollback_on_create} - @first.after_commit_block(:update){|r| r.history << :rollback_on_update} - @first.after_commit_block(:destroy){|r| r.history << :rollback_on_destroy} + @first.after_rollback_block(:create){|r| r.history << :rollback_on_create} + @first.after_rollback_block(:update){|r| r.history << :rollback_on_update} + @first.after_rollback_block(:destroy){|r| r.history << :rollback_on_destroy} Topic.transaction do @first.save! raise ActiveRecord::Rollback end - assert @first.history, [:rollback_on_update] + assert_equal [:rollback_on_update], @first.history end def test_only_call_after_rollback_on_destroy_after_transaction_rollsback_for_destroyed_record - commit_callback = [] @first.after_commit_block(:create){|r| r.history << :commit_on_create} @first.after_commit_block(:update){|r| r.history << :commit_on_update} @first.after_commit_block(:destroy){|r| r.history << :commit_on_update} - @first.after_commit_block(:create){|r| r.history << :rollback_on_create} - @first.after_commit_block(:update){|r| r.history << :rollback_on_update} - @first.after_commit_block(:destroy){|r| r.history << :rollback_on_destroy} + @first.after_rollback_block(:create){|r| r.history << :rollback_on_create} + @first.after_rollback_block(:update){|r| r.history << :rollback_on_update} + @first.after_rollback_block(:destroy){|r| r.history << :rollback_on_destroy} Topic.transaction do @first.destroy raise ActiveRecord::Rollback end - assert @first.history, [:rollback_on_destroy] + assert_equal [:rollback_on_destroy], @first.history end def test_only_call_after_rollback_on_create_after_transaction_rollsback_for_new_record @@ -147,16 +143,16 @@ class TransactionCallbacksTest < ActiveRecord::TestCase @new_record.after_commit_block(:create){|r| r.history << :commit_on_create} @new_record.after_commit_block(:update){|r| r.history << :commit_on_update} @new_record.after_commit_block(:destroy){|r| r.history << :commit_on_destroy} - @new_record.after_commit_block(:create){|r| r.history << :rollback_on_create} - @new_record.after_commit_block(:update){|r| r.history << :rollback_on_update} - @new_record.after_commit_block(:destroy){|r| r.history << :rollback_on_destroy} + @new_record.after_rollback_block(:create){|r| r.history << :rollback_on_create} + @new_record.after_rollback_block(:update){|r| r.history << :rollback_on_update} + @new_record.after_rollback_block(:destroy){|r| r.history << :rollback_on_destroy} Topic.transaction do @new_record.save! raise ActiveRecord::Rollback end - assert @new_record.history, [:rollback_on_create] + assert_equal [:rollback_on_create], @new_record.history end def test_call_after_rollback_when_commit_fails @@ -170,7 +166,7 @@ class TransactionCallbacksTest < ActiveRecord::TestCase @first.after_rollback_block{|r| r.history << :after_rollback} assert !@first.save rescue nil - assert @first.history == [:after_rollback] + assert_equal [:after_rollback], @first.history ensure @first.connection.class.send(:remove_method, :commit_db_transaction) @first.connection.class.send(:alias_method, :commit_db_transaction, :real_method_commit_db_transaction) @@ -196,18 +192,18 @@ class TransactionCallbacksTest < ActiveRecord::TestCase end end - assert 1, @first.commits - assert 0, @first.rollbacks - assert 1, @second.commits - assert 1, @second.rollbacks + assert_equal 1, @first.commits + assert_equal 0, @first.rollbacks + assert_equal 0, @second.commits + assert_equal 1, @second.rollbacks end def test_only_call_after_rollback_on_records_rolled_back_to_a_savepoint_when_release_savepoint_fails def @first.rollbacks(i=0); @rollbacks ||= 0; @rollbacks += i if i; end def @first.commits(i=0); @commits ||= 0; @commits += i if i; end - @second.after_rollback_block{|r| r.rollbacks(1)} - @second.after_commit_block{|r| r.commits(1)} + @first.after_rollback_block{|r| r.rollbacks(1)} + @first.after_commit_block{|r| r.commits(1)} Topic.transaction do @first.save @@ -221,8 +217,8 @@ class TransactionCallbacksTest < ActiveRecord::TestCase end end - assert 1, @first.commits - assert 2, @first.rollbacks + assert_equal 1, @first.commits + assert_equal 2, @first.rollbacks end def test_after_transaction_callbacks_should_not_raise_errors @@ -232,13 +228,13 @@ class TransactionCallbacksTest < ActiveRecord::TestCase @first.after_rollback_block{|r| r.last_after_transaction_error = :rollback; raise "fail!";} @first.save! - assert_equal @first.last_after_transaction_error, :commit + assert_equal :commit, @first.last_after_transaction_error Topic.transaction do @first.save! raise ActiveRecord::Rollback end - assert_equal @first.last_after_transaction_error, :rollback + assert_equal :rollback, @first.last_after_transaction_error end end diff --git a/activerecord/test/models/ship.rb b/activerecord/test/models/ship.rb index 75c792d176..3da031946f 100644 --- a/activerecord/test/models/ship.rb +++ b/activerecord/test/models/ship.rb @@ -3,8 +3,9 @@ class Ship < ActiveRecord::Base belongs_to :pirate belongs_to :update_only_pirate, :class_name => 'Pirate' - has_many :parts, :class_name => 'ShipPart', :autosave => true + has_many :parts, :class_name => 'ShipPart' + accepts_nested_attributes_for :parts, :allow_destroy => true accepts_nested_attributes_for :pirate, :allow_destroy => true, :reject_if => proc { |attributes| attributes.empty? } accepts_nested_attributes_for :update_only_pirate, :update_only => true diff --git a/activerecord/test/models/ship_part.rb b/activerecord/test/models/ship_part.rb index 0a606db239..b6a8a506b4 100644 --- a/activerecord/test/models/ship_part.rb +++ b/activerecord/test/models/ship_part.rb @@ -1,5 +1,7 @@ class ShipPart < ActiveRecord::Base belongs_to :ship + has_many :trinkets, :class_name => "Treasure", :as => :looter + accepts_nested_attributes_for :trinkets, :allow_destroy => true validates_presence_of :name end
\ No newline at end of file |