diff options
Diffstat (limited to 'activerecord')
69 files changed, 448 insertions, 329 deletions
diff --git a/activerecord/CHANGELOG.md b/activerecord/CHANGELOG.md index 929f241b1b..0bd3c2e78c 100644 --- a/activerecord/CHANGELOG.md +++ b/activerecord/CHANGELOG.md @@ -1,3 +1,8 @@ +* Ensure hashes can be assigned to attributes created using `composed_of`. + Fixes #25210. + + *Sean Griffin* + * Fix logging edge case where if an attribute was of the binary type and was provided as a Hash. @@ -13,4 +18,18 @@ *Erol Fornoles* +* PostgreSQL: Fix db:structure:load silent failure on SQL error + + The command line flag "-v ON_ERROR_STOP=1" should be used + when invoking psql to make sure errors are not suppressed. + + Example: + + psql -v ON_ERROR_STOP=1 -q -f awesome-file.sql my-app-db + + Fixes #23818. + + *Ralin Chimev* + + Please check [5-0-stable](https://github.com/rails/rails/blob/5-0-stable/activerecord/CHANGELOG.md) for previous changes. diff --git a/activerecord/Rakefile b/activerecord/Rakefile index 46df733cfe..012db35765 100644 --- a/activerecord/Rakefile +++ b/activerecord/Rakefile @@ -21,7 +21,6 @@ desc 'Run mysql2, sqlite, and postgresql tests by default' task :default => :test task :package -task "package:clean" desc 'Run mysql2, sqlite, and postgresql tests' task :test do diff --git a/activerecord/lib/active_record/aggregations.rb b/activerecord/lib/active_record/aggregations.rb index 3ff41ed81b..8bed5bca28 100644 --- a/activerecord/lib/active_record/aggregations.rb +++ b/activerecord/lib/active_record/aggregations.rb @@ -256,15 +256,16 @@ module ActiveRecord def writer_method(name, class_name, mapping, allow_nil, converter) define_method("#{name}=") do |part| klass = class_name.constantize - if part.is_a?(Hash) - raise ArgumentError unless part.size == part.keys.max - part = klass.new(*part.sort.map(&:last)) - end unless part.is_a?(klass) || converter.nil? || part.nil? part = converter.respond_to?(:call) ? converter.call(part) : klass.send(converter, part) end + if part.is_a?(Hash) + raise ArgumentError unless part.size == part.keys.max + part = klass.new(*part.sort.map(&:last)) + end + if part.nil? && allow_nil mapping.each { |key, _| self[key] = nil } @aggregation_cache[name] = nil diff --git a/activerecord/lib/active_record/associations.rb b/activerecord/lib/active_record/associations.rb index 5a973fa801..3729e22e64 100644 --- a/activerecord/lib/active_record/associations.rb +++ b/activerecord/lib/active_record/associations.rb @@ -300,10 +300,10 @@ module ActiveRecord # # === A word of warning # - # Don't create associations that have the same name as instance methods of - # ActiveRecord::Base. Since the association adds a method with that name to - # its model, it will override the inherited method and break things. - # For instance, +attributes+ and +connection+ would be bad choices for association names. + # Don't create associations that have the same name as {instance methods}[rdoc-ref:ActiveRecord::Core] of + # <tt>ActiveRecord::Base</tt>. Since the association adds a method with that name to + # its model, using an association with the same name as one provided by <tt>ActiveRecord::Base</tt> will override the method inherited through <tt>ActiveRecord::Base</tt> and will break things. + # For instance, +attributes+ and +connection+ would be bad choices for association names, because those names already exist in the list of <tt>ActiveRecord::Base</tt> instance methods. # # == Auto-generated methods # See also Instance Public methods below for more details. diff --git a/activerecord/lib/active_record/associations/join_dependency.rb b/activerecord/lib/active_record/associations/join_dependency.rb index b94feeff12..491152bbcb 100644 --- a/activerecord/lib/active_record/associations/join_dependency.rb +++ b/activerecord/lib/active_record/associations/join_dependency.rb @@ -92,8 +92,9 @@ module ActiveRecord # associations # => [:appointments] # joins # => [] # - def initialize(base, associations, joins) + def initialize(base, associations, joins, eager_loading: true) @alias_tracker = AliasTracker.create_with_joins(base.connection, base.table_name, joins, base.type_caster) + @eager_loading = eager_loading tree = self.class.make_tree associations @join_root = JoinBase.new base, build(tree, base) @join_root.children.each { |child| construct_tables! @join_root, child } @@ -238,11 +239,12 @@ module ActiveRecord reflection.check_eager_loadable! if reflection.polymorphic? + next unless @eager_loading raise EagerLoadPolymorphicError.new(reflection) end JoinAssociation.new reflection, build(right, reflection.klass) - end + end.compact end def construct(ar_parent, parent, row, rs, seen, model_cache, aliases) diff --git a/activerecord/lib/active_record/attribute.rb b/activerecord/lib/active_record/attribute.rb index 24231dc9e1..9530f134d0 100644 --- a/activerecord/lib/active_record/attribute.rb +++ b/activerecord/lib/active_record/attribute.rb @@ -77,7 +77,11 @@ module ActiveRecord end def with_type(type) - self.class.new(name, value_before_type_cast, type, original_attribute) + if changed_in_place? + with_value_from_user(value).with_type(type) + else + self.class.new(name, value_before_type_cast, type, original_attribute) + end end def type_cast(*) @@ -108,6 +112,22 @@ module ActiveRecord [self.class, name, value_before_type_cast, type].hash end + def init_with(coder) + @name = coder["name"] + @value_before_type_cast = coder["value_before_type_cast"] + @type = coder["type"] + @original_attribute = coder["original_attribute"] + @value = coder["value"] if coder.map.key?("value") + end + + def encode_with(coder) + coder["name"] = name + coder["value_before_type_cast"] = value_before_type_cast if value_before_type_cast + coder["type"] = type if type + coder["original_attribute"] = original_attribute if original_attribute + coder["value"] = value if defined?(@value) + end + protected attr_reader :original_attribute @@ -185,6 +205,8 @@ module ActiveRecord end class Uninitialized < Attribute # :nodoc: + UNINITIALIZED_ORIGINAL_VALUE = Object.new + def initialize(name, type) super(name, nil, type) end @@ -195,12 +217,20 @@ module ActiveRecord end end + def original_value + UNINITIALIZED_ORIGINAL_VALUE + end + def value_for_database end def initialized? false end + + def with_type(type) + self.class.new(name, type) + end end private_constant :FromDatabase, :FromUser, :Null, :Uninitialized, :WithCastValue end diff --git a/activerecord/lib/active_record/attribute_methods.rb b/activerecord/lib/active_record/attribute_methods.rb index 7e19dceaed..1fb5eb28cd 100644 --- a/activerecord/lib/active_record/attribute_methods.rb +++ b/activerecord/lib/active_record/attribute_methods.rb @@ -334,8 +334,6 @@ module ActiveRecord # # Note: +:id+ is always present. # - # Alias for the #read_attribute method. - # # class Person < ActiveRecord::Base # belongs_to :organization # end diff --git a/activerecord/lib/active_record/attribute_set.rb b/activerecord/lib/active_record/attribute_set.rb index be581ac2a9..720d5f8b7c 100644 --- a/activerecord/lib/active_record/attribute_set.rb +++ b/activerecord/lib/active_record/attribute_set.rb @@ -1,7 +1,10 @@ require 'active_record/attribute_set/builder' +require 'active_record/attribute_set/yaml_encoder' module ActiveRecord class AttributeSet # :nodoc: + delegate :each_value, to: :attributes + def initialize(attributes) @attributes = attributes end diff --git a/activerecord/lib/active_record/attribute_set/builder.rb b/activerecord/lib/active_record/attribute_set/builder.rb index 3bd7c7997b..24a255efc1 100644 --- a/activerecord/lib/active_record/attribute_set/builder.rb +++ b/activerecord/lib/active_record/attribute_set/builder.rb @@ -22,7 +22,7 @@ module ActiveRecord end class LazyAttributeHash # :nodoc: - delegate :transform_values, :each_key, to: :materialize + delegate :transform_values, :each_key, :each_value, to: :materialize def initialize(types, values, additional_types) @types = types diff --git a/activerecord/lib/active_record/attribute_set/yaml_encoder.rb b/activerecord/lib/active_record/attribute_set/yaml_encoder.rb new file mode 100644 index 0000000000..f9d527a5a3 --- /dev/null +++ b/activerecord/lib/active_record/attribute_set/yaml_encoder.rb @@ -0,0 +1,39 @@ +module ActiveRecord + class AttributeSet + # Attempts to do more intelligent YAML dumping of an + # ActiveRecord::AttributeSet to reduce the size of the resulting string + class YAMLEncoder # :nodoc: + def initialize(default_types) + @default_types = default_types + end + + def encode(attribute_set, coder) + coder['concise_attributes'] = attribute_set.each_value.map do |attr| + if attr.type.equal?(default_types[attr.name]) + attr.with_type(nil) + else + attr + end + end + end + + def decode(coder) + if coder['attributes'] + coder['attributes'] + else + attributes_hash = Hash[coder['concise_attributes'].map do |attr| + if attr.type.nil? + attr = attr.with_type(default_types[attr.name]) + end + [attr.name, attr] + end] + AttributeSet.new(attributes_hash) + end + end + + protected + + attr_reader :default_types + 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 f437dafec2..c341773be1 100644 --- a/activerecord/lib/active_record/connection_adapters/abstract/connection_pool.rb +++ b/activerecord/lib/active_record/connection_adapters/abstract/connection_pool.rb @@ -837,7 +837,11 @@ module ActiveRecord end alias :connection_pools :connection_pool_list - def establish_connection(spec) + def establish_connection(config) + resolver = ConnectionSpecification::Resolver.new(Base.configurations) + spec = resolver.spec(config) + + remove_connection(spec.name) owner_to_pool[spec.name] = ConnectionAdapters::ConnectionPool.new(spec) end @@ -871,9 +875,9 @@ module ActiveRecord # for (not necessarily the current class). def retrieve_connection(spec_name) #:nodoc: pool = retrieve_connection_pool(spec_name) - raise ConnectionNotEstablished, "No connection pool with id #{spec_name} found." unless pool + raise ConnectionNotEstablished, "No connection pool with id '#{spec_name}' found." unless pool conn = pool.connection - raise ConnectionNotEstablished, "No connection for #{spec_name} in connection pool" unless conn + raise ConnectionNotEstablished, "No connection for '#{spec_name}' in connection pool" unless conn conn end @@ -907,7 +911,7 @@ module ActiveRecord # A connection was established in an ancestor process that must have # subsequently forked. We can't reuse the connection, but we can copy # the specification and establish a new connection with it. - establish_connection(ancestor_pool.spec).tap do |pool| + establish_connection(ancestor_pool.spec.to_hash).tap do |pool| pool.schema_cache = ancestor_pool.schema_cache if ancestor_pool.schema_cache end else diff --git a/activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb b/activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb index bbb0e9249d..8dbafc5a4b 100644 --- a/activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb +++ b/activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb @@ -51,11 +51,12 @@ module ActiveRecord options[:primary_key] != default_primary_key end - def defined_for?(options_or_to_table = {}) - if options_or_to_table.is_a?(Hash) - options_or_to_table.all? {|key, value| options[key].to_s == value.to_s } + def defined_for?(to_table_ord = nil, to_table: nil, **options) + if to_table_ord + self.to_table == to_table_ord.to_s else - to_table == options_or_to_table.to_s + (to_table.nil? || to_table.to_s == self.to_table) && + options.all? { |k, v| self.options[k].to_s == v.to_s } 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 99a3e99bdc..eec0bc8518 100644 --- a/activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb +++ b/activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb @@ -790,7 +790,7 @@ module ActiveRecord # [<tt>:type</tt>] # The reference column type. Defaults to +:integer+. # [<tt>:index</tt>] - # Add an appropriate index. Defaults to false. + # Add an appropriate index. Defaults to false. # See #add_index for usage of this option. # [<tt>:foreign_key</tt>] # Add an appropriate foreign key constraint. Defaults to false. @@ -847,14 +847,19 @@ module ActiveRecord # # remove_reference(:products, :user, index: true, foreign_key: true) # - def remove_reference(table_name, ref_name, options = {}) - if options[:foreign_key] + def remove_reference(table_name, ref_name, foreign_key: false, polymorphic: false, **options) + if foreign_key reference_name = Base.pluralize_table_names ? ref_name.to_s.pluralize : ref_name - remove_foreign_key(table_name, reference_name) + if foreign_key.is_a?(Hash) + foreign_key_options = foreign_key + else + foreign_key_options = { to_table: reference_name } + end + remove_foreign_key(table_name, **foreign_key_options) end remove_column(table_name, "#{ref_name}_id") - remove_column(table_name, "#{ref_name}_type") if options[:polymorphic] + remove_column(table_name, "#{ref_name}_type") if polymorphic end alias :remove_belongs_to :remove_reference @@ -1123,7 +1128,6 @@ module ActiveRecord index_type ||= options[:unique] ? "UNIQUE" : "" index_name = options[:name].to_s if options.key?(:name) index_name ||= index_name(table_name, index_name_options(column_names)) - max_index_length = options.fetch(:internal, false) ? index_name_length : allowed_index_name_length if options.key?(:algorithm) algorithm = index_algorithms.fetch(options[:algorithm]) { @@ -1137,9 +1141,8 @@ module ActiveRecord index_options = options[:where] ? " WHERE #{options[:where]}" : "" end - if index_name.length > max_index_length - raise ArgumentError, "Index name '#{index_name}' on table '#{table_name}' is too long; the limit is #{max_index_length} characters" - end + validate_index_length!(table_name, index_name, options.fetch(:internal, false)) + if data_source_exists?(table_name) && index_name_exists?(table_name, index_name, false) raise ArgumentError, "Index name '#{index_name}' on table '#{table_name}' already exists" end @@ -1271,8 +1274,10 @@ module ActiveRecord end end - def validate_index_length!(table_name, new_name) # :nodoc: - if new_name.length > allowed_index_name_length + def validate_index_length!(table_name, new_name, internal = false) # :nodoc: + max_index_length = internal ? index_name_length : allowed_index_name_length + + if new_name.length > max_index_length raise ArgumentError, "Index name '#{new_name}' on table '#{table_name}' is too long; the limit is #{allowed_index_name_length} characters" end end 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 44b4b547f3..718a6c5b91 100644 --- a/activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +++ b/activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb @@ -41,14 +41,14 @@ module ActiveRecord NATIVE_DATABASE_TYPES = { primary_key: "int auto_increment PRIMARY KEY", string: { name: "varchar", limit: 255 }, - text: { name: "text" }, + text: { name: "text", limit: 65535 }, integer: { name: "int", limit: 4 }, float: { name: "float" }, decimal: { name: "decimal" }, datetime: { name: "datetime" }, time: { name: "time" }, date: { name: "date" }, - binary: { name: "blob" }, + binary: { name: "blob", limit: 65535 }, boolean: { name: "tinyint", limit: 1 }, json: { name: "json" }, } diff --git a/activerecord/lib/active_record/connection_adapters/connection_specification.rb b/activerecord/lib/active_record/connection_adapters/connection_specification.rb index 901c98b22b..346916337e 100644 --- a/activerecord/lib/active_record/connection_adapters/connection_specification.rb +++ b/activerecord/lib/active_record/connection_adapters/connection_specification.rb @@ -13,6 +13,10 @@ module ActiveRecord @config = original.config.dup end + def to_hash + @config.merge(name: @name) + end + # Expands a connection string into a hash. class ConnectionUrlResolver # :nodoc: @@ -164,7 +168,7 @@ module ActiveRecord # spec.config # # => { "host" => "localhost", "database" => "foo", "adapter" => "sqlite3" } # - def spec(config, name = nil) + def spec(config) spec = resolve(config).symbolize_keys raise(AdapterNotSpecified, "database configuration does not specify adapter") unless spec.key?(:adapter) @@ -180,13 +184,11 @@ module ActiveRecord adapter_method = "#{spec[:adapter]}_connection" - name ||= - if config.is_a?(Symbol) - config.to_s - else - "primary" - end - ConnectionSpecification.new(name, spec, adapter_method) + unless ActiveRecord::Base.respond_to?(adapter_method) + raise AdapterNotFound, "database configuration specifies nonexistent #{spec.config[:adapter]} adapter" + end + + ConnectionSpecification.new(spec.delete(:name) || "primary", spec, adapter_method) end private @@ -231,7 +233,7 @@ module ActiveRecord # def resolve_symbol_connection(spec) if config = configurations[spec.to_s] - resolve_connection(config) + resolve_connection(config).merge("name" => spec.to_s) else raise(AdapterNotSpecified, "'#{spec}' database is not configured. Available: #{configurations.keys.inspect}") end diff --git a/activerecord/lib/active_record/connection_adapters/mysql/column.rb b/activerecord/lib/active_record/connection_adapters/mysql/column.rb index 9c45fdd44a..ea554b188c 100644 --- a/activerecord/lib/active_record/connection_adapters/mysql/column.rb +++ b/activerecord/lib/active_record/connection_adapters/mysql/column.rb @@ -6,7 +6,6 @@ module ActiveRecord def initialize(*) super - assert_valid_default extract_default end @@ -38,12 +37,6 @@ module ActiveRecord @default = null || strict ? nil : '' end end - - def assert_valid_default - if blob_or_text_column? && default.present? - raise ArgumentError, "#{type} columns cannot have a default value: #{default.inspect}" - end - end end end end diff --git a/activerecord/lib/active_record/connection_adapters/postgresql/schema_statements.rb b/activerecord/lib/active_record/connection_adapters/postgresql/schema_statements.rb index 6318b1c65a..f6860b9aba 100644 --- a/activerecord/lib/active_record/connection_adapters/postgresql/schema_statements.rb +++ b/activerecord/lib/active_record/connection_adapters/postgresql/schema_statements.rb @@ -641,7 +641,7 @@ module ActiveRecord when 1, 2; 'smallint' when nil, 3, 4; 'integer' when 5..8; 'bigint' - else raise(ActiveRecordError, "No integer type has byte size #{limit}. Use a numeric with precision 0 instead.") + else raise(ActiveRecordError, "No integer type has byte size #{limit}. Use a numeric with scale 0 instead.") end else super(type, limit, precision, scale) diff --git a/activerecord/lib/active_record/connection_handling.rb b/activerecord/lib/active_record/connection_handling.rb index f932deb18d..99fdef67d0 100644 --- a/activerecord/lib/active_record/connection_handling.rb +++ b/activerecord/lib/active_record/connection_handling.rb @@ -44,21 +44,18 @@ module ActiveRecord # # The exceptions AdapterNotSpecified, AdapterNotFound and +ArgumentError+ # may be returned on an error. - def establish_connection(spec = nil) + def establish_connection(config = nil) raise "Anonymous class is not allowed." unless name - spec ||= DEFAULT_ENV.call.to_sym - resolver = ConnectionAdapters::ConnectionSpecification::Resolver.new configurations - # TODO: uses name on establish_connection, for backwards compatibility - spec = resolver.spec(spec, self == Base ? "primary" : name) + config ||= DEFAULT_ENV.call.to_sym + spec_name = self == Base ? "primary" : name + self.connection_specification_name = spec_name - unless respond_to?(spec.adapter_method) - raise AdapterNotFound, "database configuration specifies nonexistent #{spec.config[:adapter]} adapter" - end + resolver = ConnectionAdapters::ConnectionSpecification::Resolver.new(Base.configurations) + spec = resolver.resolve(config).symbolize_keys + spec[:name] = spec_name - remove_connection(spec.name) - self.connection_specification_name = spec.name - connection_handler.establish_connection spec + connection_handler.establish_connection(spec) end class MergeAndResolveDefaultUrlConfig # :nodoc: @@ -134,7 +131,7 @@ module ActiveRecord def remove_connection(name = nil) name ||= @connection_specification_name if defined?(@connection_specification_name) - # if removing a connection that have a pool, we reset the + # if removing a connection that has a pool, we reset the # connection_specification_name so it will use the parent # pool. if connection_handler.retrieve_connection_pool(name) diff --git a/activerecord/lib/active_record/core.rb b/activerecord/lib/active_record/core.rb index f936e865e4..de337b24d6 100644 --- a/activerecord/lib/active_record/core.rb +++ b/activerecord/lib/active_record/core.rb @@ -338,7 +338,7 @@ module ActiveRecord # post.title # => 'hello world' def init_with(coder) coder = LegacyYamlAdapter.convert(self.class, coder) - @attributes = coder['attributes'] + @attributes = self.class.yaml_encoder.decode(coder) init_internals @@ -404,11 +404,9 @@ module ActiveRecord # Post.new.encode_with(coder) # coder # => {"attributes" => {"id" => nil, ... }} def encode_with(coder) - # FIXME: Remove this when we better serialize attributes - coder['raw_attributes'] = attributes_before_type_cast - coder['attributes'] = @attributes + self.class.yaml_encoder.encode(@attributes, coder) coder['new_record'] = new_record? - coder['active_record_yaml_version'] = 1 + coder['active_record_yaml_version'] = 2 end # Returns true if +comparison_object+ is the same exact object, or +comparison_object+ @@ -432,7 +430,7 @@ module ActiveRecord # [ Person.find(1), Person.find(2), Person.find(3) ] & [ Person.find(1), Person.find(4) ] # => [ Person.find(1) ] def hash if id - id.hash + [self.class, id].hash else super end diff --git a/activerecord/lib/active_record/enum.rb b/activerecord/lib/active_record/enum.rb index 7be332fb97..b884edf920 100644 --- a/activerecord/lib/active_record/enum.rb +++ b/activerecord/lib/active_record/enum.rb @@ -105,6 +105,8 @@ module ActiveRecord end class EnumType < Type::Value # :nodoc: + delegate :type, to: :subtype + def initialize(name, mapping, subtype) @name = name @mapping = mapping diff --git a/activerecord/lib/active_record/fixtures.rb b/activerecord/lib/active_record/fixtures.rb index ed1bbf5dcd..51bf12d0bf 100644 --- a/activerecord/lib/active_record/fixtures.rb +++ b/activerecord/lib/active_record/fixtures.rb @@ -66,7 +66,7 @@ module ActiveRecord # By default, +test_helper.rb+ will load all of your fixtures into your test # database, so this test will succeed. # - # The testing environment will automatically load the all fixtures into the database before each + # The testing environment will automatically load all the fixtures into the database before each # test. To ensure consistent data, the environment deletes the fixtures before running the load. # # In addition to being available in the database, the fixture's data may also be accessed by diff --git a/activerecord/lib/active_record/inheritance.rb b/activerecord/lib/active_record/inheritance.rb index 899683ee4f..b5fec57c8c 100644 --- a/activerecord/lib/active_record/inheritance.rb +++ b/activerecord/lib/active_record/inheritance.rb @@ -19,7 +19,7 @@ module ActiveRecord # Be aware that because the type column is an attribute on the record every new # subclass will instantly be marked as dirty and the type column will be included # in the list of changed attributes on the record. This is different from non - # STI classes: + # Single Table Inheritance(STI) classes: # # Company.new.changed? # => false # Firm.new.changed? # => true @@ -37,6 +37,7 @@ module ActiveRecord included do # Determines whether to store the full constant name including namespace when using STI. + # This is true, by default. class_attribute :store_full_sti_class, instance_writer: false self.store_full_sti_class = true end diff --git a/activerecord/lib/active_record/legacy_yaml_adapter.rb b/activerecord/lib/active_record/legacy_yaml_adapter.rb index 89dee58423..c7683f68c7 100644 --- a/activerecord/lib/active_record/legacy_yaml_adapter.rb +++ b/activerecord/lib/active_record/legacy_yaml_adapter.rb @@ -4,7 +4,7 @@ module ActiveRecord return coder unless coder.is_a?(Psych::Coder) case coder["active_record_yaml_version"] - when 1 then coder + when 1, 2 then coder else if coder["attributes"].is_a?(AttributeSet) Rails420.convert(klass, coder) diff --git a/activerecord/lib/active_record/model_schema.rb b/activerecord/lib/active_record/model_schema.rb index f691a8319d..7996c32bbc 100644 --- a/activerecord/lib/active_record/model_schema.rb +++ b/activerecord/lib/active_record/model_schema.rb @@ -267,6 +267,10 @@ module ActiveRecord @attribute_types ||= Hash.new(Type::Value.new) end + def yaml_encoder # :nodoc: + @yaml_encoder ||= AttributeSet::YAMLEncoder.new(attribute_types) + end + # Returns the type of the attribute with the given name, after applying # all modifiers. This method is the only valid source of information for # anything related to the types of a model's attributes. This method will @@ -375,6 +379,7 @@ module ActiveRecord @columns = nil @columns_hash = nil @attribute_names = nil + @yaml_encoder = nil direct_descendants.each do |descendant| descendant.send(:reload_schema_from_cache) end diff --git a/activerecord/lib/active_record/query_cache.rb b/activerecord/lib/active_record/query_cache.rb index ca12a603da..07d863d15e 100644 --- a/activerecord/lib/active_record/query_cache.rb +++ b/activerecord/lib/active_record/query_cache.rb @@ -5,7 +5,7 @@ module ActiveRecord # Enable the query cache within the block if Active Record is configured. # If it's not, it will execute the given block. def cache(&block) - if ActiveRecord::Base.connected? + if connected? connection.cache(&block) else yield @@ -15,7 +15,7 @@ module ActiveRecord # Disable the query cache within the block if Active Record is configured. # If it's not, it will execute the given block. def uncached(&block) - if ActiveRecord::Base.connected? + if connected? connection.uncached(&block) else yield diff --git a/activerecord/lib/active_record/relation.rb b/activerecord/lib/active_record/relation.rb index d042fe5f8b..7a1552856b 100644 --- a/activerecord/lib/active_record/relation.rb +++ b/activerecord/lib/active_record/relation.rb @@ -279,12 +279,7 @@ module ActiveRecord def empty? return @records.empty? if loaded? - if limit_value == 0 - true - else - c = count(:all) - c.respond_to?(:zero?) ? c.zero? : c.empty? - end + limit_value == 0 || !exists? end # Returns true if there are no records. diff --git a/activerecord/lib/active_record/relation/finder_methods.rb b/activerecord/lib/active_record/relation/finder_methods.rb index e7e331f88d..d255cad91b 100644 --- a/activerecord/lib/active_record/relation/finder_methods.rb +++ b/activerecord/lib/active_record/relation/finder_methods.rb @@ -318,7 +318,7 @@ module ActiveRecord return false if !conditions - relation = apply_join_dependency(self, construct_join_dependency) + relation = apply_join_dependency(self, construct_join_dependency(eager_loading: false)) return false if ActiveRecord::NullRelation === relation relation = relation.except(:select, :order).select(ONE_AS_ONE).limit(1) @@ -333,6 +333,8 @@ module ActiveRecord end connection.select_value(relation, "#{name} Exists", relation.bound_attributes) ? true : false + rescue RangeError + false end # This method is called whenever no records are found with either a single @@ -392,21 +394,13 @@ module ActiveRecord end end - def construct_join_dependency(joins = []) + def construct_join_dependency(joins = [], eager_loading: true) including = eager_load_values + includes_values - ActiveRecord::Associations::JoinDependency.new(@klass, including, joins) + ActiveRecord::Associations::JoinDependency.new(@klass, including, joins, eager_loading: eager_loading) end def construct_relation_for_association_calculations - from = arel.froms.first - if Arel::Table === from - apply_join_dependency(self, construct_join_dependency(joins_values)) - else - # FIXME: as far as I can tell, `from` will always be an Arel::Table. - # There are no tests that test this branch, but presumably it's - # possible for `from` to be a list? - apply_join_dependency(self, construct_join_dependency(from)) - end + apply_join_dependency(self, construct_join_dependency(joins_values)) end def apply_join_dependency(relation, join_dependency) @@ -579,7 +573,7 @@ module ActiveRecord # e.g., reverse_order.offset(index-1).first end end - + private def find_nth_with_limit_and_offset(index, limit, offset:) # :nodoc: diff --git a/activerecord/lib/active_record/relation/predicate_builder/association_query_handler.rb b/activerecord/lib/active_record/relation/predicate_builder/association_query_handler.rb index d7fd878265..413cb9fd84 100644 --- a/activerecord/lib/active_record/relation/predicate_builder/association_query_handler.rb +++ b/activerecord/lib/active_record/relation/predicate_builder/association_query_handler.rb @@ -2,13 +2,14 @@ module ActiveRecord class PredicateBuilder class AssociationQueryHandler # :nodoc: def self.value_for(table, column, value) - klass = if table.associated_table(column).polymorphic_association? && ::Array === value && value.first.is_a?(Base) + associated_table = table.associated_table(column) + klass = if associated_table.polymorphic_association? && ::Array === value && value.first.is_a?(Base) PolymorphicArrayValue else AssociationQueryValue end - klass.new(table.associated_table(column), value) + klass.new(associated_table, value) end def initialize(predicate_builder) diff --git a/activerecord/lib/active_record/relation/query_methods.rb b/activerecord/lib/active_record/relation/query_methods.rb index 6477629560..8a87015e44 100644 --- a/activerecord/lib/active_record/relation/query_methods.rb +++ b/activerecord/lib/active_record/relation/query_methods.rb @@ -658,7 +658,7 @@ module ActiveRecord # present). Neither relation may have a #limit, #offset, or #distinct set. # # Post.where("id = 1").or(Post.where("author_id = 3")) - # # SELECT `posts`.* FROM `posts` WHERE (('id = 1' OR 'author_id = 3')) + # # SELECT `posts`.* FROM `posts` WHERE ((id = 1) OR (author_id = 3)) # def or(other) unless other.is_a? Relation @@ -1008,12 +1008,6 @@ module ActiveRecord self.send(unscope_code, result) end - def association_for_table(table_name) - table_name = table_name.to_s - @klass._reflect_on_association(table_name) || - @klass._reflect_on_association(table_name.singularize) - end - def build_from opts = from_clause.value name = from_clause.name diff --git a/activerecord/lib/active_record/table_metadata.rb b/activerecord/lib/active_record/table_metadata.rb index 0faad48ce3..a1326aa359 100644 --- a/activerecord/lib/active_record/table_metadata.rb +++ b/activerecord/lib/active_record/table_metadata.rb @@ -44,7 +44,8 @@ module ActiveRecord def associated_table(table_name) return self if table_name == arel_table.name - association = klass._reflect_on_association(table_name) + association = klass._reflect_on_association(table_name) || klass._reflect_on_association(table_name.singularize) + if association && !association.polymorphic? association_klass = association.klass arel_table = association_klass.arel_table.alias(table_name) diff --git a/activerecord/lib/active_record/tasks/database_tasks.rb b/activerecord/lib/active_record/tasks/database_tasks.rb index 0df46d54df..e3e665e149 100644 --- a/activerecord/lib/active_record/tasks/database_tasks.rb +++ b/activerecord/lib/active_record/tasks/database_tasks.rb @@ -120,7 +120,7 @@ module ActiveRecord old_pool = ActiveRecord::Base.connection_handler.retrieve_connection_pool(ActiveRecord::Base.connection_specification_name) each_local_configuration { |configuration| create configuration } if old_pool - ActiveRecord::Base.connection_handler.establish_connection(old_pool.spec) + ActiveRecord::Base.connection_handler.establish_connection(old_pool.spec.to_hash) end end diff --git a/activerecord/lib/active_record/tasks/mysql_database_tasks.rb b/activerecord/lib/active_record/tasks/mysql_database_tasks.rb index af0c935342..b1a0ad0115 100644 --- a/activerecord/lib/active_record/tasks/mysql_database_tasks.rb +++ b/activerecord/lib/active_record/tasks/mysql_database_tasks.rb @@ -58,6 +58,7 @@ module ActiveRecord args.concat(["--result-file", "#{filename}"]) args.concat(["--no-data"]) args.concat(["--routines"]) + args.concat(["--skip-comments"]) args.concat(["#{configuration['database']}"]) run_cmd('mysqldump', args, 'dumping') diff --git a/activerecord/lib/active_record/tasks/postgresql_database_tasks.rb b/activerecord/lib/active_record/tasks/postgresql_database_tasks.rb index 8b4874044c..b19ab57ee4 100644 --- a/activerecord/lib/active_record/tasks/postgresql_database_tasks.rb +++ b/activerecord/lib/active_record/tasks/postgresql_database_tasks.rb @@ -2,6 +2,7 @@ module ActiveRecord module Tasks # :nodoc: class PostgreSQLDatabaseTasks # :nodoc: DEFAULT_ENCODING = ENV['CHARSET'] || 'utf8' + ON_ERROR_STOP_1 = 'ON_ERROR_STOP=1'.freeze delegate :connection, :establish_connection, :clear_active_connections!, to: ActiveRecord::Base @@ -67,7 +68,7 @@ module ActiveRecord def structure_load(filename) set_psql_env - args = [ '-q', '-f', filename, configuration['database'] ] + args = [ '-v', ON_ERROR_STOP_1, '-q', '-f', filename, configuration['database'] ] run_cmd('psql', args, 'loading' ) end diff --git a/activerecord/lib/active_record/transactions.rb b/activerecord/lib/active_record/transactions.rb index 77c2845d88..0ee1ebcfbe 100644 --- a/activerecord/lib/active_record/transactions.rb +++ b/activerecord/lib/active_record/transactions.rb @@ -189,8 +189,8 @@ module ActiveRecord # # === Caveats # - # If you're on MySQL, then do not use DDL operations in nested transactions - # blocks that are emulated with savepoints. That is, do not execute statements + # If you're on MySQL, then do not use Data Definition Language(DDL) operations in nested + # transactions blocks that are emulated with savepoints. That is, do not execute statements # like 'CREATE TABLE' inside such blocks. This is because MySQL automatically # releases all savepoints upon executing a DDL operation. When +transaction+ # is finished and tries to release the savepoint it created earlier, a @@ -480,11 +480,11 @@ module ActiveRecord # Updates the attributes on this particular Active Record object so that # if it's associated with a transaction, then the state of the Active Record - # object will be updated to reflect the current state of the transaction + # object will be updated to reflect the current state of the transaction. # # The +@transaction_state+ variable stores the states of the associated # transaction. This relies on the fact that a transaction can only be in - # one rollback or commit (otherwise a list of states would be required) + # one rollback or commit (otherwise a list of states would be required). # Each Active Record object inside of a transaction carries that transaction's # TransactionState. # diff --git a/activerecord/lib/active_record/validations/uniqueness.rb b/activerecord/lib/active_record/validations/uniqueness.rb index 1f59276137..ec9f498c40 100644 --- a/activerecord/lib/active_record/validations/uniqueness.rb +++ b/activerecord/lib/active_record/validations/uniqueness.rb @@ -65,8 +65,6 @@ module ActiveRecord column = klass.columns_hash[attribute_name] cast_type = klass.type_for_attribute(attribute_name) - value = cast_type.serialize(value) - value = klass.connection.type_cast(value) comparison = if !options[:case_sensitive] && !value.nil? # will use SQL LOWER function before comparison, unless it detects a case insensitive collation @@ -77,11 +75,9 @@ module ActiveRecord if value.nil? klass.unscoped.where(comparison) else - bind = Relation::QueryAttribute.new(attribute_name, value, Type::Value.new) + bind = Relation::QueryAttribute.new(attribute_name, value, cast_type) klass.unscoped.where(comparison, bind) end - rescue RangeError - klass.none end def scope_relation(record, table, relation) diff --git a/activerecord/lib/rails/generators/active_record/model/model_generator.rb b/activerecord/lib/rails/generators/active_record/model/model_generator.rb index f191eff5bf..0d72913258 100644 --- a/activerecord/lib/rails/generators/active_record/model/model_generator.rb +++ b/activerecord/lib/rails/generators/active_record/model/model_generator.rb @@ -21,14 +21,14 @@ module ActiveRecord end def create_model_file - template 'model.rb', File.join('app/models', class_path, "#{file_name}.rb") generate_application_record + template 'model.rb', File.join('app/models', class_path, "#{file_name}.rb") end def create_module_file return if regular_class_path.empty? - template 'module.rb', File.join('app/models', "#{class_path.join('/')}.rb") if behavior == :invoke generate_application_record + template 'module.rb', File.join('app/models', "#{class_path.join('/')}.rb") if behavior == :invoke end hook_for :test_framework @@ -48,7 +48,7 @@ module ActiveRecord # Used by the migration template to determine the parent name of the model def parent_class_name - options[:parent] || determine_default_parent_class + options[:parent] || 'ApplicationRecord' end def application_record_exist? @@ -64,14 +64,6 @@ module ActiveRecord 'app/models/application_record.rb' end end - - def determine_default_parent_class - if application_record_exist? - "ApplicationRecord" - else - "ActiveRecord::Base" - end - end end end end diff --git a/activerecord/test/cases/adapters/mysql2/charset_collation_test.rb b/activerecord/test/cases/adapters/mysql2/charset_collation_test.rb index 668c07dacb..c8028b6b36 100644 --- a/activerecord/test/cases/adapters/mysql2/charset_collation_test.rb +++ b/activerecord/test/cases/adapters/mysql2/charset_collation_test.rb @@ -49,6 +49,6 @@ class Mysql2CharsetCollationTest < ActiveRecord::Mysql2TestCase test "schema dump includes collation" do output = dump_table_schema("charset_collations") assert_match %r{t.string\s+"string_ascii_bin",\s+collation: "ascii_bin"$}, output - assert_match %r{t.text\s+"text_ucs2_unicode_ci",\s+limit: 65535,\s+collation: "ucs2_unicode_ci"$}, output + assert_match %r{t.text\s+"text_ucs2_unicode_ci",\s+collation: "ucs2_unicode_ci"$}, output end end diff --git a/activerecord/test/cases/adapters/sqlite3/quoting_test.rb b/activerecord/test/cases/adapters/sqlite3/quoting_test.rb index f3ec2b98d3..fe2425b845 100644 --- a/activerecord/test/cases/adapters/sqlite3/quoting_test.rb +++ b/activerecord/test/cases/adapters/sqlite3/quoting_test.rb @@ -3,98 +3,92 @@ require 'bigdecimal' require 'yaml' require 'securerandom' -module ActiveRecord - module ConnectionAdapters - class SQLite3Adapter - class QuotingTest < ActiveRecord::SQLite3TestCase - def setup - @conn = ActiveRecord::Base.connection - end - - def test_type_cast_binary_encoding_without_logger - @conn.extend(Module.new { def logger; end }) - binary = SecureRandom.hex - expected = binary.dup.encode!(Encoding::UTF_8) - assert_equal expected, @conn.type_cast(binary) - end - - def test_type_cast_symbol - assert_equal 'foo', @conn.type_cast(:foo) - end - - def test_type_cast_date - date = Date.today - expected = @conn.quoted_date(date) - assert_equal expected, @conn.type_cast(date) - end - - def test_type_cast_time - time = Time.now - expected = @conn.quoted_date(time) - assert_equal expected, @conn.type_cast(time) - end - - def test_type_cast_numeric - assert_equal 10, @conn.type_cast(10) - assert_equal 2.2, @conn.type_cast(2.2) - end - - def test_type_cast_nil - assert_equal nil, @conn.type_cast(nil) - end - - def test_type_cast_true - assert_equal 't', @conn.type_cast(true) - end - - def test_type_cast_false - assert_equal 'f', @conn.type_cast(false) - end - - def test_type_cast_bigdecimal - bd = BigDecimal.new '10.0' - assert_equal bd.to_f, @conn.type_cast(bd) - end - - def test_type_cast_unknown_should_raise_error - obj = Class.new.new - assert_raise(TypeError) { @conn.type_cast(obj) } - end - - def test_type_cast_object_which_responds_to_quoted_id - quoted_id_obj = Class.new { - def quoted_id - "'zomg'" - end - - def id - 10 - end - }.new - assert_equal 10, @conn.type_cast(quoted_id_obj) - - quoted_id_obj = Class.new { - def quoted_id - "'zomg'" - end - }.new - assert_raise(TypeError) { @conn.type_cast(quoted_id_obj) } - end - - def test_quoting_binary_strings - value = "hello".encode('ascii-8bit') - type = Type::String.new - - assert_equal "'hello'", @conn.quote(type.serialize(value)) - end - - def test_quoted_time_returns_date_qualified_time - value = ::Time.utc(2000, 1, 1, 12, 30, 0, 999999) - type = Type::Time.new - - assert_equal "'2000-01-01 12:30:00.999999'", @conn.quote(type.serialize(value)) - end +class SQLite3QuotingTest < ActiveRecord::SQLite3TestCase + def setup + @conn = ActiveRecord::Base.connection + end + + def test_type_cast_binary_encoding_without_logger + @conn.extend(Module.new { def logger; end }) + binary = SecureRandom.hex + expected = binary.dup.encode!(Encoding::UTF_8) + assert_equal expected, @conn.type_cast(binary) + end + + def test_type_cast_symbol + assert_equal 'foo', @conn.type_cast(:foo) + end + + def test_type_cast_date + date = Date.today + expected = @conn.quoted_date(date) + assert_equal expected, @conn.type_cast(date) + end + + def test_type_cast_time + time = Time.now + expected = @conn.quoted_date(time) + assert_equal expected, @conn.type_cast(time) + end + + def test_type_cast_numeric + assert_equal 10, @conn.type_cast(10) + assert_equal 2.2, @conn.type_cast(2.2) + end + + def test_type_cast_nil + assert_equal nil, @conn.type_cast(nil) + end + + def test_type_cast_true + assert_equal 't', @conn.type_cast(true) + end + + def test_type_cast_false + assert_equal 'f', @conn.type_cast(false) + end + + def test_type_cast_bigdecimal + bd = BigDecimal.new '10.0' + assert_equal bd.to_f, @conn.type_cast(bd) + end + + def test_type_cast_unknown_should_raise_error + obj = Class.new.new + assert_raise(TypeError) { @conn.type_cast(obj) } + end + + def test_type_cast_object_which_responds_to_quoted_id + quoted_id_obj = Class.new { + def quoted_id + "'zomg'" + end + + def id + 10 end - end + }.new + assert_equal 10, @conn.type_cast(quoted_id_obj) + + quoted_id_obj = Class.new { + def quoted_id + "'zomg'" + end + }.new + assert_raise(TypeError) { @conn.type_cast(quoted_id_obj) } + end + + def test_quoting_binary_strings + value = "hello".encode('ascii-8bit') + type = ActiveRecord::Type::String.new + + assert_equal "'hello'", @conn.quote(type.serialize(value)) + end + + def test_quoted_time_returns_date_qualified_time + value = ::Time.utc(2000, 1, 1, 12, 30, 0, 999999) + type = ActiveRecord::Type::Time.new + + assert_equal "'2000-01-01 12:30:00.999999'", @conn.quote(type.serialize(value)) end end diff --git a/activerecord/test/cases/adapters/sqlite3/statement_pool_test.rb b/activerecord/test/cases/adapters/sqlite3/statement_pool_test.rb index 559b951109..24cc6875ab 100644 --- a/activerecord/test/cases/adapters/sqlite3/statement_pool_test.rb +++ b/activerecord/test/cases/adapters/sqlite3/statement_pool_test.rb @@ -1,24 +1,20 @@ require 'cases/helper' -module ActiveRecord::ConnectionAdapters - class SQLite3Adapter - class StatementPoolTest < ActiveRecord::SQLite3TestCase - if Process.respond_to?(:fork) - def test_cache_is_per_pid +class SQLite3StatementPoolTest < ActiveRecord::SQLite3TestCase + if Process.respond_to?(:fork) + def test_cache_is_per_pid - cache = StatementPool.new(10) - cache['foo'] = 'bar' - assert_equal 'bar', cache['foo'] + cache = ActiveRecord::ConnectionAdapters::SQLite3Adapter::StatementPool.new(10) + cache['foo'] = 'bar' + assert_equal 'bar', cache['foo'] - pid = fork { - lookup = cache['foo']; - exit!(!lookup) - } + pid = fork { + lookup = cache['foo']; + exit!(!lookup) + } - Process.waitpid pid - assert $?.success?, 'process should exit successfully' - end - end + Process.waitpid pid + assert $?.success?, 'process should exit successfully' end end end diff --git a/activerecord/test/cases/aggregations_test.rb b/activerecord/test/cases/aggregations_test.rb index 5536702f58..8a728902a8 100644 --- a/activerecord/test/cases/aggregations_test.rb +++ b/activerecord/test/cases/aggregations_test.rb @@ -138,6 +138,11 @@ class AggregationsTest < ActiveRecord::TestCase assert_equal 'Barnoit GUMBLEAU', customers(:barney).fullname.to_s assert_kind_of Fullname, customers(:barney).fullname end + + def test_assigning_hash_to_custom_converter + customers(:barney).fullname = { first: "Barney", last: "Stinson" } + assert_equal "Barney STINSON", customers(:barney).name + end end class OverridingAggregationsTest < ActiveRecord::TestCase diff --git a/activerecord/test/cases/associations/eager_test.rb b/activerecord/test/cases/associations/eager_test.rb index 7f2a2229ee..80d9a6083b 100644 --- a/activerecord/test/cases/associations/eager_test.rb +++ b/activerecord/test/cases/associations/eager_test.rb @@ -90,6 +90,10 @@ class EagerAssociationTest < ActiveRecord::TestCase assert_no_queries { authors.map(&:post) } end + def test_calculate_with_string_in_from_and_eager_loading + assert_equal 10, Post.from("authors, posts").eager_load(:comments).where("posts.author_id = authors.id").count + end + def test_with_two_tables_in_from_without_getting_double_quoted posts = Post.select("posts.*").from("authors, posts").eager_load(:comments).where("posts.author_id = authors.id").order("posts.id").to_a assert_equal 2, posts.first.comments.size @@ -1341,6 +1345,7 @@ class EagerAssociationTest < ActiveRecord::TestCase assert_nothing_raised do authors(:david).essays.includes(:writer).any? + authors(:david).essays.includes(:writer).exists? end end diff --git a/activerecord/test/cases/associations/has_one_associations_test.rb b/activerecord/test/cases/associations/has_one_associations_test.rb index c9d9e29f09..1574f373c2 100644 --- a/activerecord/test/cases/associations/has_one_associations_test.rb +++ b/activerecord/test/cases/associations/has_one_associations_test.rb @@ -659,4 +659,22 @@ class HasOneAssociationsTest < ActiveRecord::TestCase assert_deprecated { firm.account(true) } end + + class SpecialBook < ActiveRecord::Base + self.table_name = 'books' + belongs_to :author, class_name: 'SpecialAuthor' + end + + class SpecialAuthor < ActiveRecord::Base + self.table_name = 'authors' + has_one :book, class_name: 'SpecialBook', foreign_key: 'author_id' + end + + def test_assocation_enum_works_properly + author = SpecialAuthor.create!(name: 'Test') + book = SpecialBook.create!(status: 'published') + author.book = book + + refute_equal 0, SpecialAuthor.joins(:book).where(books: { status: 'published' } ).count + end end diff --git a/activerecord/test/cases/associations/left_outer_join_association_test.rb b/activerecord/test/cases/associations/left_outer_join_association_test.rb index 4af791b758..eee135cfb8 100644 --- a/activerecord/test/cases/associations/left_outer_join_association_test.rb +++ b/activerecord/test/cases/associations/left_outer_join_association_test.rb @@ -50,7 +50,7 @@ class LeftOuterJoinAssociationTest < ActiveRecord::TestCase def test_join_conditions_added_to_join_clause queries = capture_sql { Author.left_outer_joins(:essays).to_a } - assert queries.any? { |sql| /writer_type.*?=.*?(Author|\?|\$1)/i =~ sql } + assert queries.any? { |sql| /writer_type.*?=.*?(Author|\?|\$1|\:a1)/i =~ sql } assert queries.none? { |sql| /WHERE/i =~ sql } end diff --git a/activerecord/test/cases/attribute_test.rb b/activerecord/test/cases/attribute_test.rb index a24a4fc6a4..b1b8639696 100644 --- a/activerecord/test/cases/attribute_test.rb +++ b/activerecord/test/cases/attribute_test.rb @@ -242,5 +242,12 @@ module ActiveRecord attribute.with_value_from_user(1) end end + + test "with_type preserves mutations" do + attribute = Attribute.from_database(:foo, "", Type::Value.new) + attribute.value << "1" + + assert_equal 1, attribute.with_type(Type::Integer.new).value + end end end diff --git a/activerecord/test/cases/base_test.rb b/activerecord/test/cases/base_test.rb index 3191393a41..7b1ce40c0d 100644 --- a/activerecord/test/cases/base_test.rb +++ b/activerecord/test/cases/base_test.rb @@ -14,7 +14,6 @@ require 'models/auto_id' require 'models/boolean' require 'models/column_name' require 'models/subscriber' -require 'models/keyboard' require 'models/comment' require 'models/minimalistic' require 'models/warehouse_thing' @@ -25,7 +24,6 @@ require 'models/joke' require 'models/bird' require 'models/car' require 'models/bulb' -require 'rexml/document' require 'concurrent/atomic/count_down_latch' class FirstAbstractClass < ActiveRecord::Base @@ -1034,12 +1032,6 @@ class BasicsTest < ActiveRecord::TestCase assert_equal t1.title, t2.title end - def test_reload_with_exclusive_scope - dev = DeveloperCalledDavid.first - dev.update!(name: "NotDavid" ) - assert_equal dev, dev.reload - end - def test_switching_between_table_name k = Class.new(Joke) @@ -1504,6 +1496,10 @@ class BasicsTest < ActiveRecord::TestCase assert_not_equal Post.new.hash, Post.new.hash end + test "records of different classes have different hashes" do + assert_not_equal Post.new(id: 1).hash, Developer.new(id: 1).hash + end + test "resetting column information doesn't remove attribute methods" do topic = topics(:first) diff --git a/activerecord/test/cases/batches_test.rb b/activerecord/test/cases/batches_test.rb index 91ff5146fd..db71840658 100644 --- a/activerecord/test/cases/batches_test.rb +++ b/activerecord/test/cases/batches_test.rb @@ -170,8 +170,8 @@ class EachTest < ActiveRecord::TestCase end end - def test_find_in_batches_should_not_error_if_config_overriden - # Set the config option which will be overriden + def test_find_in_batches_should_not_error_if_config_overridden + # Set the config option which will be overridden prev = ActiveRecord::Base.error_on_ignored_order_or_limit ActiveRecord::Base.error_on_ignored_order_or_limit = true assert_nothing_raised do diff --git a/activerecord/test/cases/column_definition_test.rb b/activerecord/test/cases/column_definition_test.rb index 81162b7e98..78c0853992 100644 --- a/activerecord/test/cases/column_definition_test.rb +++ b/activerecord/test/cases/column_definition_test.rb @@ -60,15 +60,8 @@ module ActiveRecord end def test_should_not_set_default_for_blob_and_text_data_types - assert_raise ArgumentError do - MySQL::Column.new("title", "a", SqlTypeMetadata.new(sql_type: "blob")) - end - text_type = MySQL::TypeMetadata.new( SqlTypeMetadata.new(type: :text)) - assert_raise ArgumentError do - MySQL::Column.new("title", "Hello", text_type) - end text_column = MySQL::Column.new("title", nil, text_type) assert_equal nil, text_column.default diff --git a/activerecord/test/cases/connection_adapters/connection_handler_test.rb b/activerecord/test/cases/connection_adapters/connection_handler_test.rb index 50f942f5aa..a019cc6490 100644 --- a/activerecord/test/cases/connection_adapters/connection_handler_test.rb +++ b/activerecord/test/cases/connection_adapters/connection_handler_test.rb @@ -5,16 +5,15 @@ module ActiveRecord class ConnectionHandlerTest < ActiveRecord::TestCase def setup @handler = ConnectionHandler.new - resolver = ConnectionAdapters::ConnectionSpecification::Resolver.new Base.configurations @spec_name = "primary" - @pool = @handler.establish_connection(resolver.spec(:arunit, @spec_name)) + @pool = @handler.establish_connection(ActiveRecord::Base.configurations['arunit']) end def test_establish_connection_uses_spec_name config = {"readonly" => {"adapter" => 'sqlite3'}} resolver = ConnectionAdapters::ConnectionSpecification::Resolver.new(config) spec = resolver.spec(:readonly) - @handler.establish_connection(spec) + @handler.establish_connection(spec.to_hash) assert_not_nil @handler.retrieve_connection_pool('readonly') ensure diff --git a/activerecord/test/cases/connection_adapters/merge_and_resolve_default_url_config_test.rb b/activerecord/test/cases/connection_adapters/merge_and_resolve_default_url_config_test.rb index 9ee92a3cd2..f25b85e8a7 100644 --- a/activerecord/test/cases/connection_adapters/merge_and_resolve_default_url_config_test.rb +++ b/activerecord/test/cases/connection_adapters/merge_and_resolve_default_url_config_test.rb @@ -27,7 +27,7 @@ module ActiveRecord ENV['DATABASE_URL'] = "postgres://localhost/foo" config = { "not_production" => { "adapter" => "not_postgres", "database" => "not_foo" } } actual = resolve_spec(:default_env, config) - expected = { "adapter"=>"postgresql", "database"=>"foo", "host"=>"localhost" } + expected = { "adapter"=>"postgresql", "database"=>"foo", "host"=>"localhost", "name"=>"default_env" } assert_equal expected, actual end @@ -37,7 +37,7 @@ module ActiveRecord config = { "not_production" => { "adapter" => "not_postgres", "database" => "not_foo" } } actual = resolve_spec(:foo, config) - expected = { "adapter" => "postgresql", "database" => "foo", "host" => "localhost" } + expected = { "adapter" => "postgresql", "database" => "foo", "host" => "localhost","name"=>"foo" } assert_equal expected, actual end @@ -47,7 +47,7 @@ module ActiveRecord config = { "not_production" => { "adapter" => "not_postgres", "database" => "not_foo" } } actual = resolve_spec(:foo, config) - expected = { "adapter" => "postgresql", "database" => "foo", "host" => "localhost" } + expected = { "adapter" => "postgresql", "database" => "foo", "host" => "localhost","name"=>"foo" } assert_equal expected, actual end @@ -55,7 +55,7 @@ module ActiveRecord ENV['DATABASE_URL'] = "postgres://localhost/foo" config = { "production" => { "adapter" => "not_postgres", "database" => "not_foo", "host" => "localhost" } } actual = resolve_spec(:production, config) - expected = { "adapter"=>"not_postgres", "database"=>"not_foo", "host"=>"localhost" } + expected = { "adapter"=>"not_postgres", "database"=>"not_foo", "host"=>"localhost", "name"=>"production" } assert_equal expected, actual end @@ -93,7 +93,7 @@ module ActiveRecord ENV['DATABASE_URL'] = "ibm-db://localhost/foo" config = { "default_env" => { "adapter" => "not_postgres", "database" => "not_foo", "host" => "localhost" } } actual = resolve_spec(:default_env, config) - expected = { "adapter"=>"ibm_db", "database"=>"foo", "host"=>"localhost" } + expected = { "adapter"=>"ibm_db", "database"=>"foo", "host"=>"localhost", "name"=>"default_env" } assert_equal expected, actual end diff --git a/activerecord/test/cases/connection_specification/resolver_test.rb b/activerecord/test/cases/connection_specification/resolver_test.rb index 3bddaf32ec..b30a83d9ce 100644 --- a/activerecord/test/cases/connection_specification/resolver_test.rb +++ b/activerecord/test/cases/connection_specification/resolver_test.rb @@ -28,7 +28,8 @@ module ActiveRecord assert_equal({ "adapter" => "abstract", "host" => "foo", - "encoding" => "utf8" }, spec) + "encoding" => "utf8", + "name" => "production"}, spec) end def test_url_sub_key @@ -36,7 +37,8 @@ module ActiveRecord assert_equal({ "adapter" => "abstract", "host" => "foo", - "encoding" => "utf8" }, spec) + "encoding" => "utf8", + "name" => "production"}, spec) end def test_url_sub_key_merges_correctly @@ -46,7 +48,8 @@ module ActiveRecord "adapter" => "abstract", "host" => "foo", "encoding" => "utf8", - "pool" => "3" }, spec) + "pool" => "3", + "name" => "production"}, spec) end def test_url_host_no_db @@ -113,7 +116,8 @@ module ActiveRecord assert_equal({ "adapter" => "sqlite3", "database" => "foo", - "encoding" => "utf8" }, spec) + "encoding" => "utf8", + "name" => "production"}, spec) end def test_spec_name_on_key_lookup diff --git a/activerecord/test/cases/dirty_test.rb b/activerecord/test/cases/dirty_test.rb index a3f8d26100..f9794518c7 100644 --- a/activerecord/test/cases/dirty_test.rb +++ b/activerecord/test/cases/dirty_test.rb @@ -5,23 +5,6 @@ require 'models/parrot' require 'models/person' # For optimistic locking require 'models/aircraft' -class Pirate # Just reopening it, not defining it - attr_accessor :detected_changes_in_after_update # Boolean for if changes are detected - attr_accessor :changes_detected_in_after_update # Actual changes - - after_update :check_changes - -private - # after_save/update and the model itself - # can end up checking dirty status and acting on the results - def check_changes - if self.changed? - self.detected_changes_in_after_update = true - self.changes_detected_in_after_update = self.changes - end - end -end - class NumericData < ActiveRecord::Base self.table_name = 'numeric_data' end @@ -734,6 +717,17 @@ class DirtyTest < ActiveRecord::TestCase assert_equal "arr", pirate.catchphrase end + test "attributes assigned but not selected are dirty" do + person = Person.select(:id).first + refute person.changed? + + person.first_name = "Sean" + assert person.changed? + + person.first_name = nil + assert person.changed? + end + private def with_partial_writes(klass, on = true) old = klass.partial_writes? diff --git a/activerecord/test/cases/enum_test.rb b/activerecord/test/cases/enum_test.rb index babacd1ee9..e781b60464 100644 --- a/activerecord/test/cases/enum_test.rb +++ b/activerecord/test/cases/enum_test.rb @@ -421,4 +421,8 @@ class EnumTest < ActiveRecord::TestCase book = Book.new assert book.hard? end + + test "data type of Enum type" do + assert_equal :integer, Book.type_for_attribute('status').type + end end diff --git a/activerecord/test/cases/finder_test.rb b/activerecord/test/cases/finder_test.rb index 374a8ba199..6eaaa30cd0 100644 --- a/activerecord/test/cases/finder_test.rb +++ b/activerecord/test/cases/finder_test.rb @@ -173,11 +173,9 @@ class FinderTest < ActiveRecord::TestCase end end - def test_exists_fails_when_parameter_has_invalid_type - assert_raises(ActiveModel::RangeError) do - assert_equal false, Topic.exists?(("9"*53).to_i) # number that's bigger than int - end + def test_exists_returns_false_when_parameter_has_invalid_type assert_equal false, Topic.exists?("foo") + assert_equal false, Topic.exists?(("9"*53).to_i) # number that's bigger than int end def test_exists_does_not_select_columns_without_alias diff --git a/activerecord/test/cases/invertible_migration_test.rb b/activerecord/test/cases/invertible_migration_test.rb index e030f6c588..aba854820b 100644 --- a/activerecord/test/cases/invertible_migration_test.rb +++ b/activerecord/test/cases/invertible_migration_test.rb @@ -151,6 +151,14 @@ module ActiveRecord end end + class RevertCustomForeignKeyTable < SilentMigration + def change + change_table(:horses) do |t| + t.references :owner, foreign_key: { to_table: :developers } + end + end + end + setup do @verbose_was, ActiveRecord::Migration.verbose = ActiveRecord::Migration.verbose, false end @@ -353,6 +361,13 @@ module ActiveRecord ActiveRecord::Base.table_name_prefix = ActiveRecord::Base.table_name_suffix = '' end + def test_migrations_can_handle_foreign_keys_to_specific_tables + migration = RevertCustomForeignKeyTable.new + InvertibleMigration.migrate(:up) + migration.migrate(:up) + migration.migrate(:down) + end + # MySQL 5.7 and Oracle do not allow to create duplicate indexes on the same columns unless current_adapter?(:Mysql2Adapter, :OracleAdapter) def test_migrate_revert_add_index_with_name diff --git a/activerecord/test/cases/multiparameter_attributes_test.rb b/activerecord/test/cases/multiparameter_attributes_test.rb index ae18573126..d05cb22740 100644 --- a/activerecord/test/cases/multiparameter_attributes_test.rb +++ b/activerecord/test/cases/multiparameter_attributes_test.rb @@ -11,15 +11,13 @@ class MultiParameterAttributeTest < ActiveRecord::TestCase topic.attributes = attributes # note that extra #to_date call allows test to pass for Oracle, which # treats dates/times the same - assert_date_from_db Date.new(2004, 6, 24), topic.last_read.to_date + assert_equal Date.new(2004, 6, 24), topic.last_read.to_date end def test_multiparameter_attributes_on_date_with_empty_year attributes = { "last_read(1i)" => "", "last_read(2i)" => "6", "last_read(3i)" => "24" } topic = Topic.find(1) topic.attributes = attributes - # note that extra #to_date call allows test to pass for Oracle, which - # treats dates/times the same assert_nil topic.last_read end @@ -27,8 +25,6 @@ class MultiParameterAttributeTest < ActiveRecord::TestCase attributes = { "last_read(1i)" => "2004", "last_read(2i)" => "", "last_read(3i)" => "24" } topic = Topic.find(1) topic.attributes = attributes - # note that extra #to_date call allows test to pass for Oracle, which - # treats dates/times the same assert_nil topic.last_read end @@ -36,8 +32,6 @@ class MultiParameterAttributeTest < ActiveRecord::TestCase attributes = { "last_read(1i)" => "2004", "last_read(2i)" => "6", "last_read(3i)" => "" } topic = Topic.find(1) topic.attributes = attributes - # note that extra #to_date call allows test to pass for Oracle, which - # treats dates/times the same assert_nil topic.last_read end @@ -45,8 +39,6 @@ class MultiParameterAttributeTest < ActiveRecord::TestCase attributes = { "last_read(1i)" => "", "last_read(2i)" => "6", "last_read(3i)" => "" } topic = Topic.find(1) topic.attributes = attributes - # note that extra #to_date call allows test to pass for Oracle, which - # treats dates/times the same assert_nil topic.last_read end @@ -54,8 +46,6 @@ class MultiParameterAttributeTest < ActiveRecord::TestCase attributes = { "last_read(1i)" => "2004", "last_read(2i)" => "", "last_read(3i)" => "" } topic = Topic.find(1) topic.attributes = attributes - # note that extra #to_date call allows test to pass for Oracle, which - # treats dates/times the same assert_nil topic.last_read end @@ -63,8 +53,6 @@ class MultiParameterAttributeTest < ActiveRecord::TestCase attributes = { "last_read(1i)" => "", "last_read(2i)" => "", "last_read(3i)" => "24" } topic = Topic.find(1) topic.attributes = attributes - # note that extra #to_date call allows test to pass for Oracle, which - # treats dates/times the same assert_nil topic.last_read end diff --git a/activerecord/test/cases/query_cache_test.rb b/activerecord/test/cases/query_cache_test.rb index 406643d6fb..d5c01315c1 100644 --- a/activerecord/test/cases/query_cache_test.rb +++ b/activerecord/test/cases/query_cache_test.rb @@ -133,7 +133,6 @@ class QueryCacheTest < ActiveRecord::TestCase def test_cache_is_flat Task.cache do - Topic.columns # don't count this query assert_queries(1) { Topic.find(1); Topic.find(1); } end @@ -175,6 +174,22 @@ class QueryCacheTest < ActiveRecord::TestCase ActiveRecord::Base.configurations = conf end + def test_cache_is_not_available_when_using_a_not_connected_connection + spec_name = Task.connection_specification_name + conf = ActiveRecord::Base.configurations['arunit'].merge('name' => 'test2') + ActiveRecord::Base.connection_handler.establish_connection(conf) + Task.connection_specification_name = "test2" + refute Task.connected? + + Task.cache do + Task.connection # warmup postgresql connection setup queries + assert_queries(2) { Task.find(1); Task.find(1) } + end + ensure + ActiveRecord::Base.connection_handler.remove_connection(Task.connection_specification_name) + Task.connection_specification_name = spec_name + end + def test_query_cache_doesnt_leak_cached_results_of_rolled_back_queries ActiveRecord::Base.connection.enable_query_cache! post = Post.first diff --git a/activerecord/test/cases/schema_dumper_test.rb b/activerecord/test/cases/schema_dumper_test.rb index 9dc1f5e2c2..12f4196724 100644 --- a/activerecord/test/cases/schema_dumper_test.rb +++ b/activerecord/test/cases/schema_dumper_test.rb @@ -218,12 +218,17 @@ class SchemaDumperTest < ActiveRecord::TestCase assert_match %r{t\.boolean\s+"has_fun",.+default: false}, output end - if current_adapter?(:Mysql2Adapter) - def test_schema_dump_should_add_default_value_for_mysql_text_field - output = standard_dump - assert_match %r{t\.text\s+"body",\s+limit: 65535,\s+null: false$}, output - end + def test_schema_dump_does_not_include_limit_for_text_field + output = standard_dump + assert_match %r{t\.text\s+"params"$}, output + end + def test_schema_dump_does_not_include_limit_for_binary_field + output = standard_dump + assert_match %r{t\.binary\s+"data"$}, output + end + + if current_adapter?(:Mysql2Adapter) def test_schema_dump_includes_length_for_mysql_binary_fields output = standard_dump assert_match %r{t\.binary\s+"var_binary",\s+limit: 255$}, output @@ -233,11 +238,11 @@ class SchemaDumperTest < ActiveRecord::TestCase def test_schema_dump_includes_length_for_mysql_blob_and_text_fields output = standard_dump assert_match %r{t\.blob\s+"tiny_blob",\s+limit: 255$}, output - assert_match %r{t\.binary\s+"normal_blob",\s+limit: 65535$}, output + assert_match %r{t\.binary\s+"normal_blob"$}, output assert_match %r{t\.binary\s+"medium_blob",\s+limit: 16777215$}, output assert_match %r{t\.binary\s+"long_blob",\s+limit: 4294967295$}, output assert_match %r{t\.text\s+"tiny_text",\s+limit: 255$}, output - assert_match %r{t\.text\s+"normal_text",\s+limit: 65535$}, output + assert_match %r{t\.text\s+"normal_text"$}, output assert_match %r{t\.text\s+"medium_text",\s+limit: 16777215$}, output assert_match %r{t\.text\s+"long_text",\s+limit: 4294967295$}, output end diff --git a/activerecord/test/cases/tasks/mysql_rake_test.rb b/activerecord/test/cases/tasks/mysql_rake_test.rb index 8e480bbaee..70e406038f 100644 --- a/activerecord/test/cases/tasks/mysql_rake_test.rb +++ b/activerecord/test/cases/tasks/mysql_rake_test.rb @@ -289,7 +289,7 @@ module ActiveRecord def test_structure_dump filename = "awesome-file.sql" - Kernel.expects(:system).with("mysqldump", "--result-file", filename, "--no-data", "--routines", "test-db").returns(true) + Kernel.expects(:system).with("mysqldump", "--result-file", filename, "--no-data", "--routines", "--skip-comments", "test-db").returns(true) ActiveRecord::Tasks::DatabaseTasks.structure_dump(@configuration, filename) end @@ -297,7 +297,7 @@ module ActiveRecord def test_warn_when_external_structure_dump_command_execution_fails filename = "awesome-file.sql" Kernel.expects(:system) - .with("mysqldump", "--result-file", filename, "--no-data", "--routines", "test-db") + .with("mysqldump", "--result-file", filename, "--no-data", "--routines", "--skip-comments", "test-db") .returns(false) e = assert_raise(RuntimeError) { @@ -308,7 +308,7 @@ module ActiveRecord def test_structure_dump_with_port_number filename = "awesome-file.sql" - Kernel.expects(:system).with("mysqldump", "--port=10000", "--result-file", filename, "--no-data", "--routines", "test-db").returns(true) + Kernel.expects(:system).with("mysqldump", "--port=10000", "--result-file", filename, "--no-data", "--routines", "--skip-comments", "test-db").returns(true) ActiveRecord::Tasks::DatabaseTasks.structure_dump( @configuration.merge('port' => 10000), @@ -317,7 +317,7 @@ module ActiveRecord def test_structure_dump_with_ssl filename = "awesome-file.sql" - Kernel.expects(:system).with("mysqldump", "--ssl-ca=ca.crt", "--result-file", filename, "--no-data", "--routines", "test-db").returns(true) + Kernel.expects(:system).with("mysqldump", "--ssl-ca=ca.crt", "--result-file", filename, "--no-data", "--routines", "--skip-comments", "test-db").returns(true) ActiveRecord::Tasks::DatabaseTasks.structure_dump( @configuration.merge("sslca" => "ca.crt"), diff --git a/activerecord/test/cases/tasks/postgresql_rake_test.rb b/activerecord/test/cases/tasks/postgresql_rake_test.rb index 6a0c7fbcb5..99d73e91a4 100644 --- a/activerecord/test/cases/tasks/postgresql_rake_test.rb +++ b/activerecord/test/cases/tasks/postgresql_rake_test.rb @@ -288,14 +288,14 @@ module ActiveRecord def test_structure_load filename = "awesome-file.sql" - Kernel.expects(:system).with('psql', '-q', '-f', filename, @configuration['database']).returns(true) + Kernel.expects(:system).with('psql', '-v', 'ON_ERROR_STOP=1', '-q', '-f', filename, @configuration['database']).returns(true) ActiveRecord::Tasks::DatabaseTasks.structure_load(@configuration, filename) end def test_structure_load_accepts_path_with_spaces filename = "awesome file.sql" - Kernel.expects(:system).with('psql', '-q', '-f', filename, @configuration['database']).returns(true) + Kernel.expects(:system).with('psql', '-v', 'ON_ERROR_STOP=1', '-q', '-f', filename, @configuration['database']).returns(true) ActiveRecord::Tasks::DatabaseTasks.structure_load(@configuration, filename) end diff --git a/activerecord/test/cases/test_case.rb b/activerecord/test/cases/test_case.rb index 87299c0dab..c8adc21bbc 100644 --- a/activerecord/test/cases/test_case.rb +++ b/activerecord/test/cases/test_case.rb @@ -12,10 +12,6 @@ module ActiveRecord SQLCounter.clear_log end - def assert_date_from_db(expected, actual, message = nil) - assert_equal expected.to_s, actual.to_s, message - end - def capture_sql SQLCounter.clear_log yield diff --git a/activerecord/test/cases/validations/i18n_validation_test.rb b/activerecord/test/cases/validations/i18n_validation_test.rb index b8307d6665..5b5307489a 100644 --- a/activerecord/test/cases/validations/i18n_validation_test.rb +++ b/activerecord/test/cases/validations/i18n_validation_test.rb @@ -41,10 +41,8 @@ class I18nValidationTest < ActiveRecord::TestCase [ "given custom message", {:message => "custom"}, {:message => "custom"}], [ "given if condition", {:if => lambda { true }}, {}], [ "given unless condition", {:unless => lambda { false }}, {}], - [ "given option that is not reserved", {:format => "jpg"}, {:format => "jpg" }] - # TODO Add :on case, but below doesn't work, because then the validation isn't run for some reason - # even when using .save instead .valid? - # [ "given on condition", {on: :save}, {}] + [ "given option that is not reserved", {:format => "jpg"}, {:format => "jpg" }], + [ "given on condition", {on: [:create, :update] }, {}] ] COMMON_CASES.each do |name, validation_options, generate_message_options| diff --git a/activerecord/test/cases/yaml_serialization_test.rb b/activerecord/test/cases/yaml_serialization_test.rb index 56909a8630..d1c9a00786 100644 --- a/activerecord/test/cases/yaml_serialization_test.rb +++ b/activerecord/test/cases/yaml_serialization_test.rb @@ -109,6 +109,16 @@ class YamlSerializationTest < ActiveRecord::TestCase assert_equal("Have a nice day", topic.content) end + def test_yaml_encoding_keeps_mutations + author = Author.first + author.name = "Sean" + dumped = YAML.load(YAML.dump(author)) + + assert_equal "Sean", dumped.name + assert_equal author.name_was, dumped.name_was + assert_equal author.changes, dumped.changes + end + private def yaml_fixture(file_name) diff --git a/activerecord/test/migrations/to_copy/1_people_have_hobbies.rb b/activerecord/test/migrations/to_copy/1_people_have_hobbies.rb index 607113b091..76734bcd7d 100644 --- a/activerecord/test/migrations/to_copy/1_people_have_hobbies.rb +++ b/activerecord/test/migrations/to_copy/1_people_have_hobbies.rb @@ -1,4 +1,4 @@ -class PeopleHaveLastNames < ActiveRecord::Migration::Current +class PeopleHaveHobbies < ActiveRecord::Migration::Current def self.up add_column "people", "hobbies", :text end diff --git a/activerecord/test/migrations/to_copy/2_people_have_descriptions.rb b/activerecord/test/migrations/to_copy/2_people_have_descriptions.rb index d4cbddab50..7f883dbb45 100644 --- a/activerecord/test/migrations/to_copy/2_people_have_descriptions.rb +++ b/activerecord/test/migrations/to_copy/2_people_have_descriptions.rb @@ -1,4 +1,4 @@ -class PeopleHaveLastNames < ActiveRecord::Migration::Current +class PeopleHaveDescriptions < ActiveRecord::Migration::Current def self.up add_column "people", "description", :text end diff --git a/activerecord/test/migrations/to_copy2/2_create_comments.rb b/activerecord/test/migrations/to_copy2/2_create_comments.rb index 2e9f5ec6bc..d361847d4b 100644 --- a/activerecord/test/migrations/to_copy2/2_create_comments.rb +++ b/activerecord/test/migrations/to_copy2/2_create_comments.rb @@ -1,4 +1,4 @@ -class CreateArticles < ActiveRecord::Migration::Current +class CreateComments < ActiveRecord::Migration::Current def self.up end diff --git a/activerecord/test/migrations/to_copy_with_name_collision/1_people_have_hobbies.rb b/activerecord/test/migrations/to_copy_with_name_collision/1_people_have_hobbies.rb index 8f81805fe1..1a863367dd 100644 --- a/activerecord/test/migrations/to_copy_with_name_collision/1_people_have_hobbies.rb +++ b/activerecord/test/migrations/to_copy_with_name_collision/1_people_have_hobbies.rb @@ -1,4 +1,4 @@ -class PeopleHaveLastNames < ActiveRecord::Migration::Current +class PeopleHaveHobbies < ActiveRecord::Migration::Current def self.up add_column "people", "hobbies", :string end diff --git a/activerecord/test/migrations/to_copy_with_timestamps/20090101010101_people_have_hobbies.rb b/activerecord/test/migrations/to_copy_with_timestamps/20090101010101_people_have_hobbies.rb index 607113b091..76734bcd7d 100644 --- a/activerecord/test/migrations/to_copy_with_timestamps/20090101010101_people_have_hobbies.rb +++ b/activerecord/test/migrations/to_copy_with_timestamps/20090101010101_people_have_hobbies.rb @@ -1,4 +1,4 @@ -class PeopleHaveLastNames < ActiveRecord::Migration::Current +class PeopleHaveHobbies < ActiveRecord::Migration::Current def self.up add_column "people", "hobbies", :text end diff --git a/activerecord/test/migrations/to_copy_with_timestamps/20090101010202_people_have_descriptions.rb b/activerecord/test/migrations/to_copy_with_timestamps/20090101010202_people_have_descriptions.rb index d4cbddab50..7f883dbb45 100644 --- a/activerecord/test/migrations/to_copy_with_timestamps/20090101010202_people_have_descriptions.rb +++ b/activerecord/test/migrations/to_copy_with_timestamps/20090101010202_people_have_descriptions.rb @@ -1,4 +1,4 @@ -class PeopleHaveLastNames < ActiveRecord::Migration::Current +class PeopleHaveDescriptions < ActiveRecord::Migration::Current def self.up add_column "people", "description", :text end diff --git a/activerecord/test/models/customer.rb b/activerecord/test/models/customer.rb index afe4b3d707..3338aaf7e1 100644 --- a/activerecord/test/models/customer.rb +++ b/activerecord/test/models/customer.rb @@ -64,7 +64,12 @@ class Fullname def self.parse(str) return nil unless str - new(*str.to_s.split) + + if str.is_a?(Hash) + new(str[:first], str[:last]) + else + new(*str.to_s.split) + end end def initialize(first, last = nil) |