diff options
Diffstat (limited to 'activerecord/lib')
45 files changed, 266 insertions, 161 deletions
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/association.rb b/activerecord/lib/active_record/associations/association.rb index f7edfbfb5f..62e867a353 100644 --- a/activerecord/lib/active_record/associations/association.rb +++ b/activerecord/lib/active_record/associations/association.rb @@ -217,7 +217,8 @@ module ActiveRecord unless record.is_a?(reflection.klass) fresh_class = reflection.class_name.safe_constantize unless fresh_class && record.is_a?(fresh_class) - message = "#{reflection.class_name}(##{reflection.klass.object_id}) expected, got #{record.class}(##{record.class.object_id})" + message = "#{reflection.class_name}(##{reflection.klass.object_id}) expected, "\ + "got #{record.inspect} which is an instance of #{record.class}(##{record.class.object_id})" raise ActiveRecord::AssociationTypeMismatch, message end end diff --git a/activerecord/lib/active_record/associations/collection_association.rb b/activerecord/lib/active_record/associations/collection_association.rb index 2dca6b612e..0eaa0a4f36 100644 --- a/activerecord/lib/active_record/associations/collection_association.rb +++ b/activerecord/lib/active_record/associations/collection_association.rb @@ -10,9 +10,9 @@ module ActiveRecord # HasManyAssociation => has_many # HasManyThroughAssociation + ThroughAssociation => has_many :through # - # CollectionAssociation class provides common methods to the collections + # The CollectionAssociation class provides common methods to the collections # defined by +has_and_belongs_to_many+, +has_many+ or +has_many+ with - # +:through association+ option. + # the +:through association+ option. # # You need to be careful with assumptions regarding the target: The proxy # does not fetch records from the database until it needs them, but new @@ -246,9 +246,12 @@ module ActiveRecord end end - # Count all records using SQL. Construct options and pass them with - # scope to the target class's +count+. + # Returns the number of records. If no arguments are given, it counts all + # columns using SQL. If one argument is given, it counts only the passed + # column using SQL. If a block is given, it counts the number of records + # yielding a true value. def count(column_name = nil) + return super if block_given? relation = scope if association_scope.distinct_value # This is needed because 'SELECT count(DISTINCT *)..' is not valid SQL. @@ -280,7 +283,7 @@ module ActiveRecord _options = records.extract_options! dependent = _options[:dependent] || options[:dependent] - records = find(records) if records.any? { |record| record.kind_of?(Fixnum) || record.kind_of?(String) } + records = find(records) if records.any? { |record| record.kind_of?(Integer) || record.kind_of?(String) } delete_or_destroy(records, dependent) end @@ -291,7 +294,7 @@ module ActiveRecord # +:dependent+ option. def destroy(*records) return if records.empty? - records = find(records) if records.any? { |record| record.kind_of?(Fixnum) || record.kind_of?(String) } + records = find(records) if records.any? { |record| record.kind_of?(Integer) || record.kind_of?(String) } delete_or_destroy(records, :destroy) end diff --git a/activerecord/lib/active_record/associations/collection_proxy.rb b/activerecord/lib/active_record/associations/collection_proxy.rb index b9aed05135..5d1e7ffb73 100644 --- a/activerecord/lib/active_record/associations/collection_proxy.rb +++ b/activerecord/lib/active_record/associations/collection_proxy.rb @@ -597,7 +597,7 @@ module ActiveRecord # Pet.find(1) # # => ActiveRecord::RecordNotFound: Couldn't find Pet with 'id'=1 # - # You can pass +Fixnum+ or +String+ values, it finds the records + # You can pass +Integer+ or +String+ values, it finds the records # responding to the +id+ and executes delete on them. # # class Person < ActiveRecord::Base @@ -661,7 +661,7 @@ module ActiveRecord # # Pet.find(1, 2, 3) # => ActiveRecord::RecordNotFound: Couldn't find all Pets with 'id': (1, 2, 3) # - # You can pass +Fixnum+ or +String+ values, it finds the records + # You can pass +Integer+ or +String+ values, it finds the records # responding to the +id+ and then deletes them from the database. # # person.pets.size # => 3 @@ -715,12 +715,13 @@ module ActiveRecord end alias uniq distinct - # Count all records using SQL. + # Count all records. # # class Person < ActiveRecord::Base # has_many :pets # end # + # # This will perform the count using SQL. # person.pets.count # => 3 # person.pets # # => [ @@ -728,8 +729,13 @@ module ActiveRecord # # #<Pet id: 2, name: "Spook", person_id: 1>, # # #<Pet id: 3, name: "Choo-Choo", person_id: 1> # # ] - def count(column_name = nil) - @association.count(column_name) + # + # Passing a block will select all of a person's pets in SQL and then + # perform the count using Ruby. + # + # person.pets.count { |pet| pet.name.include?('-') } # => 2 + def count(column_name = nil, &block) + @association.count(column_name, &block) end # Returns the size of the collection. If the collection hasn't been loaded, 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 3c4c8f10ec..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 @@ -170,7 +190,7 @@ module ActiveRecord super(name, nil, Type::Value.new) end - def value + def type_cast(*) nil end @@ -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_assignment.rb b/activerecord/lib/active_record/attribute_assignment.rb index 4c22be8235..b96d8e9352 100644 --- a/activerecord/lib/active_record/attribute_assignment.rb +++ b/activerecord/lib/active_record/attribute_assignment.rb @@ -38,7 +38,7 @@ module ActiveRecord # by calling new on the column type or aggregation type (through composed_of) object with these parameters. # So having the pairs written_on(1) = "2004", written_on(2) = "6", written_on(3) = "24", will instantiate # written_on (a date type) with Date.new("2004", "6", "24"). You can also specify a typecast character in the - # parentheses to have the parameters typecasted before they're used in the constructor. Use i for Fixnum and + # parentheses to have the parameters typecasted before they're used in the constructor. Use i for Integer and # f for Float. If all the values for a given attribute are empty, the attribute will be set to +nil+. def assign_multiparameter_attributes(pairs) execute_callstack_for_multiparameter_attributes( diff --git a/activerecord/lib/active_record/attribute_methods.rb b/activerecord/lib/active_record/attribute_methods.rb index e902eb7531..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 @@ -360,7 +358,7 @@ module ActiveRecord # person = Person.new # person[:age] = '22' # person[:age] # => 22 - # person[:age] # => Fixnum + # person[:age].class # => Integer def []=(attr_name, value) write_attribute(attr_name, value) end diff --git a/activerecord/lib/active_record/attribute_methods/write.rb b/activerecord/lib/active_record/attribute_methods/write.rb index 5599b590ca..70c2d2f25d 100644 --- a/activerecord/lib/active_record/attribute_methods/write.rb +++ b/activerecord/lib/active_record/attribute_methods/write.rb @@ -26,7 +26,7 @@ module ActiveRecord end # Updates the attribute identified by <tt>attr_name</tt> with the - # specified +value+. Empty strings for fixnum and float columns are + # specified +value+. Empty strings for Integer and Float columns are # turned into +nil+. def write_attribute(attr_name, value) write_attribute_with_type_cast(attr_name, value, true) 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..6208048231 --- /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 + 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/coders/json.rb b/activerecord/lib/active_record/coders/json.rb index 75d3bfe625..cb185a881e 100644 --- a/activerecord/lib/active_record/coders/json.rb +++ b/activerecord/lib/active_record/coders/json.rb @@ -6,7 +6,7 @@ module ActiveRecord end def self.load(json) - ActiveSupport::JSON.decode(json) unless json.nil? + ActiveSupport::JSON.decode(json) unless json.blank? 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 1bea16ebcc..c341773be1 100644 --- a/activerecord/lib/active_record/connection_adapters/abstract/connection_pool.rb +++ b/activerecord/lib/active_record/connection_adapters/abstract/connection_pool.rb @@ -826,9 +826,7 @@ module ActiveRecord # in order to lookup the correct connection pool. class ConnectionHandler def initialize - # These caches are keyed by klass.name, NOT klass. Keying them by klass - # alone would lead to memory leaks in development mode as all previous - # instances of the class would stay in memory. + # These caches are keyed by spec.name (ConnectionSpecification#name). @owner_to_pool = Concurrent::Map.new(:initial_capacity => 2) do |h,k| h[k] = Concurrent::Map.new(:initial_capacity => 2) end @@ -839,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 @@ -873,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 @@ -898,15 +900,9 @@ module ActiveRecord end end - # Retrieving the connection pool happens a lot so we cache it in @class_to_pool. + # Retrieving the connection pool happens a lot, so we cache it in @owner_to_pool. # This makes retrieving the connection pool O(1) once the process is warm. # When a connection is established or removed, we invalidate the cache. - # - # Ideally we would use #fetch here, as class_to_pool[klass] may sometimes be nil. - # However, benchmarking (https://gist.github.com/jonleighton/3552829) showed that - # #fetch is significantly slower than #[]. So in the nil case, no caching will - # take place, but that's ok since the nil case is not the common one that we wish - # to optimise for. def retrieve_connection_pool(spec_name) owner_to_pool.fetch(spec_name) do # Check if a connection was previously established in an ancestor process, @@ -915,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 fdd6bffa13..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" }, } @@ -707,7 +707,7 @@ module ActiveRecord case length when Hash column_names.each {|name| option_strings[name] += "(#{length[name]})" if length.has_key?(name) && length[name].present?} - when Fixnum + when Integer column_names.each {|name| option_strings[name] += "(#{length})"} end end @@ -727,14 +727,22 @@ module ActiveRecord column_names.map {|name| quote_column_name(name) + option_strings[name]} end + # See https://dev.mysql.com/doc/refman/5.7/en/error-messages-server.html + ER_DUP_ENTRY = 1062 + ER_NO_REFERENCED_ROW_2 = 1452 + ER_DATA_TOO_LONG = 1406 + ER_LOCK_DEADLOCK = 1213 + def translate_exception(exception, message) case error_number(exception) - when 1062 + when ER_DUP_ENTRY RecordNotUnique.new(message) - when 1452 + when ER_NO_REFERENCED_ROW_2 InvalidForeignKey.new(message) - when 1406 + when ER_DATA_TOO_LONG ValueTooLong.new(message) + when ER_LOCK_DEADLOCK + TransactionSerializationError.new(message) else super end @@ -832,7 +840,7 @@ module ActiveRecord # Increase timeout so the server doesn't disconnect us. wait_timeout = @config[:wait_timeout] - wait_timeout = 2147483 unless wait_timeout.is_a?(Fixnum) + wait_timeout = 2147483 unless wait_timeout.is_a?(Integer) variables['wait_timeout'] = self.class.type_cast_config_to_integer(wait_timeout) defaults = [':default', :default].to_set 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/postgresql/oid/rails_5_1_point.rb b/activerecord/lib/active_record/connection_adapters/postgresql/oid/rails_5_1_point.rb index 7427a25ad5..4da240edb2 100644 --- a/activerecord/lib/active_record/connection_adapters/postgresql/oid/rails_5_1_point.rb +++ b/activerecord/lib/active_record/connection_adapters/postgresql/oid/rails_5_1_point.rb @@ -14,6 +14,8 @@ module ActiveRecord def cast(value) case value when ::String + return if value.blank? + if value[0] == '(' && value[-1] == ')' value = value[1...-1] 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_adapters/postgresql_adapter.rb b/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb index bab80a8890..ddfc560747 100644 --- a/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb +++ b/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb @@ -406,6 +406,7 @@ module ActiveRecord VALUE_LIMIT_VIOLATION = "22001" FOREIGN_KEY_VIOLATION = "23503" UNIQUE_VIOLATION = "23505" + SERIALIZATION_FAILURE = "40001" def translate_exception(exception, message) return exception unless exception.respond_to?(:result) @@ -417,6 +418,8 @@ module ActiveRecord InvalidForeignKey.new(message) when VALUE_LIMIT_VIOLATION ValueTooLong.new(message) + when SERIALIZATION_FAILURE + TransactionSerializationError.new(message) else super end diff --git a/activerecord/lib/active_record/connection_handling.rb b/activerecord/lib/active_record/connection_handling.rb index a628ee4dbd..086c678af5 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) - self.connection_specification_name = spec.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 - connection_handler.establish_connection spec + connection_handler.establish_connection(spec) end class MergeAndResolveDefaultUrlConfig # :nodoc: @@ -95,8 +92,8 @@ module ActiveRecord # Return the specification name from the current class or its parent. def connection_specification_name - unless defined?(@connection_specification_name) - @connection_specification_name = self == Base ? "primary" : superclass.connection_specification_name + if !defined?(@connection_specification_name) || @connection_specification_name.nil? + return self == Base ? "primary" : superclass.connection_specification_name end @connection_specification_name end @@ -132,7 +129,15 @@ module ActiveRecord connection_handler.connected?(connection_specification_name) end - def remove_connection(name = connection_specification_name) + 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 + # connection_specification_name so it will use the parent + # pool. + if connection_handler.retrieve_connection_pool(name) + self.connection_specification_name = nil + end + connection_handler.remove_connection(name) end 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/errors.rb b/activerecord/lib/active_record/errors.rb index b8b8684cff..38e4fbec8b 100644 --- a/activerecord/lib/active_record/errors.rb +++ b/activerecord/lib/active_record/errors.rb @@ -285,6 +285,16 @@ module ActiveRecord class TransactionIsolationError < ActiveRecordError end + # TransactionSerializationError will be raised when a transaction is rolled + # back by the database due to a serialization failure or a deadlock. + # + # See the following: + # + # * http://www.postgresql.org/docs/current/static/transaction-iso.html + # * https://dev.mysql.com/doc/refman/5.7/en/error-messages-server.html#error_er_lock_deadlock + class TransactionSerializationError < ActiveRecordError + end + # IrreversibleOrderError is raised when a relation's order is too complex for # +reverse_order+ to automatically reverse. class IrreversibleOrderError < ActiveRecordError 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/internal_metadata.rb b/activerecord/lib/active_record/internal_metadata.rb index 81db96bffd..17a5dc1d1b 100644 --- a/activerecord/lib/active_record/internal_metadata.rb +++ b/activerecord/lib/active_record/internal_metadata.rb @@ -19,7 +19,7 @@ module ActiveRecord end def []=(key, value) - first_or_initialize(key: key).update_attributes!(value: value) + find_or_initialize_by(key: key).update_attributes!(value: value) end def [](key) 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/locking/optimistic.rb b/activerecord/lib/active_record/locking/optimistic.rb index 1e37ffefc6..67b8efac66 100644 --- a/activerecord/lib/active_record/locking/optimistic.rb +++ b/activerecord/lib/active_record/locking/optimistic.rb @@ -184,9 +184,12 @@ module ActiveRecord end end + + # In de/serialize we change `nil` to 0, so that we can allow passing + # `nil` values to `lock_version`, and not result in `ActiveRecord::StaleObjectError` + # during update record. class LockingType < DelegateClass(Type::Value) # :nodoc: def deserialize(value) - # `nil` *should* be changed to 0 super.to_i end diff --git a/activerecord/lib/active_record/log_subscriber.rb b/activerecord/lib/active_record/log_subscriber.rb index efa2a4df02..8e32af1c49 100644 --- a/activerecord/lib/active_record/log_subscriber.rb +++ b/activerecord/lib/active_record/log_subscriber.rb @@ -22,7 +22,11 @@ module ActiveRecord def render_bind(attribute) value = if attribute.type.binary? && attribute.value - "<#{attribute.value.bytesize} bytes of binary data>" + if attribute.value.is_a?(Hash) + "<#{attribute.value_for_database.to_s.bytesize} bytes of binary data>" + else + "<#{attribute.value.bytesize} bytes of binary data>" + end else attribute.value_for_database end diff --git a/activerecord/lib/active_record/migration.rb b/activerecord/lib/active_record/migration.rb index f30861b4d0..81fe053fe1 100644 --- a/activerecord/lib/active_record/migration.rb +++ b/activerecord/lib/active_record/migration.rb @@ -166,13 +166,13 @@ module ActiveRecord class EnvironmentMismatchError < ActiveRecordError def initialize(current: nil, stored: nil) msg = "You are attempting to modify a database that was last run in `#{ stored }` environment.\n" - msg << "You are running in `#{ current }` environment." + msg << "You are running in `#{ current }` environment. " msg << "If you are sure you want to continue, first set the environment using:\n\n" msg << "\tbin/rails db:environment:set" if defined?(Rails.env) - super("#{msg} RAILS_ENV=#{::Rails.env}") + super("#{msg} RAILS_ENV=#{::Rails.env}\n\n") else - super(msg) + super("#{msg}\n\n") end end end 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/calculations.rb b/activerecord/lib/active_record/relation/calculations.rb index 54c9af4898..d6d92b8607 100644 --- a/activerecord/lib/active_record/relation/calculations.rb +++ b/activerecord/lib/active_record/relation/calculations.rb @@ -37,7 +37,11 @@ module ActiveRecord # Note: not all valid {Relation#select}[rdoc-ref:QueryMethods#select] expressions are valid #count expressions. The specifics differ # between databases. In invalid cases, an error from the database is thrown. def count(column_name = nil) - calculate(:count, column_name) + if block_given? + to_a.count { |*block_args| yield(*block_args) } + else + calculate(:count, column_name) + end end # Calculates the average value on a given column. Returns +nil+ if there's @@ -89,7 +93,7 @@ module ActiveRecord # # There are two basic forms of output: # - # * Single aggregate value: The single value is type cast to Fixnum for COUNT, Float + # * Single aggregate value: The single value is type cast to Integer for COUNT, Float # for AVG, and the given column's type for everything else. # # * Grouped values: This returns an ordered hash of the values and groups them. It 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/schema_dumper.rb b/activerecord/lib/active_record/schema_dumper.rb index 301718b874..d769376d1a 100644 --- a/activerecord/lib/active_record/schema_dumper.rb +++ b/activerecord/lib/active_record/schema_dumper.rb @@ -50,10 +50,6 @@ module ActiveRecord def header(stream) define_params = @version ? "version: #{@version}" : "" - if stream.respond_to?(:external_encoding) && stream.external_encoding - stream.puts "# encoding: #{stream.external_encoding.name}" - end - stream.puts <<HEADER # This file is auto-generated from the current state of the database. Instead # of editing this file, please use the migrations feature of Active Record to diff --git a/activerecord/lib/active_record/suppressor.rb b/activerecord/lib/active_record/suppressor.rb index 8ec4b48d31..d9acb1a1dc 100644 --- a/activerecord/lib/active_record/suppressor.rb +++ b/activerecord/lib/active_record/suppressor.rb @@ -30,10 +30,11 @@ module ActiveRecord module ClassMethods def suppress(&block) + previous_state = SuppressorRegistry.suppressed[name] SuppressorRegistry.suppressed[name] = true yield ensure - SuppressorRegistry.suppressed[name] = false + SuppressorRegistry.suppressed[name] = previous_state end end 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/type/serialized.rb b/activerecord/lib/active_record/type/serialized.rb index 4ff0740cfb..a3a5241780 100644 --- a/activerecord/lib/active_record/type/serialized.rb +++ b/activerecord/lib/active_record/type/serialized.rb @@ -32,7 +32,7 @@ module ActiveRecord def changed_in_place?(raw_old_value, value) return false if value.nil? - raw_new_value = serialize(value) + raw_new_value = encoded(value) raw_old_value.nil? != raw_new_value.nil? || subtype.changed_in_place?(raw_old_value, raw_new_value) end @@ -52,6 +52,12 @@ module ActiveRecord def default_value?(value) value == coder.load(nil) end + + def encoded(value) + unless default_value?(value) + coder.dump(value) + end + end end end end 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 |