aboutsummaryrefslogtreecommitdiffstats
path: root/activerecord/lib
diff options
context:
space:
mode:
authorXavier Noria <fxn@hashref.com>2016-08-06 19:55:02 +0200
committerXavier Noria <fxn@hashref.com>2016-08-06 20:16:27 +0200
commit80e66cc4d90bf8c15d1a5f6e3152e90147f00772 (patch)
treee7e75464af04f3cf1935b29238dbd7cb2337b0dd /activerecord/lib
parent411ccbdab2608c62aabdb320d52cb02d446bb39c (diff)
downloadrails-80e66cc4d90bf8c15d1a5f6e3152e90147f00772.tar.gz
rails-80e66cc4d90bf8c15d1a5f6e3152e90147f00772.tar.bz2
rails-80e66cc4d90bf8c15d1a5f6e3152e90147f00772.zip
normalizes indentation and whitespace across the project
Diffstat (limited to 'activerecord/lib')
-rw-r--r--activerecord/lib/active_record/aggregations.rb174
-rw-r--r--activerecord/lib/active_record/association_relation.rb6
-rw-r--r--activerecord/lib/active_record/associations.rb1318
-rw-r--r--activerecord/lib/active_record/associations/association_scope.rb158
-rw-r--r--activerecord/lib/active_record/associations/builder/has_and_belongs_to_many.rb44
-rw-r--r--activerecord/lib/active_record/associations/collection_association.rb2
-rw-r--r--activerecord/lib/active_record/associations/join_dependency.rb210
-rw-r--r--activerecord/lib/active_record/associations/preloader.rb134
-rw-r--r--activerecord/lib/active_record/associations/preloader/association.rb142
-rw-r--r--activerecord/lib/active_record/associations/preloader/collection_association.rb14
-rw-r--r--activerecord/lib/active_record/associations/preloader/singular_association.rb14
-rw-r--r--activerecord/lib/active_record/associations/preloader/through_association.rb64
-rw-r--r--activerecord/lib/active_record/attribute.rb146
-rw-r--r--activerecord/lib/active_record/attribute/user_provided_default.rb2
-rw-r--r--activerecord/lib/active_record/attribute_assignment.rb106
-rw-r--r--activerecord/lib/active_record/attribute_decorators.rb26
-rw-r--r--activerecord/lib/active_record/attribute_methods.rb82
-rw-r--r--activerecord/lib/active_record/attribute_methods/before_type_cast.rb12
-rw-r--r--activerecord/lib/active_record/attribute_methods/dirty.rb72
-rw-r--r--activerecord/lib/active_record/attribute_methods/primary_key.rb134
-rw-r--r--activerecord/lib/active_record/attribute_methods/read.rb18
-rw-r--r--activerecord/lib/active_record/attribute_methods/serialization.rb2
-rw-r--r--activerecord/lib/active_record/attribute_methods/time_zone_conversion.rb88
-rw-r--r--activerecord/lib/active_record/attribute_methods/write.rb36
-rw-r--r--activerecord/lib/active_record/attribute_mutation_tracker.rb8
-rw-r--r--activerecord/lib/active_record/attribute_set.rb8
-rw-r--r--activerecord/lib/active_record/attribute_set/builder.rb38
-rw-r--r--activerecord/lib/active_record/attribute_set/yaml_encoder.rb2
-rw-r--r--activerecord/lib/active_record/attributes.rb32
-rw-r--r--activerecord/lib/active_record/coders/yaml_column.rb12
-rw-r--r--activerecord/lib/active_record/connection_adapters/abstract/connection_pool.rb360
-rw-r--r--activerecord/lib/active_record/connection_adapters/abstract/query_cache.rb28
-rw-r--r--activerecord/lib/active_record/connection_adapters/abstract/quoting.rb76
-rw-r--r--activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb82
-rw-r--r--activerecord/lib/active_record/connection_adapters/abstract/schema_dumper.rb66
-rw-r--r--activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb64
-rw-r--r--activerecord/lib/active_record/connection_adapters/abstract_adapter.rb182
-rw-r--r--activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb536
-rw-r--r--activerecord/lib/active_record/connection_adapters/column.rb6
-rw-r--r--activerecord/lib/active_record/connection_adapters/connection_specification.rb112
-rw-r--r--activerecord/lib/active_record/connection_adapters/mysql/column.rb8
-rw-r--r--activerecord/lib/active_record/connection_adapters/mysql/database_statements.rb76
-rw-r--r--activerecord/lib/active_record/connection_adapters/mysql/explain_pretty_printer.rb44
-rw-r--r--activerecord/lib/active_record/connection_adapters/mysql/quoting.rb12
-rw-r--r--activerecord/lib/active_record/connection_adapters/mysql/schema_creation.rb84
-rw-r--r--activerecord/lib/active_record/connection_adapters/mysql/schema_definitions.rb6
-rw-r--r--activerecord/lib/active_record/connection_adapters/mysql/schema_dumper.rb36
-rw-r--r--activerecord/lib/active_record/connection_adapters/mysql/type_metadata.rb6
-rw-r--r--activerecord/lib/active_record/connection_adapters/mysql2_adapter.rb22
-rw-r--r--activerecord/lib/active_record/connection_adapters/postgresql/database_statements.rb6
-rw-r--r--activerecord/lib/active_record/connection_adapters/postgresql/oid/array.rb12
-rw-r--r--activerecord/lib/active_record/connection_adapters/postgresql/oid/bit.rb2
-rw-r--r--activerecord/lib/active_record/connection_adapters/postgresql/oid/enum.rb6
-rw-r--r--activerecord/lib/active_record/connection_adapters/postgresql/oid/hstore.rb26
-rw-r--r--activerecord/lib/active_record/connection_adapters/postgresql/oid/point.rb6
-rw-r--r--activerecord/lib/active_record/connection_adapters/postgresql/oid/rails_5_1_point.rb14
-rw-r--r--activerecord/lib/active_record/connection_adapters/postgresql/oid/range.rb52
-rw-r--r--activerecord/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb88
-rw-r--r--activerecord/lib/active_record/connection_adapters/postgresql/quoting.rb60
-rw-r--r--activerecord/lib/active_record/connection_adapters/postgresql/schema_dumper.rb26
-rw-r--r--activerecord/lib/active_record/connection_adapters/postgresql/schema_statements.rb18
-rw-r--r--activerecord/lib/active_record/connection_adapters/postgresql/type_metadata.rb6
-rw-r--r--activerecord/lib/active_record/connection_adapters/sql_type_metadata.rb6
-rw-r--r--activerecord/lib/active_record/connection_adapters/sqlite3/quoting.rb32
-rw-r--r--activerecord/lib/active_record/connection_adapters/sqlite3_adapter.rb6
-rw-r--r--activerecord/lib/active_record/connection_adapters/statement_pool.rb12
-rw-r--r--activerecord/lib/active_record/core.rb86
-rw-r--r--activerecord/lib/active_record/dynamic_matchers.rb148
-rw-r--r--activerecord/lib/active_record/enum.rb2
-rw-r--r--activerecord/lib/active_record/fixtures.rb26
-rw-r--r--activerecord/lib/active_record/inheritance.rb132
-rw-r--r--activerecord/lib/active_record/locking/optimistic.rb86
-rw-r--r--activerecord/lib/active_record/log_subscriber.rb56
-rw-r--r--activerecord/lib/active_record/migration.rb230
-rw-r--r--activerecord/lib/active_record/migration/command_recorder.rb176
-rw-r--r--activerecord/lib/active_record/migration/compatibility.rb24
-rw-r--r--activerecord/lib/active_record/migration/join_table.rb12
-rw-r--r--activerecord/lib/active_record/model_schema.rb124
-rw-r--r--activerecord/lib/active_record/nested_attributes.rb232
-rw-r--r--activerecord/lib/active_record/railties/databases.rake4
-rw-r--r--activerecord/lib/active_record/relation.rb68
-rw-r--r--activerecord/lib/active_record/relation/batches.rb30
-rw-r--r--activerecord/lib/active_record/relation/calculations.rb296
-rw-r--r--activerecord/lib/active_record/relation/delegation.rb42
-rw-r--r--activerecord/lib/active_record/relation/finder_methods.rb336
-rw-r--r--activerecord/lib/active_record/relation/merger.rb122
-rw-r--r--activerecord/lib/active_record/relation/predicate_builder.rb134
-rw-r--r--activerecord/lib/active_record/relation/predicate_builder/array_handler.rb10
-rw-r--r--activerecord/lib/active_record/relation/predicate_builder/association_query_handler.rb42
-rw-r--r--activerecord/lib/active_record/relation/predicate_builder/base_handler.rb2
-rw-r--r--activerecord/lib/active_record/relation/predicate_builder/class_handler.rb8
-rw-r--r--activerecord/lib/active_record/relation/predicate_builder/polymorphic_array_handler.rb20
-rw-r--r--activerecord/lib/active_record/relation/query_methods.rb412
-rw-r--r--activerecord/lib/active_record/relation/where_clause.rb122
-rw-r--r--activerecord/lib/active_record/relation/where_clause_factory.rb2
-rw-r--r--activerecord/lib/active_record/result.rb58
-rw-r--r--activerecord/lib/active_record/sanitization.rb180
-rw-r--r--activerecord/lib/active_record/scoping.rb8
-rw-r--r--activerecord/lib/active_record/scoping/default.rb84
-rw-r--r--activerecord/lib/active_record/store.rb48
-rw-r--r--activerecord/lib/active_record/table_metadata.rb2
-rw-r--r--activerecord/lib/active_record/tasks/database_tasks.rb50
-rw-r--r--activerecord/lib/active_record/tasks/mysql_database_tasks.rb116
-rw-r--r--activerecord/lib/active_record/tasks/postgresql_database_tasks.rb54
-rw-r--r--activerecord/lib/active_record/tasks/sqlite_database_tasks.rb12
-rw-r--r--activerecord/lib/active_record/transactions.rb140
-rw-r--r--activerecord/lib/active_record/type/adapter_specific_registry.rb82
-rw-r--r--activerecord/lib/active_record/type/hash_lookup_type_map.rb6
-rw-r--r--activerecord/lib/active_record/type/serialized.rb14
-rw-r--r--activerecord/lib/active_record/type/time.rb1
-rw-r--r--activerecord/lib/active_record/type/type_map.rb24
-rw-r--r--activerecord/lib/active_record/type_caster/connection.rb12
-rw-r--r--activerecord/lib/active_record/type_caster/map.rb2
-rw-r--r--activerecord/lib/rails/generators/active_record/migration/migration_generator.rb54
114 files changed, 4609 insertions, 4610 deletions
diff --git a/activerecord/lib/active_record/aggregations.rb b/activerecord/lib/active_record/aggregations.rb
index 9f965052c5..55076c4314 100644
--- a/activerecord/lib/active_record/aggregations.rb
+++ b/activerecord/lib/active_record/aggregations.rb
@@ -179,104 +179,104 @@ module ActiveRecord
#
# Customer.where(balance: Money.new(20, "USD"))
#
- module ClassMethods
- # Adds reader and writer methods for manipulating a value object:
- # <tt>composed_of :address</tt> adds <tt>address</tt> and <tt>address=(new_address)</tt> methods.
- #
- # Options are:
- # * <tt>:class_name</tt> - Specifies the class name of the association. Use it only if that name
- # can't be inferred from the part id. So <tt>composed_of :address</tt> will by default be linked
- # to the Address class, but if the real class name is +CompanyAddress+, you'll have to specify it
- # with this option.
- # * <tt>:mapping</tt> - Specifies the mapping of entity attributes to attributes of the value
- # object. Each mapping is represented as an array where the first item is the name of the
- # entity attribute and the second item is the name of the attribute in the value object. The
- # order in which mappings are defined determines the order in which attributes are sent to the
- # value class constructor.
- # * <tt>:allow_nil</tt> - Specifies that the value object will not be instantiated when all mapped
- # attributes are +nil+. Setting the value object to +nil+ has the effect of writing +nil+ to all
- # mapped attributes.
- # This defaults to +false+.
- # * <tt>:constructor</tt> - A symbol specifying the name of the constructor method or a Proc that
- # is called to initialize the value object. The constructor is passed all of the mapped attributes,
- # in the order that they are defined in the <tt>:mapping option</tt>, as arguments and uses them
- # to instantiate a <tt>:class_name</tt> object.
- # The default is <tt>:new</tt>.
- # * <tt>:converter</tt> - A symbol specifying the name of a class method of <tt>:class_name</tt>
- # or a Proc that is called when a new value is assigned to the value object. The converter is
- # passed the single value that is used in the assignment and is only called if the new value is
- # not an instance of <tt>:class_name</tt>. If <tt>:allow_nil</tt> is set to true, the converter
- # can return nil to skip the assignment.
- #
- # Option examples:
- # composed_of :temperature, mapping: %w(reading celsius)
- # composed_of :balance, class_name: "Money", mapping: %w(balance amount),
- # converter: Proc.new { |balance| balance.to_money }
- # composed_of :address, mapping: [ %w(address_street street), %w(address_city city) ]
- # composed_of :gps_location
- # composed_of :gps_location, allow_nil: true
- # composed_of :ip_address,
- # class_name: 'IPAddr',
- # mapping: %w(ip to_i),
- # constructor: Proc.new { |ip| IPAddr.new(ip, Socket::AF_INET) },
- # converter: Proc.new { |ip| ip.is_a?(Integer) ? IPAddr.new(ip, Socket::AF_INET) : IPAddr.new(ip.to_s) }
- #
- def composed_of(part_id, options = {})
- options.assert_valid_keys(:class_name, :mapping, :allow_nil, :constructor, :converter)
+ module ClassMethods
+ # Adds reader and writer methods for manipulating a value object:
+ # <tt>composed_of :address</tt> adds <tt>address</tt> and <tt>address=(new_address)</tt> methods.
+ #
+ # Options are:
+ # * <tt>:class_name</tt> - Specifies the class name of the association. Use it only if that name
+ # can't be inferred from the part id. So <tt>composed_of :address</tt> will by default be linked
+ # to the Address class, but if the real class name is +CompanyAddress+, you'll have to specify it
+ # with this option.
+ # * <tt>:mapping</tt> - Specifies the mapping of entity attributes to attributes of the value
+ # object. Each mapping is represented as an array where the first item is the name of the
+ # entity attribute and the second item is the name of the attribute in the value object. The
+ # order in which mappings are defined determines the order in which attributes are sent to the
+ # value class constructor.
+ # * <tt>:allow_nil</tt> - Specifies that the value object will not be instantiated when all mapped
+ # attributes are +nil+. Setting the value object to +nil+ has the effect of writing +nil+ to all
+ # mapped attributes.
+ # This defaults to +false+.
+ # * <tt>:constructor</tt> - A symbol specifying the name of the constructor method or a Proc that
+ # is called to initialize the value object. The constructor is passed all of the mapped attributes,
+ # in the order that they are defined in the <tt>:mapping option</tt>, as arguments and uses them
+ # to instantiate a <tt>:class_name</tt> object.
+ # The default is <tt>:new</tt>.
+ # * <tt>:converter</tt> - A symbol specifying the name of a class method of <tt>:class_name</tt>
+ # or a Proc that is called when a new value is assigned to the value object. The converter is
+ # passed the single value that is used in the assignment and is only called if the new value is
+ # not an instance of <tt>:class_name</tt>. If <tt>:allow_nil</tt> is set to true, the converter
+ # can return nil to skip the assignment.
+ #
+ # Option examples:
+ # composed_of :temperature, mapping: %w(reading celsius)
+ # composed_of :balance, class_name: "Money", mapping: %w(balance amount),
+ # converter: Proc.new { |balance| balance.to_money }
+ # composed_of :address, mapping: [ %w(address_street street), %w(address_city city) ]
+ # composed_of :gps_location
+ # composed_of :gps_location, allow_nil: true
+ # composed_of :ip_address,
+ # class_name: 'IPAddr',
+ # mapping: %w(ip to_i),
+ # constructor: Proc.new { |ip| IPAddr.new(ip, Socket::AF_INET) },
+ # converter: Proc.new { |ip| ip.is_a?(Integer) ? IPAddr.new(ip, Socket::AF_INET) : IPAddr.new(ip.to_s) }
+ #
+ def composed_of(part_id, options = {})
+ options.assert_valid_keys(:class_name, :mapping, :allow_nil, :constructor, :converter)
- name = part_id.id2name
- class_name = options[:class_name] || name.camelize
- mapping = options[:mapping] || [ name, name ]
- mapping = [ mapping ] unless mapping.first.is_a?(Array)
- allow_nil = options[:allow_nil] || false
- constructor = options[:constructor] || :new
- converter = options[:converter]
+ name = part_id.id2name
+ class_name = options[:class_name] || name.camelize
+ mapping = options[:mapping] || [ name, name ]
+ mapping = [ mapping ] unless mapping.first.is_a?(Array)
+ allow_nil = options[:allow_nil] || false
+ constructor = options[:constructor] || :new
+ converter = options[:converter]
- reader_method(name, class_name, mapping, allow_nil, constructor)
- writer_method(name, class_name, mapping, allow_nil, converter)
+ reader_method(name, class_name, mapping, allow_nil, constructor)
+ writer_method(name, class_name, mapping, allow_nil, converter)
- reflection = ActiveRecord::Reflection.create(:composed_of, part_id, nil, options, self)
- Reflection.add_aggregate_reflection self, part_id, reflection
- end
+ reflection = ActiveRecord::Reflection.create(:composed_of, part_id, nil, options, self)
+ Reflection.add_aggregate_reflection self, part_id, reflection
+ end
- private
- def reader_method(name, class_name, mapping, allow_nil, constructor)
- define_method(name) do
- if @aggregation_cache[name].nil? && (!allow_nil || mapping.any? {|key, _| !_read_attribute(key).nil? })
- attrs = mapping.collect {|key, _| _read_attribute(key)}
- object = constructor.respond_to?(:call) ?
- constructor.call(*attrs) :
- class_name.constantize.send(constructor, *attrs)
- @aggregation_cache[name] = object
+ private
+ def reader_method(name, class_name, mapping, allow_nil, constructor)
+ define_method(name) do
+ if @aggregation_cache[name].nil? && (!allow_nil || mapping.any? {|key, _| !_read_attribute(key).nil? })
+ attrs = mapping.collect {|key, _| _read_attribute(key)}
+ object = constructor.respond_to?(:call) ?
+ constructor.call(*attrs) :
+ class_name.constantize.send(constructor, *attrs)
+ @aggregation_cache[name] = object
+ end
+ @aggregation_cache[name]
end
- @aggregation_cache[name]
end
- end
- def writer_method(name, class_name, mapping, allow_nil, converter)
- define_method("#{name}=") do |part|
- klass = class_name.constantize
+ def writer_method(name, class_name, mapping, allow_nil, converter)
+ define_method("#{name}=") do |part|
+ klass = class_name.constantize
- unless part.is_a?(klass) || converter.nil? || part.nil?
- part = converter.respond_to?(:call) ? converter.call(part) : klass.send(converter, part)
- end
+ unless part.is_a?(klass) || converter.nil? || part.nil?
+ part = converter.respond_to?(:call) ? converter.call(part) : klass.send(converter, part)
+ end
- hash_from_multiparameter_assignment = part.is_a?(Hash) &&
- part.each_key.all? { |k| k.is_a?(Integer) }
- if hash_from_multiparameter_assignment
- raise ArgumentError unless part.size == part.each_key.max
- part = klass.new(*part.sort.map(&:last))
- end
+ hash_from_multiparameter_assignment = part.is_a?(Hash) &&
+ part.each_key.all? { |k| k.is_a?(Integer) }
+ if hash_from_multiparameter_assignment
+ raise ArgumentError unless part.size == part.each_key.max
+ part = klass.new(*part.sort.map(&:last))
+ end
- if part.nil? && allow_nil
- mapping.each { |key, _| self[key] = nil }
- @aggregation_cache[name] = nil
- else
- mapping.each { |key, value| self[key] = part.send(value) }
- @aggregation_cache[name] = part.freeze
+ if part.nil? && allow_nil
+ mapping.each { |key, _| self[key] = nil }
+ @aggregation_cache[name] = nil
+ else
+ mapping.each { |key, value| self[key] = part.send(value) }
+ @aggregation_cache[name] = part.freeze
+ end
end
end
- end
- end
+ end
end
end
diff --git a/activerecord/lib/active_record/association_relation.rb b/activerecord/lib/active_record/association_relation.rb
index c18e88e4cf..2da2d968b9 100644
--- a/activerecord/lib/active_record/association_relation.rb
+++ b/activerecord/lib/active_record/association_relation.rb
@@ -28,8 +28,8 @@ module ActiveRecord
private
- def exec_queries
- super.each { |r| @association.set_inverse_instance r }
- end
+ def exec_queries
+ super.each { |r| @association.set_inverse_instance r }
+ end
end
end
diff --git a/activerecord/lib/active_record/associations.rb b/activerecord/lib/active_record/associations.rb
index d1d71391e6..659e512ce2 100644
--- a/activerecord/lib/active_record/associations.rb
+++ b/activerecord/lib/active_record/associations.rb
@@ -1150,684 +1150,684 @@ module ActiveRecord
#
# All of the association macros can be specialized through options. This makes cases
# more complex than the simple and guessable ones possible.
- module ClassMethods
- # Specifies a one-to-many association. The following methods for retrieval and query of
- # collections of associated objects will be added:
- #
- # +collection+ is a placeholder for the symbol passed as the +name+ argument, so
- # <tt>has_many :clients</tt> would add among others <tt>clients.empty?</tt>.
- #
- # [collection(force_reload = false)]
- # Returns an array of all the associated objects.
- # An empty array is returned if none are found.
- # [collection<<(object, ...)]
- # Adds one or more objects to the collection by setting their foreign keys to the collection's primary key.
- # Note that this operation instantly fires update SQL without waiting for the save or update call on the
- # parent object, unless the parent object is a new record.
- # This will also run validations and callbacks of associated object(s).
- # [collection.delete(object, ...)]
- # Removes one or more objects from the collection by setting their foreign keys to +NULL+.
- # Objects will be in addition destroyed if they're associated with <tt>dependent: :destroy</tt>,
- # and deleted if they're associated with <tt>dependent: :delete_all</tt>.
- #
- # If the <tt>:through</tt> option is used, then the join records are deleted (rather than
- # nullified) by default, but you can specify <tt>dependent: :destroy</tt> or
- # <tt>dependent: :nullify</tt> to override this.
- # [collection.destroy(object, ...)]
- # Removes one or more objects from the collection by running <tt>destroy</tt> on
- # each record, regardless of any dependent option, ensuring callbacks are run.
- #
- # If the <tt>:through</tt> option is used, then the join records are destroyed
- # instead, not the objects themselves.
- # [collection=objects]
- # Replaces the collections content by deleting and adding objects as appropriate. If the <tt>:through</tt>
- # option is true callbacks in the join models are triggered except destroy callbacks, since deletion is
- # direct by default. You can specify <tt>dependent: :destroy</tt> or
- # <tt>dependent: :nullify</tt> to override this.
- # [collection_singular_ids]
- # Returns an array of the associated objects' ids
- # [collection_singular_ids=ids]
- # Replace the collection with the objects identified by the primary keys in +ids+. This
- # method loads the models and calls <tt>collection=</tt>. See above.
- # [collection.clear]
- # Removes every object from the collection. This destroys the associated objects if they
- # are associated with <tt>dependent: :destroy</tt>, deletes them directly from the
- # database if <tt>dependent: :delete_all</tt>, otherwise sets their foreign keys to +NULL+.
- # If the <tt>:through</tt> option is true no destroy callbacks are invoked on the join models.
- # Join models are directly deleted.
- # [collection.empty?]
- # Returns +true+ if there are no associated objects.
- # [collection.size]
- # Returns the number of associated objects.
- # [collection.find(...)]
- # Finds an associated object according to the same rules as ActiveRecord::FinderMethods#find.
- # [collection.exists?(...)]
- # Checks whether an associated object with the given conditions exists.
- # Uses the same rules as ActiveRecord::FinderMethods#exists?.
- # [collection.build(attributes = {}, ...)]
- # Returns one or more new objects of the collection type that have been instantiated
- # with +attributes+ and linked to this object through a foreign key, but have not yet
- # been saved.
- # [collection.create(attributes = {})]
- # Returns a new object of the collection type that has been instantiated
- # with +attributes+, linked to this object through a foreign key, and that has already
- # been saved (if it passed the validation). *Note*: This only works if the base model
- # already exists in the DB, not if it is a new (unsaved) record!
- # [collection.create!(attributes = {})]
- # Does the same as <tt>collection.create</tt>, but raises ActiveRecord::RecordInvalid
- # if the record is invalid.
- #
- # === Example
- #
- # A <tt>Firm</tt> class declares <tt>has_many :clients</tt>, which will add:
- # * <tt>Firm#clients</tt> (similar to <tt>Client.where(firm_id: id)</tt>)
- # * <tt>Firm#clients<<</tt>
- # * <tt>Firm#clients.delete</tt>
- # * <tt>Firm#clients.destroy</tt>
- # * <tt>Firm#clients=</tt>
- # * <tt>Firm#client_ids</tt>
- # * <tt>Firm#client_ids=</tt>
- # * <tt>Firm#clients.clear</tt>
- # * <tt>Firm#clients.empty?</tt> (similar to <tt>firm.clients.size == 0</tt>)
- # * <tt>Firm#clients.size</tt> (similar to <tt>Client.count "firm_id = #{id}"</tt>)
- # * <tt>Firm#clients.find</tt> (similar to <tt>Client.where(firm_id: id).find(id)</tt>)
- # * <tt>Firm#clients.exists?(name: 'ACME')</tt> (similar to <tt>Client.exists?(name: 'ACME', firm_id: firm.id)</tt>)
- # * <tt>Firm#clients.build</tt> (similar to <tt>Client.new("firm_id" => id)</tt>)
- # * <tt>Firm#clients.create</tt> (similar to <tt>c = Client.new("firm_id" => id); c.save; c</tt>)
- # * <tt>Firm#clients.create!</tt> (similar to <tt>c = Client.new("firm_id" => id); c.save!</tt>)
- # The declaration can also include an +options+ hash to specialize the behavior of the association.
- #
- # === Scopes
- #
- # You can pass a second argument +scope+ as a callable (i.e. proc or
- # lambda) to retrieve a specific set of records or customize the generated
- # query when you access the associated collection.
- #
- # Scope examples:
- # has_many :comments, -> { where(author_id: 1) }
- # has_many :employees, -> { joins(:address) }
- # has_many :posts, ->(post) { where("max_post_length > ?", post.length) }
- #
- # === Extensions
- #
- # The +extension+ argument allows you to pass a block into a has_many
- # association. This is useful for adding new finders, creators and other
- # factory-type methods to be used as part of the association.
- #
- # Extension examples:
- # has_many :employees do
- # def find_or_create_by_name(name)
- # first_name, last_name = name.split(" ", 2)
- # find_or_create_by(first_name: first_name, last_name: last_name)
- # end
- # end
- #
- # === Options
- # [:class_name]
- # Specify the class name of the association. Use it only if that name can't be inferred
- # from the association name. So <tt>has_many :products</tt> will by default be linked
- # to the +Product+ class, but if the real class name is +SpecialProduct+, you'll have to
- # specify it with this option.
- # [:foreign_key]
- # Specify the foreign key used for the association. By default this is guessed to be the name
- # of this class in lower-case and "_id" suffixed. So a Person class that makes a #has_many
- # association will use "person_id" as the default <tt>:foreign_key</tt>.
- # [:foreign_type]
- # Specify the column used to store the associated object's type, if this is a polymorphic
- # association. By default this is guessed to be the name of the polymorphic association
- # specified on "as" option with a "_type" suffix. So a class that defines a
- # <tt>has_many :tags, as: :taggable</tt> association will use "taggable_type" as the
- # default <tt>:foreign_type</tt>.
- # [:primary_key]
- # Specify the name of the column to use as the primary key for the association. By default this is +id+.
- # [:dependent]
- # Controls what happens to the associated objects when
- # their owner is destroyed. Note that these are implemented as
- # callbacks, and Rails executes callbacks in order. Therefore, other
- # similar callbacks may affect the <tt>:dependent</tt> behavior, and the
- # <tt>:dependent</tt> behavior may affect other callbacks.
- #
- # * <tt>:destroy</tt> causes all the associated objects to also be destroyed.
- # * <tt>:delete_all</tt> causes all the associated objects to be deleted directly from the database (so callbacks will not be executed).
- # * <tt>:nullify</tt> causes the foreign keys to be set to +NULL+. Callbacks are not executed.
- # * <tt>:restrict_with_exception</tt> causes an exception to be raised if there are any associated records.
- # * <tt>:restrict_with_error</tt> causes an error to be added to the owner if there are any associated objects.
- #
- # If using with the <tt>:through</tt> option, the association on the join model must be
- # a #belongs_to, and the records which get deleted are the join records, rather than
- # the associated records.
- # [:counter_cache]
- # This option can be used to configure a custom named <tt>:counter_cache.</tt> You only need this option,
- # when you customized the name of your <tt>:counter_cache</tt> on the #belongs_to association.
- # [:as]
- # Specifies a polymorphic interface (See #belongs_to).
- # [:through]
- # Specifies an association through which to perform the query. This can be any other type
- # of association, including other <tt>:through</tt> associations. Options for <tt>:class_name</tt>,
- # <tt>:primary_key</tt> and <tt>:foreign_key</tt> are ignored, as the association uses the
- # source reflection.
- #
- # If the association on the join model is a #belongs_to, the collection can be modified
- # and the records on the <tt>:through</tt> model will be automatically created and removed
- # as appropriate. Otherwise, the collection is read-only, so you should manipulate the
- # <tt>:through</tt> association directly.
- #
- # If you are going to modify the association (rather than just read from it), then it is
- # a good idea to set the <tt>:inverse_of</tt> option on the source association on the
- # join model. This allows associated records to be built which will automatically create
- # the appropriate join model records when they are saved. (See the 'Association Join Models'
- # section above.)
- # [:source]
- # Specifies the source association name used by #has_many <tt>:through</tt> queries.
- # Only use it if the name cannot be inferred from the association.
- # <tt>has_many :subscribers, through: :subscriptions</tt> will look for either <tt>:subscribers</tt> or
- # <tt>:subscriber</tt> on Subscription, unless a <tt>:source</tt> is given.
- # [:source_type]
- # Specifies type of the source association used by #has_many <tt>:through</tt> queries where the source
- # association is a polymorphic #belongs_to.
- # [:validate]
- # When set to +true+, validates new objects added to association when saving the parent object. +true+ by default.
- # If you want to ensure associated objects are revalidated on every update, use +validates_associated+.
- # [:autosave]
- # If true, always save the associated objects or destroy them if marked for destruction,
- # when saving the parent object. If false, never save or destroy the associated objects.
- # By default, only save associated objects that are new records. This option is implemented as a
- # +before_save+ callback. Because callbacks are run in the order they are defined, associated objects
- # may need to be explicitly saved in any user-defined +before_save+ callbacks.
- #
- # Note that NestedAttributes::ClassMethods#accepts_nested_attributes_for sets
- # <tt>:autosave</tt> to <tt>true</tt>.
- # [:inverse_of]
- # Specifies the name of the #belongs_to association on the associated object
- # that is the inverse of this #has_many association. Does not work in combination
- # with <tt>:through</tt> or <tt>:as</tt> options.
- # See ActiveRecord::Associations::ClassMethods's overview on Bi-directional associations for more detail.
- # [:extend]
- # Specifies a module or array of modules that will be extended into the association object returned.
- # Useful for defining methods on associations, especially when they should be shared between multiple
- # association objects.
- #
- # Option examples:
- # has_many :comments, -> { order("posted_on") }
- # has_many :comments, -> { includes(:author) }
- # has_many :people, -> { where(deleted: false).order("name") }, class_name: "Person"
- # has_many :tracks, -> { order("position") }, dependent: :destroy
- # has_many :comments, dependent: :nullify
- # has_many :tags, as: :taggable
- # has_many :reports, -> { readonly }
- # has_many :subscribers, through: :subscriptions, source: :user
- def has_many(name, scope = nil, options = {}, &extension)
- reflection = Builder::HasMany.build(self, name, scope, options, &extension)
- Reflection.add_reflection self, name, reflection
- end
-
- # Specifies a one-to-one association with another class. This method should only be used
- # if the other class contains the foreign key. If the current class contains the foreign key,
- # then you should use #belongs_to instead. See also ActiveRecord::Associations::ClassMethods's overview
- # on when to use #has_one and when to use #belongs_to.
- #
- # The following methods for retrieval and query of a single associated object will be added:
- #
- # +association+ is a placeholder for the symbol passed as the +name+ argument, so
- # <tt>has_one :manager</tt> would add among others <tt>manager.nil?</tt>.
- #
- # [association(force_reload = false)]
- # Returns the associated object. +nil+ is returned if none is found.
- # [association=(associate)]
- # Assigns the associate object, extracts the primary key, sets it as the foreign key,
- # and saves the associate object. To avoid database inconsistencies, permanently deletes an existing
- # associated object when assigning a new one, even if the new one isn't saved to database.
- # [build_association(attributes = {})]
- # Returns a new object of the associated type that has been instantiated
- # with +attributes+ and linked to this object through a foreign key, but has not
- # yet been saved.
- # [create_association(attributes = {})]
- # Returns a new object of the associated type that has been instantiated
- # with +attributes+, linked to this object through a foreign key, and that
- # has already been saved (if it passed the validation).
- # [create_association!(attributes = {})]
- # Does the same as <tt>create_association</tt>, but raises ActiveRecord::RecordInvalid
- # if the record is invalid.
- #
- # === Example
- #
- # An Account class declares <tt>has_one :beneficiary</tt>, which will add:
- # * <tt>Account#beneficiary</tt> (similar to <tt>Beneficiary.where(account_id: id).first</tt>)
- # * <tt>Account#beneficiary=(beneficiary)</tt> (similar to <tt>beneficiary.account_id = account.id; beneficiary.save</tt>)
- # * <tt>Account#build_beneficiary</tt> (similar to <tt>Beneficiary.new("account_id" => id)</tt>)
- # * <tt>Account#create_beneficiary</tt> (similar to <tt>b = Beneficiary.new("account_id" => id); b.save; b</tt>)
- # * <tt>Account#create_beneficiary!</tt> (similar to <tt>b = Beneficiary.new("account_id" => id); b.save!; b</tt>)
- #
- # === Scopes
- #
- # You can pass a second argument +scope+ as a callable (i.e. proc or
- # lambda) to retrieve a specific record or customize the generated query
- # when you access the associated object.
- #
- # Scope examples:
- # has_one :author, -> { where(comment_id: 1) }
- # has_one :employer, -> { joins(:company) }
- # has_one :dob, ->(dob) { where("Date.new(2000, 01, 01) > ?", dob) }
- #
- # === Options
- #
- # The declaration can also include an +options+ hash to specialize the behavior of the association.
- #
- # Options are:
- # [:class_name]
- # Specify the class name of the association. Use it only if that name can't be inferred
- # from the association name. So <tt>has_one :manager</tt> will by default be linked to the Manager class, but
- # if the real class name is Person, you'll have to specify it with this option.
- # [:dependent]
- # Controls what happens to the associated object when
- # its owner is destroyed:
- #
- # * <tt>:destroy</tt> causes the associated object to also be destroyed
- # * <tt>:delete</tt> causes the associated object to be deleted directly from the database (so callbacks will not execute)
- # * <tt>:nullify</tt> causes the foreign key to be set to +NULL+. Callbacks are not executed.
- # * <tt>:restrict_with_exception</tt> causes an exception to be raised if there is an associated record
- # * <tt>:restrict_with_error</tt> causes an error to be added to the owner if there is an associated object
- #
- # Note that <tt>:dependent</tt> option is ignored when using <tt>:through</tt> option.
- # [:foreign_key]
- # Specify the foreign key used for the association. By default this is guessed to be the name
- # of this class in lower-case and "_id" suffixed. So a Person class that makes a #has_one association
- # will use "person_id" as the default <tt>:foreign_key</tt>.
- # [:foreign_type]
- # Specify the column used to store the associated object's type, if this is a polymorphic
- # association. By default this is guessed to be the name of the polymorphic association
- # specified on "as" option with a "_type" suffix. So a class that defines a
- # <tt>has_one :tag, as: :taggable</tt> association will use "taggable_type" as the
- # default <tt>:foreign_type</tt>.
- # [:primary_key]
- # Specify the method that returns the primary key used for the association. By default this is +id+.
- # [:as]
- # Specifies a polymorphic interface (See #belongs_to).
- # [:through]
- # Specifies a Join Model through which to perform the query. Options for <tt>:class_name</tt>,
- # <tt>:primary_key</tt>, and <tt>:foreign_key</tt> are ignored, as the association uses the
- # source reflection. You can only use a <tt>:through</tt> query through a #has_one
- # or #belongs_to association on the join model.
- # [:source]
- # Specifies the source association name used by #has_one <tt>:through</tt> queries.
- # Only use it if the name cannot be inferred from the association.
- # <tt>has_one :favorite, through: :favorites</tt> will look for a
- # <tt>:favorite</tt> on Favorite, unless a <tt>:source</tt> is given.
- # [:source_type]
- # Specifies type of the source association used by #has_one <tt>:through</tt> queries where the source
- # association is a polymorphic #belongs_to.
- # [:validate]
- # When set to +true+, validates new objects added to association when saving the parent object. +false+ by default.
- # If you want to ensure associated objects are revalidated on every update, use +validates_associated+.
- # [:autosave]
- # If true, always save the associated object or destroy it if marked for destruction,
- # when saving the parent object. If false, never save or destroy the associated object.
- # By default, only save the associated object if it's a new record.
- #
- # Note that NestedAttributes::ClassMethods#accepts_nested_attributes_for sets
- # <tt>:autosave</tt> to <tt>true</tt>.
- # [:inverse_of]
- # Specifies the name of the #belongs_to association on the associated object
- # that is the inverse of this #has_one association. Does not work in combination
- # with <tt>:through</tt> or <tt>:as</tt> options.
- # See ActiveRecord::Associations::ClassMethods's overview on Bi-directional associations for more detail.
- # [:required]
- # When set to +true+, the association will also have its presence validated.
- # This will validate the association itself, not the id. You can use
- # +:inverse_of+ to avoid an extra query during validation.
- #
- # Option examples:
- # has_one :credit_card, dependent: :destroy # destroys the associated credit card
- # has_one :credit_card, dependent: :nullify # updates the associated records foreign
- # # key value to NULL rather than destroying it
- # has_one :last_comment, -> { order('posted_on') }, class_name: "Comment"
- # has_one :project_manager, -> { where(role: 'project_manager') }, class_name: "Person"
- # has_one :attachment, as: :attachable
- # has_one :boss, -> { readonly }
- # has_one :club, through: :membership
- # has_one :primary_address, -> { where(primary: true) }, through: :addressables, source: :addressable
- # has_one :credit_card, required: true
- def has_one(name, scope = nil, options = {})
- reflection = Builder::HasOne.build(self, name, scope, options)
- Reflection.add_reflection self, name, reflection
- end
+ module ClassMethods
+ # Specifies a one-to-many association. The following methods for retrieval and query of
+ # collections of associated objects will be added:
+ #
+ # +collection+ is a placeholder for the symbol passed as the +name+ argument, so
+ # <tt>has_many :clients</tt> would add among others <tt>clients.empty?</tt>.
+ #
+ # [collection(force_reload = false)]
+ # Returns an array of all the associated objects.
+ # An empty array is returned if none are found.
+ # [collection<<(object, ...)]
+ # Adds one or more objects to the collection by setting their foreign keys to the collection's primary key.
+ # Note that this operation instantly fires update SQL without waiting for the save or update call on the
+ # parent object, unless the parent object is a new record.
+ # This will also run validations and callbacks of associated object(s).
+ # [collection.delete(object, ...)]
+ # Removes one or more objects from the collection by setting their foreign keys to +NULL+.
+ # Objects will be in addition destroyed if they're associated with <tt>dependent: :destroy</tt>,
+ # and deleted if they're associated with <tt>dependent: :delete_all</tt>.
+ #
+ # If the <tt>:through</tt> option is used, then the join records are deleted (rather than
+ # nullified) by default, but you can specify <tt>dependent: :destroy</tt> or
+ # <tt>dependent: :nullify</tt> to override this.
+ # [collection.destroy(object, ...)]
+ # Removes one or more objects from the collection by running <tt>destroy</tt> on
+ # each record, regardless of any dependent option, ensuring callbacks are run.
+ #
+ # If the <tt>:through</tt> option is used, then the join records are destroyed
+ # instead, not the objects themselves.
+ # [collection=objects]
+ # Replaces the collections content by deleting and adding objects as appropriate. If the <tt>:through</tt>
+ # option is true callbacks in the join models are triggered except destroy callbacks, since deletion is
+ # direct by default. You can specify <tt>dependent: :destroy</tt> or
+ # <tt>dependent: :nullify</tt> to override this.
+ # [collection_singular_ids]
+ # Returns an array of the associated objects' ids
+ # [collection_singular_ids=ids]
+ # Replace the collection with the objects identified by the primary keys in +ids+. This
+ # method loads the models and calls <tt>collection=</tt>. See above.
+ # [collection.clear]
+ # Removes every object from the collection. This destroys the associated objects if they
+ # are associated with <tt>dependent: :destroy</tt>, deletes them directly from the
+ # database if <tt>dependent: :delete_all</tt>, otherwise sets their foreign keys to +NULL+.
+ # If the <tt>:through</tt> option is true no destroy callbacks are invoked on the join models.
+ # Join models are directly deleted.
+ # [collection.empty?]
+ # Returns +true+ if there are no associated objects.
+ # [collection.size]
+ # Returns the number of associated objects.
+ # [collection.find(...)]
+ # Finds an associated object according to the same rules as ActiveRecord::FinderMethods#find.
+ # [collection.exists?(...)]
+ # Checks whether an associated object with the given conditions exists.
+ # Uses the same rules as ActiveRecord::FinderMethods#exists?.
+ # [collection.build(attributes = {}, ...)]
+ # Returns one or more new objects of the collection type that have been instantiated
+ # with +attributes+ and linked to this object through a foreign key, but have not yet
+ # been saved.
+ # [collection.create(attributes = {})]
+ # Returns a new object of the collection type that has been instantiated
+ # with +attributes+, linked to this object through a foreign key, and that has already
+ # been saved (if it passed the validation). *Note*: This only works if the base model
+ # already exists in the DB, not if it is a new (unsaved) record!
+ # [collection.create!(attributes = {})]
+ # Does the same as <tt>collection.create</tt>, but raises ActiveRecord::RecordInvalid
+ # if the record is invalid.
+ #
+ # === Example
+ #
+ # A <tt>Firm</tt> class declares <tt>has_many :clients</tt>, which will add:
+ # * <tt>Firm#clients</tt> (similar to <tt>Client.where(firm_id: id)</tt>)
+ # * <tt>Firm#clients<<</tt>
+ # * <tt>Firm#clients.delete</tt>
+ # * <tt>Firm#clients.destroy</tt>
+ # * <tt>Firm#clients=</tt>
+ # * <tt>Firm#client_ids</tt>
+ # * <tt>Firm#client_ids=</tt>
+ # * <tt>Firm#clients.clear</tt>
+ # * <tt>Firm#clients.empty?</tt> (similar to <tt>firm.clients.size == 0</tt>)
+ # * <tt>Firm#clients.size</tt> (similar to <tt>Client.count "firm_id = #{id}"</tt>)
+ # * <tt>Firm#clients.find</tt> (similar to <tt>Client.where(firm_id: id).find(id)</tt>)
+ # * <tt>Firm#clients.exists?(name: 'ACME')</tt> (similar to <tt>Client.exists?(name: 'ACME', firm_id: firm.id)</tt>)
+ # * <tt>Firm#clients.build</tt> (similar to <tt>Client.new("firm_id" => id)</tt>)
+ # * <tt>Firm#clients.create</tt> (similar to <tt>c = Client.new("firm_id" => id); c.save; c</tt>)
+ # * <tt>Firm#clients.create!</tt> (similar to <tt>c = Client.new("firm_id" => id); c.save!</tt>)
+ # The declaration can also include an +options+ hash to specialize the behavior of the association.
+ #
+ # === Scopes
+ #
+ # You can pass a second argument +scope+ as a callable (i.e. proc or
+ # lambda) to retrieve a specific set of records or customize the generated
+ # query when you access the associated collection.
+ #
+ # Scope examples:
+ # has_many :comments, -> { where(author_id: 1) }
+ # has_many :employees, -> { joins(:address) }
+ # has_many :posts, ->(post) { where("max_post_length > ?", post.length) }
+ #
+ # === Extensions
+ #
+ # The +extension+ argument allows you to pass a block into a has_many
+ # association. This is useful for adding new finders, creators and other
+ # factory-type methods to be used as part of the association.
+ #
+ # Extension examples:
+ # has_many :employees do
+ # def find_or_create_by_name(name)
+ # first_name, last_name = name.split(" ", 2)
+ # find_or_create_by(first_name: first_name, last_name: last_name)
+ # end
+ # end
+ #
+ # === Options
+ # [:class_name]
+ # Specify the class name of the association. Use it only if that name can't be inferred
+ # from the association name. So <tt>has_many :products</tt> will by default be linked
+ # to the +Product+ class, but if the real class name is +SpecialProduct+, you'll have to
+ # specify it with this option.
+ # [:foreign_key]
+ # Specify the foreign key used for the association. By default this is guessed to be the name
+ # of this class in lower-case and "_id" suffixed. So a Person class that makes a #has_many
+ # association will use "person_id" as the default <tt>:foreign_key</tt>.
+ # [:foreign_type]
+ # Specify the column used to store the associated object's type, if this is a polymorphic
+ # association. By default this is guessed to be the name of the polymorphic association
+ # specified on "as" option with a "_type" suffix. So a class that defines a
+ # <tt>has_many :tags, as: :taggable</tt> association will use "taggable_type" as the
+ # default <tt>:foreign_type</tt>.
+ # [:primary_key]
+ # Specify the name of the column to use as the primary key for the association. By default this is +id+.
+ # [:dependent]
+ # Controls what happens to the associated objects when
+ # their owner is destroyed. Note that these are implemented as
+ # callbacks, and Rails executes callbacks in order. Therefore, other
+ # similar callbacks may affect the <tt>:dependent</tt> behavior, and the
+ # <tt>:dependent</tt> behavior may affect other callbacks.
+ #
+ # * <tt>:destroy</tt> causes all the associated objects to also be destroyed.
+ # * <tt>:delete_all</tt> causes all the associated objects to be deleted directly from the database (so callbacks will not be executed).
+ # * <tt>:nullify</tt> causes the foreign keys to be set to +NULL+. Callbacks are not executed.
+ # * <tt>:restrict_with_exception</tt> causes an exception to be raised if there are any associated records.
+ # * <tt>:restrict_with_error</tt> causes an error to be added to the owner if there are any associated objects.
+ #
+ # If using with the <tt>:through</tt> option, the association on the join model must be
+ # a #belongs_to, and the records which get deleted are the join records, rather than
+ # the associated records.
+ # [:counter_cache]
+ # This option can be used to configure a custom named <tt>:counter_cache.</tt> You only need this option,
+ # when you customized the name of your <tt>:counter_cache</tt> on the #belongs_to association.
+ # [:as]
+ # Specifies a polymorphic interface (See #belongs_to).
+ # [:through]
+ # Specifies an association through which to perform the query. This can be any other type
+ # of association, including other <tt>:through</tt> associations. Options for <tt>:class_name</tt>,
+ # <tt>:primary_key</tt> and <tt>:foreign_key</tt> are ignored, as the association uses the
+ # source reflection.
+ #
+ # If the association on the join model is a #belongs_to, the collection can be modified
+ # and the records on the <tt>:through</tt> model will be automatically created and removed
+ # as appropriate. Otherwise, the collection is read-only, so you should manipulate the
+ # <tt>:through</tt> association directly.
+ #
+ # If you are going to modify the association (rather than just read from it), then it is
+ # a good idea to set the <tt>:inverse_of</tt> option on the source association on the
+ # join model. This allows associated records to be built which will automatically create
+ # the appropriate join model records when they are saved. (See the 'Association Join Models'
+ # section above.)
+ # [:source]
+ # Specifies the source association name used by #has_many <tt>:through</tt> queries.
+ # Only use it if the name cannot be inferred from the association.
+ # <tt>has_many :subscribers, through: :subscriptions</tt> will look for either <tt>:subscribers</tt> or
+ # <tt>:subscriber</tt> on Subscription, unless a <tt>:source</tt> is given.
+ # [:source_type]
+ # Specifies type of the source association used by #has_many <tt>:through</tt> queries where the source
+ # association is a polymorphic #belongs_to.
+ # [:validate]
+ # When set to +true+, validates new objects added to association when saving the parent object. +true+ by default.
+ # If you want to ensure associated objects are revalidated on every update, use +validates_associated+.
+ # [:autosave]
+ # If true, always save the associated objects or destroy them if marked for destruction,
+ # when saving the parent object. If false, never save or destroy the associated objects.
+ # By default, only save associated objects that are new records. This option is implemented as a
+ # +before_save+ callback. Because callbacks are run in the order they are defined, associated objects
+ # may need to be explicitly saved in any user-defined +before_save+ callbacks.
+ #
+ # Note that NestedAttributes::ClassMethods#accepts_nested_attributes_for sets
+ # <tt>:autosave</tt> to <tt>true</tt>.
+ # [:inverse_of]
+ # Specifies the name of the #belongs_to association on the associated object
+ # that is the inverse of this #has_many association. Does not work in combination
+ # with <tt>:through</tt> or <tt>:as</tt> options.
+ # See ActiveRecord::Associations::ClassMethods's overview on Bi-directional associations for more detail.
+ # [:extend]
+ # Specifies a module or array of modules that will be extended into the association object returned.
+ # Useful for defining methods on associations, especially when they should be shared between multiple
+ # association objects.
+ #
+ # Option examples:
+ # has_many :comments, -> { order("posted_on") }
+ # has_many :comments, -> { includes(:author) }
+ # has_many :people, -> { where(deleted: false).order("name") }, class_name: "Person"
+ # has_many :tracks, -> { order("position") }, dependent: :destroy
+ # has_many :comments, dependent: :nullify
+ # has_many :tags, as: :taggable
+ # has_many :reports, -> { readonly }
+ # has_many :subscribers, through: :subscriptions, source: :user
+ def has_many(name, scope = nil, options = {}, &extension)
+ reflection = Builder::HasMany.build(self, name, scope, options, &extension)
+ Reflection.add_reflection self, name, reflection
+ end
- # Specifies a one-to-one association with another class. This method should only be used
- # if this class contains the foreign key. If the other class contains the foreign key,
- # then you should use #has_one instead. See also ActiveRecord::Associations::ClassMethods's overview
- # on when to use #has_one and when to use #belongs_to.
- #
- # Methods will be added for retrieval and query for a single associated object, for which
- # this object holds an id:
- #
- # +association+ is a placeholder for the symbol passed as the +name+ argument, so
- # <tt>belongs_to :author</tt> would add among others <tt>author.nil?</tt>.
- #
- # [association(force_reload = false)]
- # Returns the associated object. +nil+ is returned if none is found.
- # [association=(associate)]
- # Assigns the associate object, extracts the primary key, and sets it as the foreign key.
- # [build_association(attributes = {})]
- # Returns a new object of the associated type that has been instantiated
- # with +attributes+ and linked to this object through a foreign key, but has not yet been saved.
- # [create_association(attributes = {})]
- # Returns a new object of the associated type that has been instantiated
- # with +attributes+, linked to this object through a foreign key, and that
- # has already been saved (if it passed the validation).
- # [create_association!(attributes = {})]
- # Does the same as <tt>create_association</tt>, but raises ActiveRecord::RecordInvalid
- # if the record is invalid.
- #
- # === Example
- #
- # A Post class declares <tt>belongs_to :author</tt>, which will add:
- # * <tt>Post#author</tt> (similar to <tt>Author.find(author_id)</tt>)
- # * <tt>Post#author=(author)</tt> (similar to <tt>post.author_id = author.id</tt>)
- # * <tt>Post#build_author</tt> (similar to <tt>post.author = Author.new</tt>)
- # * <tt>Post#create_author</tt> (similar to <tt>post.author = Author.new; post.author.save; post.author</tt>)
- # * <tt>Post#create_author!</tt> (similar to <tt>post.author = Author.new; post.author.save!; post.author</tt>)
- # The declaration can also include an +options+ hash to specialize the behavior of the association.
- #
- # === Scopes
- #
- # You can pass a second argument +scope+ as a callable (i.e. proc or
- # lambda) to retrieve a specific record or customize the generated query
- # when you access the associated object.
- #
- # Scope examples:
- # belongs_to :firm, -> { where(id: 2) }
- # belongs_to :user, -> { joins(:friends) }
- # belongs_to :level, ->(level) { where("game_level > ?", level.current) }
- #
- # === Options
- #
- # [:class_name]
- # Specify the class name of the association. Use it only if that name can't be inferred
- # from the association name. So <tt>belongs_to :author</tt> will by default be linked to the Author class, but
- # if the real class name is Person, you'll have to specify it with this option.
- # [:foreign_key]
- # Specify the foreign key used for the association. By default this is guessed to be the name
- # of the association with an "_id" suffix. So a class that defines a <tt>belongs_to :person</tt>
- # association will use "person_id" as the default <tt>:foreign_key</tt>. Similarly,
- # <tt>belongs_to :favorite_person, class_name: "Person"</tt> will use a foreign key
- # of "favorite_person_id".
- # [:foreign_type]
- # Specify the column used to store the associated object's type, if this is a polymorphic
- # association. By default this is guessed to be the name of the association with a "_type"
- # suffix. So a class that defines a <tt>belongs_to :taggable, polymorphic: true</tt>
- # association will use "taggable_type" as the default <tt>:foreign_type</tt>.
- # [:primary_key]
- # Specify the method that returns the primary key of associated object used for the association.
- # By default this is id.
- # [:dependent]
- # If set to <tt>:destroy</tt>, the associated object is destroyed when this object is. If set to
- # <tt>:delete</tt>, the associated object is deleted *without* calling its destroy method.
- # This option should not be specified when #belongs_to is used in conjunction with
- # a #has_many relationship on another class because of the potential to leave
- # orphaned records behind.
- # [:counter_cache]
- # Caches the number of belonging objects on the associate class through the use of CounterCache::ClassMethods#increment_counter
- # and CounterCache::ClassMethods#decrement_counter. The counter cache is incremented when an object of this
- # class is created and decremented when it's destroyed. This requires that a column
- # named <tt>#{table_name}_count</tt> (such as +comments_count+ for a belonging Comment class)
- # is used on the associate class (such as a Post class) - that is the migration for
- # <tt>#{table_name}_count</tt> is created on the associate class (such that <tt>Post.comments_count</tt> will
- # return the count cached, see note below). You can also specify a custom counter
- # cache column by providing a column name instead of a +true+/+false+ value to this
- # option (e.g., <tt>counter_cache: :my_custom_counter</tt>.)
- # Note: Specifying a counter cache will add it to that model's list of readonly attributes
- # using +attr_readonly+.
- # [:polymorphic]
- # Specify this association is a polymorphic association by passing +true+.
- # Note: If you've enabled the counter cache, then you may want to add the counter cache attribute
- # to the +attr_readonly+ list in the associated classes (e.g. <tt>class Post; attr_readonly :comments_count; end</tt>).
- # [:validate]
- # When set to +true+, validates new objects added to association when saving the parent object. +false+ by default.
- # If you want to ensure associated objects are revalidated on every update, use +validates_associated+.
- # [:autosave]
- # If true, always save the associated object or destroy it if marked for destruction, when
- # saving the parent object.
- # If false, never save or destroy the associated object.
- # By default, only save the associated object if it's a new record.
- #
- # Note that NestedAttributes::ClassMethods#accepts_nested_attributes_for
- # sets <tt>:autosave</tt> to <tt>true</tt>.
- # [:touch]
- # If true, the associated object will be touched (the updated_at/on attributes set to current time)
- # when this record is either saved or destroyed. If you specify a symbol, that attribute
- # will be updated with the current time in addition to the updated_at/on attribute.
- # Please note that with touching no validation is performed and only the +after_touch+,
- # +after_commit+ and +after_rollback+ callbacks are executed.
- # [:inverse_of]
- # Specifies the name of the #has_one or #has_many association on the associated
- # object that is the inverse of this #belongs_to association. Does not work in
- # combination with the <tt>:polymorphic</tt> options.
- # See ActiveRecord::Associations::ClassMethods's overview on Bi-directional associations for more detail.
- # [:optional]
- # When set to +true+, the association will not have its presence validated.
- # [:required]
- # When set to +true+, the association will also have its presence validated.
- # This will validate the association itself, not the id. You can use
- # +:inverse_of+ to avoid an extra query during validation.
- # NOTE: <tt>required</tt> is set to <tt>true</tt> by default and is deprecated. If
- # you don't want to have association presence validated, use <tt>optional: true</tt>.
- #
- # Option examples:
- # belongs_to :firm, foreign_key: "client_of"
- # belongs_to :person, primary_key: "name", foreign_key: "person_name"
- # belongs_to :author, class_name: "Person", foreign_key: "author_id"
- # belongs_to :valid_coupon, ->(o) { where "discounts > ?", o.payments_count },
- # class_name: "Coupon", foreign_key: "coupon_id"
- # belongs_to :attachable, polymorphic: true
- # belongs_to :project, -> { readonly }
- # belongs_to :post, counter_cache: true
- # belongs_to :comment, touch: true
- # belongs_to :company, touch: :employees_last_updated_at
- # belongs_to :user, optional: true
- def belongs_to(name, scope = nil, options = {})
- reflection = Builder::BelongsTo.build(self, name, scope, options)
- Reflection.add_reflection self, name, reflection
- end
+ # Specifies a one-to-one association with another class. This method should only be used
+ # if the other class contains the foreign key. If the current class contains the foreign key,
+ # then you should use #belongs_to instead. See also ActiveRecord::Associations::ClassMethods's overview
+ # on when to use #has_one and when to use #belongs_to.
+ #
+ # The following methods for retrieval and query of a single associated object will be added:
+ #
+ # +association+ is a placeholder for the symbol passed as the +name+ argument, so
+ # <tt>has_one :manager</tt> would add among others <tt>manager.nil?</tt>.
+ #
+ # [association(force_reload = false)]
+ # Returns the associated object. +nil+ is returned if none is found.
+ # [association=(associate)]
+ # Assigns the associate object, extracts the primary key, sets it as the foreign key,
+ # and saves the associate object. To avoid database inconsistencies, permanently deletes an existing
+ # associated object when assigning a new one, even if the new one isn't saved to database.
+ # [build_association(attributes = {})]
+ # Returns a new object of the associated type that has been instantiated
+ # with +attributes+ and linked to this object through a foreign key, but has not
+ # yet been saved.
+ # [create_association(attributes = {})]
+ # Returns a new object of the associated type that has been instantiated
+ # with +attributes+, linked to this object through a foreign key, and that
+ # has already been saved (if it passed the validation).
+ # [create_association!(attributes = {})]
+ # Does the same as <tt>create_association</tt>, but raises ActiveRecord::RecordInvalid
+ # if the record is invalid.
+ #
+ # === Example
+ #
+ # An Account class declares <tt>has_one :beneficiary</tt>, which will add:
+ # * <tt>Account#beneficiary</tt> (similar to <tt>Beneficiary.where(account_id: id).first</tt>)
+ # * <tt>Account#beneficiary=(beneficiary)</tt> (similar to <tt>beneficiary.account_id = account.id; beneficiary.save</tt>)
+ # * <tt>Account#build_beneficiary</tt> (similar to <tt>Beneficiary.new("account_id" => id)</tt>)
+ # * <tt>Account#create_beneficiary</tt> (similar to <tt>b = Beneficiary.new("account_id" => id); b.save; b</tt>)
+ # * <tt>Account#create_beneficiary!</tt> (similar to <tt>b = Beneficiary.new("account_id" => id); b.save!; b</tt>)
+ #
+ # === Scopes
+ #
+ # You can pass a second argument +scope+ as a callable (i.e. proc or
+ # lambda) to retrieve a specific record or customize the generated query
+ # when you access the associated object.
+ #
+ # Scope examples:
+ # has_one :author, -> { where(comment_id: 1) }
+ # has_one :employer, -> { joins(:company) }
+ # has_one :dob, ->(dob) { where("Date.new(2000, 01, 01) > ?", dob) }
+ #
+ # === Options
+ #
+ # The declaration can also include an +options+ hash to specialize the behavior of the association.
+ #
+ # Options are:
+ # [:class_name]
+ # Specify the class name of the association. Use it only if that name can't be inferred
+ # from the association name. So <tt>has_one :manager</tt> will by default be linked to the Manager class, but
+ # if the real class name is Person, you'll have to specify it with this option.
+ # [:dependent]
+ # Controls what happens to the associated object when
+ # its owner is destroyed:
+ #
+ # * <tt>:destroy</tt> causes the associated object to also be destroyed
+ # * <tt>:delete</tt> causes the associated object to be deleted directly from the database (so callbacks will not execute)
+ # * <tt>:nullify</tt> causes the foreign key to be set to +NULL+. Callbacks are not executed.
+ # * <tt>:restrict_with_exception</tt> causes an exception to be raised if there is an associated record
+ # * <tt>:restrict_with_error</tt> causes an error to be added to the owner if there is an associated object
+ #
+ # Note that <tt>:dependent</tt> option is ignored when using <tt>:through</tt> option.
+ # [:foreign_key]
+ # Specify the foreign key used for the association. By default this is guessed to be the name
+ # of this class in lower-case and "_id" suffixed. So a Person class that makes a #has_one association
+ # will use "person_id" as the default <tt>:foreign_key</tt>.
+ # [:foreign_type]
+ # Specify the column used to store the associated object's type, if this is a polymorphic
+ # association. By default this is guessed to be the name of the polymorphic association
+ # specified on "as" option with a "_type" suffix. So a class that defines a
+ # <tt>has_one :tag, as: :taggable</tt> association will use "taggable_type" as the
+ # default <tt>:foreign_type</tt>.
+ # [:primary_key]
+ # Specify the method that returns the primary key used for the association. By default this is +id+.
+ # [:as]
+ # Specifies a polymorphic interface (See #belongs_to).
+ # [:through]
+ # Specifies a Join Model through which to perform the query. Options for <tt>:class_name</tt>,
+ # <tt>:primary_key</tt>, and <tt>:foreign_key</tt> are ignored, as the association uses the
+ # source reflection. You can only use a <tt>:through</tt> query through a #has_one
+ # or #belongs_to association on the join model.
+ # [:source]
+ # Specifies the source association name used by #has_one <tt>:through</tt> queries.
+ # Only use it if the name cannot be inferred from the association.
+ # <tt>has_one :favorite, through: :favorites</tt> will look for a
+ # <tt>:favorite</tt> on Favorite, unless a <tt>:source</tt> is given.
+ # [:source_type]
+ # Specifies type of the source association used by #has_one <tt>:through</tt> queries where the source
+ # association is a polymorphic #belongs_to.
+ # [:validate]
+ # When set to +true+, validates new objects added to association when saving the parent object. +false+ by default.
+ # If you want to ensure associated objects are revalidated on every update, use +validates_associated+.
+ # [:autosave]
+ # If true, always save the associated object or destroy it if marked for destruction,
+ # when saving the parent object. If false, never save or destroy the associated object.
+ # By default, only save the associated object if it's a new record.
+ #
+ # Note that NestedAttributes::ClassMethods#accepts_nested_attributes_for sets
+ # <tt>:autosave</tt> to <tt>true</tt>.
+ # [:inverse_of]
+ # Specifies the name of the #belongs_to association on the associated object
+ # that is the inverse of this #has_one association. Does not work in combination
+ # with <tt>:through</tt> or <tt>:as</tt> options.
+ # See ActiveRecord::Associations::ClassMethods's overview on Bi-directional associations for more detail.
+ # [:required]
+ # When set to +true+, the association will also have its presence validated.
+ # This will validate the association itself, not the id. You can use
+ # +:inverse_of+ to avoid an extra query during validation.
+ #
+ # Option examples:
+ # has_one :credit_card, dependent: :destroy # destroys the associated credit card
+ # has_one :credit_card, dependent: :nullify # updates the associated records foreign
+ # # key value to NULL rather than destroying it
+ # has_one :last_comment, -> { order('posted_on') }, class_name: "Comment"
+ # has_one :project_manager, -> { where(role: 'project_manager') }, class_name: "Person"
+ # has_one :attachment, as: :attachable
+ # has_one :boss, -> { readonly }
+ # has_one :club, through: :membership
+ # has_one :primary_address, -> { where(primary: true) }, through: :addressables, source: :addressable
+ # has_one :credit_card, required: true
+ def has_one(name, scope = nil, options = {})
+ reflection = Builder::HasOne.build(self, name, scope, options)
+ Reflection.add_reflection self, name, reflection
+ end
- # Specifies a many-to-many relationship with another class. This associates two classes via an
- # intermediate join table. Unless the join table is explicitly specified as an option, it is
- # guessed using the lexical order of the class names. So a join between Developer and Project
- # will give the default join table name of "developers_projects" because "D" precedes "P" alphabetically.
- # Note that this precedence is calculated using the <tt><</tt> operator for String. This
- # means that if the strings are of different lengths, and the strings are equal when compared
- # up to the shortest length, then the longer string is considered of higher
- # lexical precedence than the shorter one. For example, one would expect the tables "paper_boxes" and "papers"
- # to generate a join table name of "papers_paper_boxes" because of the length of the name "paper_boxes",
- # but it in fact generates a join table name of "paper_boxes_papers". Be aware of this caveat, and use the
- # custom <tt>:join_table</tt> option if you need to.
- # If your tables share a common prefix, it will only appear once at the beginning. For example,
- # the tables "catalog_categories" and "catalog_products" generate a join table name of "catalog_categories_products".
- #
- # The join table should not have a primary key or a model associated with it. You must manually generate the
- # join table with a migration such as this:
- #
- # class CreateDevelopersProjectsJoinTable < ActiveRecord::Migration[5.0]
- # def change
- # create_join_table :developers, :projects
- # end
- # end
- #
- # It's also a good idea to add indexes to each of those columns to speed up the joins process.
- # However, in MySQL it is advised to add a compound index for both of the columns as MySQL only
- # uses one index per table during the lookup.
- #
- # Adds the following methods for retrieval and query:
- #
- # +collection+ is a placeholder for the symbol passed as the +name+ argument, so
- # <tt>has_and_belongs_to_many :categories</tt> would add among others <tt>categories.empty?</tt>.
- #
- # [collection(force_reload = false)]
- # Returns an array of all the associated objects.
- # An empty array is returned if none are found.
- # [collection<<(object, ...)]
- # Adds one or more objects to the collection by creating associations in the join table
- # (<tt>collection.push</tt> and <tt>collection.concat</tt> are aliases to this method).
- # Note that this operation instantly fires update SQL without waiting for the save or update call on the
- # parent object, unless the parent object is a new record.
- # [collection.delete(object, ...)]
- # Removes one or more objects from the collection by removing their associations from the join table.
- # This does not destroy the objects.
- # [collection.destroy(object, ...)]
- # Removes one or more objects from the collection by running destroy on each association in the join table, overriding any dependent option.
- # This does not destroy the objects.
- # [collection=objects]
- # Replaces the collection's content by deleting and adding objects as appropriate.
- # [collection_singular_ids]
- # Returns an array of the associated objects' ids.
- # [collection_singular_ids=ids]
- # Replace the collection by the objects identified by the primary keys in +ids+.
- # [collection.clear]
- # Removes every object from the collection. This does not destroy the objects.
- # [collection.empty?]
- # Returns +true+ if there are no associated objects.
- # [collection.size]
- # Returns the number of associated objects.
- # [collection.find(id)]
- # Finds an associated object responding to the +id+ and that
- # meets the condition that it has to be associated with this object.
- # Uses the same rules as ActiveRecord::FinderMethods#find.
- # [collection.exists?(...)]
- # Checks whether an associated object with the given conditions exists.
- # Uses the same rules as ActiveRecord::FinderMethods#exists?.
- # [collection.build(attributes = {})]
- # Returns a new object of the collection type that has been instantiated
- # with +attributes+ and linked to this object through the join table, but has not yet been saved.
- # [collection.create(attributes = {})]
- # Returns a new object of the collection type that has been instantiated
- # with +attributes+, linked to this object through the join table, and that has already been
- # saved (if it passed the validation).
- #
- # === Example
- #
- # A Developer class declares <tt>has_and_belongs_to_many :projects</tt>, which will add:
- # * <tt>Developer#projects</tt>
- # * <tt>Developer#projects<<</tt>
- # * <tt>Developer#projects.delete</tt>
- # * <tt>Developer#projects.destroy</tt>
- # * <tt>Developer#projects=</tt>
- # * <tt>Developer#project_ids</tt>
- # * <tt>Developer#project_ids=</tt>
- # * <tt>Developer#projects.clear</tt>
- # * <tt>Developer#projects.empty?</tt>
- # * <tt>Developer#projects.size</tt>
- # * <tt>Developer#projects.find(id)</tt>
- # * <tt>Developer#projects.exists?(...)</tt>
- # * <tt>Developer#projects.build</tt> (similar to <tt>Project.new("developer_id" => id)</tt>)
- # * <tt>Developer#projects.create</tt> (similar to <tt>c = Project.new("developer_id" => id); c.save; c</tt>)
- # The declaration may include an +options+ hash to specialize the behavior of the association.
- #
- # === Scopes
- #
- # You can pass a second argument +scope+ as a callable (i.e. proc or
- # lambda) to retrieve a specific set of records or customize the generated
- # query when you access the associated collection.
- #
- # Scope examples:
- # has_and_belongs_to_many :projects, -> { includes(:milestones, :manager) }
- # has_and_belongs_to_many :categories, ->(category) {
- # where("default_category = ?", category.name)
- # }
- #
- # === Extensions
- #
- # The +extension+ argument allows you to pass a block into a
- # has_and_belongs_to_many association. This is useful for adding new
- # finders, creators and other factory-type methods to be used as part of
- # the association.
- #
- # Extension examples:
- # has_and_belongs_to_many :contractors do
- # def find_or_create_by_name(name)
- # first_name, last_name = name.split(" ", 2)
- # find_or_create_by(first_name: first_name, last_name: last_name)
- # end
- # end
- #
- # === Options
- #
- # [:class_name]
- # Specify the class name of the association. Use it only if that name can't be inferred
- # from the association name. So <tt>has_and_belongs_to_many :projects</tt> will by default be linked to the
- # Project class, but if the real class name is SuperProject, you'll have to specify it with this option.
- # [:join_table]
- # Specify the name of the join table if the default based on lexical order isn't what you want.
- # <b>WARNING:</b> If you're overwriting the table name of either class, the +table_name+ method
- # MUST be declared underneath any #has_and_belongs_to_many declaration in order to work.
- # [:foreign_key]
- # Specify the foreign key used for the association. By default this is guessed to be the name
- # of this class in lower-case and "_id" suffixed. So a Person class that makes
- # a #has_and_belongs_to_many association to Project will use "person_id" as the
- # default <tt>:foreign_key</tt>.
- # [:association_foreign_key]
- # Specify the foreign key used for the association on the receiving side of the association.
- # By default this is guessed to be the name of the associated class in lower-case and "_id" suffixed.
- # So if a Person class makes a #has_and_belongs_to_many association to Project,
- # the association will use "project_id" as the default <tt>:association_foreign_key</tt>.
- # [:validate]
- # When set to +true+, validates new objects added to association when saving the parent object. +true+ by default.
- # If you want to ensure associated objects are revalidated on every update, use +validates_associated+.
- # [:autosave]
- # If true, always save the associated objects or destroy them if marked for destruction, when
- # saving the parent object.
- # If false, never save or destroy the associated objects.
- # By default, only save associated objects that are new records.
- #
- # Note that NestedAttributes::ClassMethods#accepts_nested_attributes_for sets
- # <tt>:autosave</tt> to <tt>true</tt>.
- #
- # Option examples:
- # has_and_belongs_to_many :projects
- # has_and_belongs_to_many :projects, -> { includes(:milestones, :manager) }
- # has_and_belongs_to_many :nations, class_name: "Country"
- # has_and_belongs_to_many :categories, join_table: "prods_cats"
- # has_and_belongs_to_many :categories, -> { readonly }
- def has_and_belongs_to_many(name, scope = nil, options = {}, &extension)
- if scope.is_a?(Hash)
- options = scope
- scope = nil
+ # Specifies a one-to-one association with another class. This method should only be used
+ # if this class contains the foreign key. If the other class contains the foreign key,
+ # then you should use #has_one instead. See also ActiveRecord::Associations::ClassMethods's overview
+ # on when to use #has_one and when to use #belongs_to.
+ #
+ # Methods will be added for retrieval and query for a single associated object, for which
+ # this object holds an id:
+ #
+ # +association+ is a placeholder for the symbol passed as the +name+ argument, so
+ # <tt>belongs_to :author</tt> would add among others <tt>author.nil?</tt>.
+ #
+ # [association(force_reload = false)]
+ # Returns the associated object. +nil+ is returned if none is found.
+ # [association=(associate)]
+ # Assigns the associate object, extracts the primary key, and sets it as the foreign key.
+ # [build_association(attributes = {})]
+ # Returns a new object of the associated type that has been instantiated
+ # with +attributes+ and linked to this object through a foreign key, but has not yet been saved.
+ # [create_association(attributes = {})]
+ # Returns a new object of the associated type that has been instantiated
+ # with +attributes+, linked to this object through a foreign key, and that
+ # has already been saved (if it passed the validation).
+ # [create_association!(attributes = {})]
+ # Does the same as <tt>create_association</tt>, but raises ActiveRecord::RecordInvalid
+ # if the record is invalid.
+ #
+ # === Example
+ #
+ # A Post class declares <tt>belongs_to :author</tt>, which will add:
+ # * <tt>Post#author</tt> (similar to <tt>Author.find(author_id)</tt>)
+ # * <tt>Post#author=(author)</tt> (similar to <tt>post.author_id = author.id</tt>)
+ # * <tt>Post#build_author</tt> (similar to <tt>post.author = Author.new</tt>)
+ # * <tt>Post#create_author</tt> (similar to <tt>post.author = Author.new; post.author.save; post.author</tt>)
+ # * <tt>Post#create_author!</tt> (similar to <tt>post.author = Author.new; post.author.save!; post.author</tt>)
+ # The declaration can also include an +options+ hash to specialize the behavior of the association.
+ #
+ # === Scopes
+ #
+ # You can pass a second argument +scope+ as a callable (i.e. proc or
+ # lambda) to retrieve a specific record or customize the generated query
+ # when you access the associated object.
+ #
+ # Scope examples:
+ # belongs_to :firm, -> { where(id: 2) }
+ # belongs_to :user, -> { joins(:friends) }
+ # belongs_to :level, ->(level) { where("game_level > ?", level.current) }
+ #
+ # === Options
+ #
+ # [:class_name]
+ # Specify the class name of the association. Use it only if that name can't be inferred
+ # from the association name. So <tt>belongs_to :author</tt> will by default be linked to the Author class, but
+ # if the real class name is Person, you'll have to specify it with this option.
+ # [:foreign_key]
+ # Specify the foreign key used for the association. By default this is guessed to be the name
+ # of the association with an "_id" suffix. So a class that defines a <tt>belongs_to :person</tt>
+ # association will use "person_id" as the default <tt>:foreign_key</tt>. Similarly,
+ # <tt>belongs_to :favorite_person, class_name: "Person"</tt> will use a foreign key
+ # of "favorite_person_id".
+ # [:foreign_type]
+ # Specify the column used to store the associated object's type, if this is a polymorphic
+ # association. By default this is guessed to be the name of the association with a "_type"
+ # suffix. So a class that defines a <tt>belongs_to :taggable, polymorphic: true</tt>
+ # association will use "taggable_type" as the default <tt>:foreign_type</tt>.
+ # [:primary_key]
+ # Specify the method that returns the primary key of associated object used for the association.
+ # By default this is id.
+ # [:dependent]
+ # If set to <tt>:destroy</tt>, the associated object is destroyed when this object is. If set to
+ # <tt>:delete</tt>, the associated object is deleted *without* calling its destroy method.
+ # This option should not be specified when #belongs_to is used in conjunction with
+ # a #has_many relationship on another class because of the potential to leave
+ # orphaned records behind.
+ # [:counter_cache]
+ # Caches the number of belonging objects on the associate class through the use of CounterCache::ClassMethods#increment_counter
+ # and CounterCache::ClassMethods#decrement_counter. The counter cache is incremented when an object of this
+ # class is created and decremented when it's destroyed. This requires that a column
+ # named <tt>#{table_name}_count</tt> (such as +comments_count+ for a belonging Comment class)
+ # is used on the associate class (such as a Post class) - that is the migration for
+ # <tt>#{table_name}_count</tt> is created on the associate class (such that <tt>Post.comments_count</tt> will
+ # return the count cached, see note below). You can also specify a custom counter
+ # cache column by providing a column name instead of a +true+/+false+ value to this
+ # option (e.g., <tt>counter_cache: :my_custom_counter</tt>.)
+ # Note: Specifying a counter cache will add it to that model's list of readonly attributes
+ # using +attr_readonly+.
+ # [:polymorphic]
+ # Specify this association is a polymorphic association by passing +true+.
+ # Note: If you've enabled the counter cache, then you may want to add the counter cache attribute
+ # to the +attr_readonly+ list in the associated classes (e.g. <tt>class Post; attr_readonly :comments_count; end</tt>).
+ # [:validate]
+ # When set to +true+, validates new objects added to association when saving the parent object. +false+ by default.
+ # If you want to ensure associated objects are revalidated on every update, use +validates_associated+.
+ # [:autosave]
+ # If true, always save the associated object or destroy it if marked for destruction, when
+ # saving the parent object.
+ # If false, never save or destroy the associated object.
+ # By default, only save the associated object if it's a new record.
+ #
+ # Note that NestedAttributes::ClassMethods#accepts_nested_attributes_for
+ # sets <tt>:autosave</tt> to <tt>true</tt>.
+ # [:touch]
+ # If true, the associated object will be touched (the updated_at/on attributes set to current time)
+ # when this record is either saved or destroyed. If you specify a symbol, that attribute
+ # will be updated with the current time in addition to the updated_at/on attribute.
+ # Please note that with touching no validation is performed and only the +after_touch+,
+ # +after_commit+ and +after_rollback+ callbacks are executed.
+ # [:inverse_of]
+ # Specifies the name of the #has_one or #has_many association on the associated
+ # object that is the inverse of this #belongs_to association. Does not work in
+ # combination with the <tt>:polymorphic</tt> options.
+ # See ActiveRecord::Associations::ClassMethods's overview on Bi-directional associations for more detail.
+ # [:optional]
+ # When set to +true+, the association will not have its presence validated.
+ # [:required]
+ # When set to +true+, the association will also have its presence validated.
+ # This will validate the association itself, not the id. You can use
+ # +:inverse_of+ to avoid an extra query during validation.
+ # NOTE: <tt>required</tt> is set to <tt>true</tt> by default and is deprecated. If
+ # you don't want to have association presence validated, use <tt>optional: true</tt>.
+ #
+ # Option examples:
+ # belongs_to :firm, foreign_key: "client_of"
+ # belongs_to :person, primary_key: "name", foreign_key: "person_name"
+ # belongs_to :author, class_name: "Person", foreign_key: "author_id"
+ # belongs_to :valid_coupon, ->(o) { where "discounts > ?", o.payments_count },
+ # class_name: "Coupon", foreign_key: "coupon_id"
+ # belongs_to :attachable, polymorphic: true
+ # belongs_to :project, -> { readonly }
+ # belongs_to :post, counter_cache: true
+ # belongs_to :comment, touch: true
+ # belongs_to :company, touch: :employees_last_updated_at
+ # belongs_to :user, optional: true
+ def belongs_to(name, scope = nil, options = {})
+ reflection = Builder::BelongsTo.build(self, name, scope, options)
+ Reflection.add_reflection self, name, reflection
end
- habtm_reflection = ActiveRecord::Reflection::HasAndBelongsToManyReflection.new(name, scope, options, self)
+ # Specifies a many-to-many relationship with another class. This associates two classes via an
+ # intermediate join table. Unless the join table is explicitly specified as an option, it is
+ # guessed using the lexical order of the class names. So a join between Developer and Project
+ # will give the default join table name of "developers_projects" because "D" precedes "P" alphabetically.
+ # Note that this precedence is calculated using the <tt><</tt> operator for String. This
+ # means that if the strings are of different lengths, and the strings are equal when compared
+ # up to the shortest length, then the longer string is considered of higher
+ # lexical precedence than the shorter one. For example, one would expect the tables "paper_boxes" and "papers"
+ # to generate a join table name of "papers_paper_boxes" because of the length of the name "paper_boxes",
+ # but it in fact generates a join table name of "paper_boxes_papers". Be aware of this caveat, and use the
+ # custom <tt>:join_table</tt> option if you need to.
+ # If your tables share a common prefix, it will only appear once at the beginning. For example,
+ # the tables "catalog_categories" and "catalog_products" generate a join table name of "catalog_categories_products".
+ #
+ # The join table should not have a primary key or a model associated with it. You must manually generate the
+ # join table with a migration such as this:
+ #
+ # class CreateDevelopersProjectsJoinTable < ActiveRecord::Migration[5.0]
+ # def change
+ # create_join_table :developers, :projects
+ # end
+ # end
+ #
+ # It's also a good idea to add indexes to each of those columns to speed up the joins process.
+ # However, in MySQL it is advised to add a compound index for both of the columns as MySQL only
+ # uses one index per table during the lookup.
+ #
+ # Adds the following methods for retrieval and query:
+ #
+ # +collection+ is a placeholder for the symbol passed as the +name+ argument, so
+ # <tt>has_and_belongs_to_many :categories</tt> would add among others <tt>categories.empty?</tt>.
+ #
+ # [collection(force_reload = false)]
+ # Returns an array of all the associated objects.
+ # An empty array is returned if none are found.
+ # [collection<<(object, ...)]
+ # Adds one or more objects to the collection by creating associations in the join table
+ # (<tt>collection.push</tt> and <tt>collection.concat</tt> are aliases to this method).
+ # Note that this operation instantly fires update SQL without waiting for the save or update call on the
+ # parent object, unless the parent object is a new record.
+ # [collection.delete(object, ...)]
+ # Removes one or more objects from the collection by removing their associations from the join table.
+ # This does not destroy the objects.
+ # [collection.destroy(object, ...)]
+ # Removes one or more objects from the collection by running destroy on each association in the join table, overriding any dependent option.
+ # This does not destroy the objects.
+ # [collection=objects]
+ # Replaces the collection's content by deleting and adding objects as appropriate.
+ # [collection_singular_ids]
+ # Returns an array of the associated objects' ids.
+ # [collection_singular_ids=ids]
+ # Replace the collection by the objects identified by the primary keys in +ids+.
+ # [collection.clear]
+ # Removes every object from the collection. This does not destroy the objects.
+ # [collection.empty?]
+ # Returns +true+ if there are no associated objects.
+ # [collection.size]
+ # Returns the number of associated objects.
+ # [collection.find(id)]
+ # Finds an associated object responding to the +id+ and that
+ # meets the condition that it has to be associated with this object.
+ # Uses the same rules as ActiveRecord::FinderMethods#find.
+ # [collection.exists?(...)]
+ # Checks whether an associated object with the given conditions exists.
+ # Uses the same rules as ActiveRecord::FinderMethods#exists?.
+ # [collection.build(attributes = {})]
+ # Returns a new object of the collection type that has been instantiated
+ # with +attributes+ and linked to this object through the join table, but has not yet been saved.
+ # [collection.create(attributes = {})]
+ # Returns a new object of the collection type that has been instantiated
+ # with +attributes+, linked to this object through the join table, and that has already been
+ # saved (if it passed the validation).
+ #
+ # === Example
+ #
+ # A Developer class declares <tt>has_and_belongs_to_many :projects</tt>, which will add:
+ # * <tt>Developer#projects</tt>
+ # * <tt>Developer#projects<<</tt>
+ # * <tt>Developer#projects.delete</tt>
+ # * <tt>Developer#projects.destroy</tt>
+ # * <tt>Developer#projects=</tt>
+ # * <tt>Developer#project_ids</tt>
+ # * <tt>Developer#project_ids=</tt>
+ # * <tt>Developer#projects.clear</tt>
+ # * <tt>Developer#projects.empty?</tt>
+ # * <tt>Developer#projects.size</tt>
+ # * <tt>Developer#projects.find(id)</tt>
+ # * <tt>Developer#projects.exists?(...)</tt>
+ # * <tt>Developer#projects.build</tt> (similar to <tt>Project.new("developer_id" => id)</tt>)
+ # * <tt>Developer#projects.create</tt> (similar to <tt>c = Project.new("developer_id" => id); c.save; c</tt>)
+ # The declaration may include an +options+ hash to specialize the behavior of the association.
+ #
+ # === Scopes
+ #
+ # You can pass a second argument +scope+ as a callable (i.e. proc or
+ # lambda) to retrieve a specific set of records or customize the generated
+ # query when you access the associated collection.
+ #
+ # Scope examples:
+ # has_and_belongs_to_many :projects, -> { includes(:milestones, :manager) }
+ # has_and_belongs_to_many :categories, ->(category) {
+ # where("default_category = ?", category.name)
+ # }
+ #
+ # === Extensions
+ #
+ # The +extension+ argument allows you to pass a block into a
+ # has_and_belongs_to_many association. This is useful for adding new
+ # finders, creators and other factory-type methods to be used as part of
+ # the association.
+ #
+ # Extension examples:
+ # has_and_belongs_to_many :contractors do
+ # def find_or_create_by_name(name)
+ # first_name, last_name = name.split(" ", 2)
+ # find_or_create_by(first_name: first_name, last_name: last_name)
+ # end
+ # end
+ #
+ # === Options
+ #
+ # [:class_name]
+ # Specify the class name of the association. Use it only if that name can't be inferred
+ # from the association name. So <tt>has_and_belongs_to_many :projects</tt> will by default be linked to the
+ # Project class, but if the real class name is SuperProject, you'll have to specify it with this option.
+ # [:join_table]
+ # Specify the name of the join table if the default based on lexical order isn't what you want.
+ # <b>WARNING:</b> If you're overwriting the table name of either class, the +table_name+ method
+ # MUST be declared underneath any #has_and_belongs_to_many declaration in order to work.
+ # [:foreign_key]
+ # Specify the foreign key used for the association. By default this is guessed to be the name
+ # of this class in lower-case and "_id" suffixed. So a Person class that makes
+ # a #has_and_belongs_to_many association to Project will use "person_id" as the
+ # default <tt>:foreign_key</tt>.
+ # [:association_foreign_key]
+ # Specify the foreign key used for the association on the receiving side of the association.
+ # By default this is guessed to be the name of the associated class in lower-case and "_id" suffixed.
+ # So if a Person class makes a #has_and_belongs_to_many association to Project,
+ # the association will use "project_id" as the default <tt>:association_foreign_key</tt>.
+ # [:validate]
+ # When set to +true+, validates new objects added to association when saving the parent object. +true+ by default.
+ # If you want to ensure associated objects are revalidated on every update, use +validates_associated+.
+ # [:autosave]
+ # If true, always save the associated objects or destroy them if marked for destruction, when
+ # saving the parent object.
+ # If false, never save or destroy the associated objects.
+ # By default, only save associated objects that are new records.
+ #
+ # Note that NestedAttributes::ClassMethods#accepts_nested_attributes_for sets
+ # <tt>:autosave</tt> to <tt>true</tt>.
+ #
+ # Option examples:
+ # has_and_belongs_to_many :projects
+ # has_and_belongs_to_many :projects, -> { includes(:milestones, :manager) }
+ # has_and_belongs_to_many :nations, class_name: "Country"
+ # has_and_belongs_to_many :categories, join_table: "prods_cats"
+ # has_and_belongs_to_many :categories, -> { readonly }
+ def has_and_belongs_to_many(name, scope = nil, options = {}, &extension)
+ if scope.is_a?(Hash)
+ options = scope
+ scope = nil
+ end
+
+ habtm_reflection = ActiveRecord::Reflection::HasAndBelongsToManyReflection.new(name, scope, options, self)
- builder = Builder::HasAndBelongsToMany.new name, self, options
+ builder = Builder::HasAndBelongsToMany.new name, self, options
- join_model = builder.through_model
+ join_model = builder.through_model
- const_set join_model.name, join_model
- private_constant join_model.name
+ const_set join_model.name, join_model
+ private_constant join_model.name
- middle_reflection = builder.middle_reflection join_model
+ middle_reflection = builder.middle_reflection join_model
- Builder::HasMany.define_callbacks self, middle_reflection
- Reflection.add_reflection self, middle_reflection.name, middle_reflection
- middle_reflection.parent_reflection = habtm_reflection
+ Builder::HasMany.define_callbacks self, middle_reflection
+ Reflection.add_reflection self, middle_reflection.name, middle_reflection
+ middle_reflection.parent_reflection = habtm_reflection
- include Module.new {
- class_eval <<-RUBY, __FILE__, __LINE__ + 1
+ include Module.new {
+ class_eval <<-RUBY, __FILE__, __LINE__ + 1
def destroy_associations
association(:#{middle_reflection.name}).delete_all(:delete_all)
association(:#{name}).reset
super
end
RUBY
- }
+ }
- hm_options = {}
- hm_options[:through] = middle_reflection.name
- hm_options[:source] = join_model.right_reflection.name
+ hm_options = {}
+ hm_options[:through] = middle_reflection.name
+ hm_options[:source] = join_model.right_reflection.name
- [:before_add, :after_add, :before_remove, :after_remove, :autosave, :validate, :join_table, :class_name, :extend].each do |k|
- hm_options[k] = options[k] if options.key? k
- end
+ [:before_add, :after_add, :before_remove, :after_remove, :autosave, :validate, :join_table, :class_name, :extend].each do |k|
+ hm_options[k] = options[k] if options.key? k
+ end
- has_many name, scope, hm_options, &extension
- self._reflections[name.to_s].parent_reflection = habtm_reflection
+ has_many name, scope, hm_options, &extension
+ self._reflections[name.to_s].parent_reflection = habtm_reflection
+ end
end
- end
end
end
diff --git a/activerecord/lib/active_record/associations/association_scope.rb b/activerecord/lib/active_record/associations/association_scope.rb
index 15844de0bc..12f8c1ccd4 100644
--- a/activerecord/lib/active_record/associations/association_scope.rb
+++ b/activerecord/lib/active_record/associations/association_scope.rb
@@ -51,115 +51,115 @@ module ActiveRecord
protected
- attr_reader :value_transformation
+ attr_reader :value_transformation
private
- def join(table, constraint)
- table.create_join(table, table.create_on(constraint), join_type)
- end
+ def join(table, constraint)
+ table.create_join(table, table.create_on(constraint), join_type)
+ end
+
+ def last_chain_scope(scope, table, reflection, owner, association_klass)
+ join_keys = reflection.join_keys(association_klass)
+ key = join_keys.key
+ foreign_key = join_keys.foreign_key
- def last_chain_scope(scope, table, reflection, owner, association_klass)
- join_keys = reflection.join_keys(association_klass)
- key = join_keys.key
- foreign_key = join_keys.foreign_key
+ value = transform_value(owner[foreign_key])
+ scope = scope.where(table.name => { key => value })
- value = transform_value(owner[foreign_key])
- scope = scope.where(table.name => { key => value })
+ if reflection.type
+ polymorphic_type = transform_value(owner.class.base_class.name)
+ scope = scope.where(table.name => { reflection.type => polymorphic_type })
+ end
- if reflection.type
- polymorphic_type = transform_value(owner.class.base_class.name)
- scope = scope.where(table.name => { reflection.type => polymorphic_type })
+ scope
end
- scope
- end
+ def transform_value(value)
+ value_transformation.call(value)
+ end
- def transform_value(value)
- value_transformation.call(value)
- end
+ def next_chain_scope(scope, table, reflection, association_klass, foreign_table, next_reflection)
+ join_keys = reflection.join_keys(association_klass)
+ key = join_keys.key
+ foreign_key = join_keys.foreign_key
- def next_chain_scope(scope, table, reflection, association_klass, foreign_table, next_reflection)
- join_keys = reflection.join_keys(association_klass)
- key = join_keys.key
- foreign_key = join_keys.foreign_key
+ constraint = table[key].eq(foreign_table[foreign_key])
- constraint = table[key].eq(foreign_table[foreign_key])
+ if reflection.type
+ value = transform_value(next_reflection.klass.base_class.name)
+ scope = scope.where(table.name => { reflection.type => value })
+ end
- if reflection.type
- value = transform_value(next_reflection.klass.base_class.name)
- scope = scope.where(table.name => { reflection.type => value })
+ scope = scope.joins(join(foreign_table, constraint))
end
- scope = scope.joins(join(foreign_table, constraint))
- end
+ class ReflectionProxy < SimpleDelegator # :nodoc:
+ attr_accessor :next
+ attr_reader :alias_name
- class ReflectionProxy < SimpleDelegator # :nodoc:
- attr_accessor :next
- attr_reader :alias_name
+ def initialize(reflection, alias_name)
+ super(reflection)
+ @alias_name = alias_name
+ end
- def initialize(reflection, alias_name)
- super(reflection)
- @alias_name = alias_name
+ def all_includes; nil; end
end
- def all_includes; nil; end
- end
-
- def get_chain(reflection, association, tracker)
- name = reflection.name
- runtime_reflection = Reflection::RuntimeReflection.new(reflection, association)
- previous_reflection = runtime_reflection
- reflection.chain.drop(1).each do |refl|
- alias_name = tracker.aliased_table_for(refl.table_name, refl.alias_candidate(name))
- proxy = ReflectionProxy.new(refl, alias_name)
- previous_reflection.next = proxy
- previous_reflection = proxy
+ def get_chain(reflection, association, tracker)
+ name = reflection.name
+ runtime_reflection = Reflection::RuntimeReflection.new(reflection, association)
+ previous_reflection = runtime_reflection
+ reflection.chain.drop(1).each do |refl|
+ alias_name = tracker.aliased_table_for(refl.table_name, refl.alias_candidate(name))
+ proxy = ReflectionProxy.new(refl, alias_name)
+ previous_reflection.next = proxy
+ previous_reflection = proxy
+ end
+ [runtime_reflection, previous_reflection]
end
- [runtime_reflection, previous_reflection]
- end
- def add_constraints(scope, owner, association_klass, refl, chain_head, chain_tail)
- owner_reflection = chain_tail
- table = owner_reflection.alias_name
- scope = last_chain_scope(scope, table, owner_reflection, owner, association_klass)
+ def add_constraints(scope, owner, association_klass, refl, chain_head, chain_tail)
+ owner_reflection = chain_tail
+ table = owner_reflection.alias_name
+ scope = last_chain_scope(scope, table, owner_reflection, owner, association_klass)
- reflection = chain_head
- while reflection
- table = reflection.alias_name
+ reflection = chain_head
+ while reflection
+ table = reflection.alias_name
- unless reflection == chain_tail
- next_reflection = reflection.next
- foreign_table = next_reflection.alias_name
- scope = next_chain_scope(scope, table, reflection, association_klass, foreign_table, next_reflection)
- end
+ unless reflection == chain_tail
+ next_reflection = reflection.next
+ foreign_table = next_reflection.alias_name
+ scope = next_chain_scope(scope, table, reflection, association_klass, foreign_table, next_reflection)
+ end
- # Exclude the scope of the association itself, because that
- # was already merged in the #scope method.
- reflection.constraints.each do |scope_chain_item|
- item = eval_scope(reflection.klass, scope_chain_item, owner)
+ # Exclude the scope of the association itself, because that
+ # was already merged in the #scope method.
+ reflection.constraints.each do |scope_chain_item|
+ item = eval_scope(reflection.klass, scope_chain_item, owner)
- if scope_chain_item == refl.scope
- scope.merge! item.except(:where, :includes)
- end
+ if scope_chain_item == refl.scope
+ scope.merge! item.except(:where, :includes)
+ end
+
+ reflection.all_includes do
+ scope.includes! item.includes_values
+ end
- reflection.all_includes do
- scope.includes! item.includes_values
+ scope.unscope!(*item.unscope_values)
+ scope.where_clause += item.where_clause
+ scope.order_values |= item.order_values
end
- scope.unscope!(*item.unscope_values)
- scope.where_clause += item.where_clause
- scope.order_values |= item.order_values
+ reflection = reflection.next
end
- reflection = reflection.next
+ scope
end
- scope
- end
-
- def eval_scope(klass, scope, owner)
- klass.unscoped.instance_exec(owner, &scope)
- end
+ def eval_scope(klass, scope, owner)
+ klass.unscoped.instance_exec(owner, &scope)
+ end
end
end
end
diff --git a/activerecord/lib/active_record/associations/builder/has_and_belongs_to_many.rb b/activerecord/lib/active_record/associations/builder/has_and_belongs_to_many.rb
index 33c8d4b8d6..047292b2bd 100644
--- a/activerecord/lib/active_record/associations/builder/has_and_belongs_to_many.rb
+++ b/activerecord/lib/active_record/associations/builder/has_and_belongs_to_many.rb
@@ -16,9 +16,9 @@ module ActiveRecord::Associations::Builder # :nodoc:
private
- def klass
- @lhs_class.send(:compute_type, @rhs_class_name)
- end
+ def klass
+ @lhs_class.send(:compute_type, @rhs_class_name)
+ end
end
def self.build(lhs_class, name, options)
@@ -105,29 +105,29 @@ module ActiveRecord::Associations::Builder # :nodoc:
private
- def middle_options(join_model)
- middle_options = {}
- middle_options[:class_name] = "#{lhs_model.name}::#{join_model.name}"
- middle_options[:source] = join_model.left_reflection.name
- if options.key? :foreign_key
- middle_options[:foreign_key] = options[:foreign_key]
+ def middle_options(join_model)
+ middle_options = {}
+ middle_options[:class_name] = "#{lhs_model.name}::#{join_model.name}"
+ middle_options[:source] = join_model.left_reflection.name
+ if options.key? :foreign_key
+ middle_options[:foreign_key] = options[:foreign_key]
+ end
+ middle_options
end
- middle_options
- end
- def belongs_to_options(options)
- rhs_options = {}
+ def belongs_to_options(options)
+ rhs_options = {}
- if options.key? :class_name
- rhs_options[:foreign_key] = options[:class_name].to_s.foreign_key
- rhs_options[:class_name] = options[:class_name]
- end
+ if options.key? :class_name
+ rhs_options[:foreign_key] = options[:class_name].to_s.foreign_key
+ rhs_options[:class_name] = options[:class_name]
+ end
- if options.key? :association_foreign_key
- rhs_options[:foreign_key] = options[:association_foreign_key]
- end
+ if options.key? :association_foreign_key
+ rhs_options[:foreign_key] = options[:association_foreign_key]
+ end
- rhs_options
- end
+ rhs_options
+ end
end
end
diff --git a/activerecord/lib/active_record/associations/collection_association.rb b/activerecord/lib/active_record/associations/collection_association.rb
index c8805d107b..7d106015d7 100644
--- a/activerecord/lib/active_record/associations/collection_association.rb
+++ b/activerecord/lib/active_record/associations/collection_association.rb
@@ -221,7 +221,7 @@ module ActiveRecord
end
dependent = if dependent
- dependent
+ dependent
elsif options[:dependent] == :destroy
:delete_all
else
diff --git a/activerecord/lib/active_record/associations/join_dependency.rb b/activerecord/lib/active_record/associations/join_dependency.rb
index 0f9ad77405..3946d5baa4 100644
--- a/activerecord/lib/active_record/associations/join_dependency.rb
+++ b/activerecord/lib/active_record/associations/join_dependency.rb
@@ -167,134 +167,134 @@ module ActiveRecord
private
- def make_constraints(parent, child, tables, join_type)
- chain = child.reflection.chain
- foreign_table = parent.table
- foreign_klass = parent.base_klass
- child.join_constraints(foreign_table, foreign_klass, child, join_type, tables, child.reflection.scope_chain, chain)
- end
-
- def make_outer_joins(parent, child)
- tables = table_aliases_for(parent, child)
- join_type = Arel::Nodes::OuterJoin
- info = make_constraints parent, child, tables, join_type
-
- [info] + child.children.flat_map { |c| make_outer_joins(child, c) }
- end
+ def make_constraints(parent, child, tables, join_type)
+ chain = child.reflection.chain
+ foreign_table = parent.table
+ foreign_klass = parent.base_klass
+ child.join_constraints(foreign_table, foreign_klass, child, join_type, tables, child.reflection.scope_chain, chain)
+ end
- def make_left_outer_joins(parent, child)
- tables = child.tables
- join_type = Arel::Nodes::OuterJoin
- info = make_constraints parent, child, tables, join_type
+ def make_outer_joins(parent, child)
+ tables = table_aliases_for(parent, child)
+ join_type = Arel::Nodes::OuterJoin
+ info = make_constraints parent, child, tables, join_type
- [info] + child.children.flat_map { |c| make_left_outer_joins(child, c) }
- end
+ [info] + child.children.flat_map { |c| make_outer_joins(child, c) }
+ end
- def make_inner_joins(parent, child)
- tables = child.tables
- join_type = Arel::Nodes::InnerJoin
- info = make_constraints parent, child, tables, join_type
+ def make_left_outer_joins(parent, child)
+ tables = child.tables
+ join_type = Arel::Nodes::OuterJoin
+ info = make_constraints parent, child, tables, join_type
- [info] + child.children.flat_map { |c| make_inner_joins(child, c) }
- end
+ [info] + child.children.flat_map { |c| make_left_outer_joins(child, c) }
+ end
- def table_aliases_for(parent, node)
- node.reflection.chain.map { |reflection|
- alias_tracker.aliased_table_for(
- reflection.table_name,
- table_alias_for(reflection, parent, reflection != node.reflection)
- )
- }
- end
+ def make_inner_joins(parent, child)
+ tables = child.tables
+ join_type = Arel::Nodes::InnerJoin
+ info = make_constraints parent, child, tables, join_type
- def construct_tables!(parent, node)
- node.tables = table_aliases_for(parent, node)
- node.children.each { |child| construct_tables! node, child }
- end
+ [info] + child.children.flat_map { |c| make_inner_joins(child, c) }
+ end
- def table_alias_for(reflection, parent, join)
- name = "#{reflection.plural_name}_#{parent.table_name}"
- name << "_join" if join
- name
- end
+ def table_aliases_for(parent, node)
+ node.reflection.chain.map { |reflection|
+ alias_tracker.aliased_table_for(
+ reflection.table_name,
+ table_alias_for(reflection, parent, reflection != node.reflection)
+ )
+ }
+ end
- def walk(left, right)
- intersection, missing = right.children.map { |node1|
- [left.children.find { |node2| node1.match? node2 }, node1]
- }.partition(&:first)
+ def construct_tables!(parent, node)
+ node.tables = table_aliases_for(parent, node)
+ node.children.each { |child| construct_tables! node, child }
+ end
- ojs = missing.flat_map { |_,n| make_outer_joins left, n }
- intersection.flat_map { |l,r| walk l, r }.concat ojs
- end
+ def table_alias_for(reflection, parent, join)
+ name = "#{reflection.plural_name}_#{parent.table_name}"
+ name << "_join" if join
+ name
+ end
- def find_reflection(klass, name)
- klass._reflect_on_association(name) or
- raise ConfigurationError, "Can't join '#{ klass.name }' to association named '#{ name }'; perhaps you misspelled it?"
- end
+ def walk(left, right)
+ intersection, missing = right.children.map { |node1|
+ [left.children.find { |node2| node1.match? node2 }, node1]
+ }.partition(&:first)
- def build(associations, base_klass)
- associations.map do |name, right|
- reflection = find_reflection base_klass, name
- reflection.check_validity!
- reflection.check_eager_loadable!
+ ojs = missing.flat_map { |_,n| make_outer_joins left, n }
+ intersection.flat_map { |l,r| walk l, r }.concat ojs
+ end
- if reflection.polymorphic?
- next unless @eager_loading
- raise EagerLoadPolymorphicError.new(reflection)
- end
+ def find_reflection(klass, name)
+ klass._reflect_on_association(name) or
+ raise ConfigurationError, "Can't join '#{ klass.name }' to association named '#{ name }'; perhaps you misspelled it?"
+ end
- JoinAssociation.new reflection, build(right, reflection.klass)
- end.compact
- end
+ def build(associations, base_klass)
+ associations.map do |name, right|
+ reflection = find_reflection base_klass, name
+ reflection.check_validity!
+ reflection.check_eager_loadable!
- def construct(ar_parent, parent, row, rs, seen, model_cache, aliases)
- return if ar_parent.nil?
+ if reflection.polymorphic?
+ next unless @eager_loading
+ raise EagerLoadPolymorphicError.new(reflection)
+ end
- parent.children.each do |node|
- if node.reflection.collection?
- other = ar_parent.association(node.reflection.name)
- other.loaded!
- elsif ar_parent.association_cached?(node.reflection.name)
- model = ar_parent.association(node.reflection.name).target
- construct(model, node, row, rs, seen, model_cache, aliases)
- next
- end
+ JoinAssociation.new reflection, build(right, reflection.klass)
+ end.compact
+ end
- key = aliases.column_alias(node, node.primary_key)
- id = row[key]
- if id.nil?
- nil_association = ar_parent.association(node.reflection.name)
- nil_association.loaded!
- next
+ def construct(ar_parent, parent, row, rs, seen, model_cache, aliases)
+ return if ar_parent.nil?
+
+ parent.children.each do |node|
+ if node.reflection.collection?
+ other = ar_parent.association(node.reflection.name)
+ other.loaded!
+ elsif ar_parent.association_cached?(node.reflection.name)
+ model = ar_parent.association(node.reflection.name).target
+ construct(model, node, row, rs, seen, model_cache, aliases)
+ next
+ end
+
+ key = aliases.column_alias(node, node.primary_key)
+ id = row[key]
+ if id.nil?
+ nil_association = ar_parent.association(node.reflection.name)
+ nil_association.loaded!
+ next
+ end
+
+ model = seen[ar_parent.object_id][node.base_klass][id]
+
+ if model
+ construct(model, node, row, rs, seen, model_cache, aliases)
+ else
+ model = construct_model(ar_parent, node, row, model_cache, id, aliases)
+ model.readonly!
+ seen[ar_parent.object_id][node.base_klass][id] = model
+ construct(model, node, row, rs, seen, model_cache, aliases)
+ end
end
+ end
- model = seen[ar_parent.object_id][node.base_klass][id]
+ def construct_model(record, node, row, model_cache, id, aliases)
+ model = model_cache[node][id] ||= node.instantiate(row,
+ aliases.column_aliases(node))
+ other = record.association(node.reflection.name)
- if model
- construct(model, node, row, rs, seen, model_cache, aliases)
+ if node.reflection.collection?
+ other.target.push(model)
else
- model = construct_model(ar_parent, node, row, model_cache, id, aliases)
- model.readonly!
- seen[ar_parent.object_id][node.base_klass][id] = model
- construct(model, node, row, rs, seen, model_cache, aliases)
+ other.target = model
end
- end
- end
- def construct_model(record, node, row, model_cache, id, aliases)
- model = model_cache[node][id] ||= node.instantiate(row,
- aliases.column_aliases(node))
- other = record.association(node.reflection.name)
-
- if node.reflection.collection?
- other.target.push(model)
- else
- other.target = model
+ other.set_inverse_instance(model)
+ model
end
-
- other.set_inverse_instance(model)
- model
- end
end
end
end
diff --git a/activerecord/lib/active_record/associations/preloader.rb b/activerecord/lib/active_record/associations/preloader.rb
index 320d9dc952..a81860e40f 100644
--- a/activerecord/lib/active_record/associations/preloader.rb
+++ b/activerecord/lib/active_record/associations/preloader.rb
@@ -107,30 +107,30 @@ module ActiveRecord
private
# Loads all the given data into +records+ for the +association+.
- def preloaders_on(association, records, scope)
- case association
- when Hash
- preloaders_for_hash(association, records, scope)
- when Symbol
- preloaders_for_one(association, records, scope)
- when String
- preloaders_for_one(association.to_sym, records, scope)
- else
- raise ArgumentError, "#{association.inspect} was not recognized for preload"
+ def preloaders_on(association, records, scope)
+ case association
+ when Hash
+ preloaders_for_hash(association, records, scope)
+ when Symbol
+ preloaders_for_one(association, records, scope)
+ when String
+ preloaders_for_one(association.to_sym, records, scope)
+ else
+ raise ArgumentError, "#{association.inspect} was not recognized for preload"
+ end
end
- end
- def preloaders_for_hash(association, records, scope)
- association.flat_map { |parent, child|
- loaders = preloaders_for_one parent, records, scope
+ def preloaders_for_hash(association, records, scope)
+ association.flat_map { |parent, child|
+ loaders = preloaders_for_one parent, records, scope
- recs = loaders.flat_map(&:preloaded_records).uniq
- loaders.concat Array.wrap(child).flat_map { |assoc|
- preloaders_on assoc, recs, scope
+ recs = loaders.flat_map(&:preloaded_records).uniq
+ loaders.concat Array.wrap(child).flat_map { |assoc|
+ preloaders_on assoc, recs, scope
+ }
+ loaders
}
- loaders
- }
- end
+ end
# Loads all the given data into +records+ for a singular +association+.
#
@@ -144,70 +144,70 @@ module ActiveRecord
# Additionally, polymorphic belongs_to associations can have multiple associated
# classes, depending on the polymorphic_type field. So we group by the classes as
# well.
- def preloaders_for_one(association, records, scope)
- grouped_records(association, records).flat_map do |reflection, klasses|
- klasses.map do |rhs_klass, rs|
- loader = preloader_for(reflection, rs, rhs_klass).new(rhs_klass, rs, reflection, scope)
- loader.run self
- loader
+ def preloaders_for_one(association, records, scope)
+ grouped_records(association, records).flat_map do |reflection, klasses|
+ klasses.map do |rhs_klass, rs|
+ loader = preloader_for(reflection, rs, rhs_klass).new(rhs_klass, rs, reflection, scope)
+ loader.run self
+ loader
+ end
end
end
- end
- def grouped_records(association, records)
- h = {}
- records.each do |record|
- next unless record
- assoc = record.association(association)
- klasses = h[assoc.reflection] ||= {}
- (klasses[assoc.klass] ||= []) << record
+ def grouped_records(association, records)
+ h = {}
+ records.each do |record|
+ next unless record
+ assoc = record.association(association)
+ klasses = h[assoc.reflection] ||= {}
+ (klasses[assoc.klass] ||= []) << record
+ end
+ h
end
- h
- end
- class AlreadyLoaded # :nodoc:
- attr_reader :owners, :reflection
+ class AlreadyLoaded # :nodoc:
+ attr_reader :owners, :reflection
- def initialize(klass, owners, reflection, preload_scope)
- @owners = owners
- @reflection = reflection
- end
+ def initialize(klass, owners, reflection, preload_scope)
+ @owners = owners
+ @reflection = reflection
+ end
- def run(preloader); end
+ def run(preloader); end
- def preloaded_records
- owners.flat_map { |owner| owner.association(reflection.name).target }
+ def preloaded_records
+ owners.flat_map { |owner| owner.association(reflection.name).target }
+ end
end
- end
- class NullPreloader # :nodoc:
- def self.new(klass, owners, reflection, preload_scope); self; end
- def self.run(preloader); end
- def self.preloaded_records; []; end
- def self.owners; []; end
- end
+ class NullPreloader # :nodoc:
+ def self.new(klass, owners, reflection, preload_scope); self; end
+ def self.run(preloader); end
+ def self.preloaded_records; []; end
+ def self.owners; []; end
+ end
# Returns a class containing the logic needed to load preload the data
# and attach it to a relation. For example +Preloader::Association+ or
# +Preloader::HasManyThrough+. The class returned implements a `run` method
# that accepts a preloader.
- def preloader_for(reflection, owners, rhs_klass)
- return NullPreloader unless rhs_klass
+ def preloader_for(reflection, owners, rhs_klass)
+ return NullPreloader unless rhs_klass
- if owners.first.association(reflection.name).loaded?
- return AlreadyLoaded
- end
- reflection.check_preloadable!
-
- case reflection.macro
- when :has_many
- reflection.options[:through] ? HasManyThrough : HasMany
- when :has_one
- reflection.options[:through] ? HasOneThrough : HasOne
- when :belongs_to
- BelongsTo
+ if owners.first.association(reflection.name).loaded?
+ return AlreadyLoaded
+ end
+ reflection.check_preloadable!
+
+ case reflection.macro
+ when :has_many
+ reflection.options[:through] ? HasManyThrough : HasMany
+ when :has_one
+ reflection.options[:through] ? HasOneThrough : HasOne
+ when :belongs_to
+ BelongsTo
+ end
end
- end
end
end
end
diff --git a/activerecord/lib/active_record/associations/preloader/association.rb b/activerecord/lib/active_record/associations/preloader/association.rb
index 3032bc786e..a8afa48865 100644
--- a/activerecord/lib/active_record/associations/preloader/association.rb
+++ b/activerecord/lib/active_record/associations/preloader/association.rb
@@ -61,99 +61,99 @@ module ActiveRecord
private
- def associated_records_by_owner(preloader)
- records = load_records
- owners.each_with_object({}) do |owner, result|
- result[owner] = records[convert_key(owner[owner_key_name])] || []
+ def associated_records_by_owner(preloader)
+ records = load_records
+ owners.each_with_object({}) do |owner, result|
+ result[owner] = records[convert_key(owner[owner_key_name])] || []
+ end
end
- end
- def owner_keys
- unless defined?(@owner_keys)
- @owner_keys = owners.map do |owner|
- owner[owner_key_name]
+ def owner_keys
+ unless defined?(@owner_keys)
+ @owner_keys = owners.map do |owner|
+ owner[owner_key_name]
+ end
+ @owner_keys.uniq!
+ @owner_keys.compact!
end
- @owner_keys.uniq!
- @owner_keys.compact!
+ @owner_keys
end
- @owner_keys
- end
- def key_conversion_required?
- @key_conversion_required ||= association_key_type != owner_key_type
- end
+ def key_conversion_required?
+ @key_conversion_required ||= association_key_type != owner_key_type
+ end
- def convert_key(key)
- if key_conversion_required?
- key.to_s
- else
- key
+ def convert_key(key)
+ if key_conversion_required?
+ key.to_s
+ else
+ key
+ end
end
- end
- def association_key_type
- @klass.type_for_attribute(association_key_name.to_s).type
- end
+ def association_key_type
+ @klass.type_for_attribute(association_key_name.to_s).type
+ end
- def owner_key_type
- @model.type_for_attribute(owner_key_name.to_s).type
- end
+ def owner_key_type
+ @model.type_for_attribute(owner_key_name.to_s).type
+ end
- def load_records
- return {} if owner_keys.empty?
- # Some databases impose a limit on the number of ids in a list (in Oracle it's 1000)
- # Make several smaller queries if necessary or make one query if the adapter supports it
- slices = owner_keys.each_slice(klass.connection.in_clause_length || owner_keys.size)
- @preloaded_records = slices.flat_map do |slice|
- records_for(slice)
+ def load_records
+ return {} if owner_keys.empty?
+ # Some databases impose a limit on the number of ids in a list (in Oracle it's 1000)
+ # Make several smaller queries if necessary or make one query if the adapter supports it
+ slices = owner_keys.each_slice(klass.connection.in_clause_length || owner_keys.size)
+ @preloaded_records = slices.flat_map do |slice|
+ records_for(slice)
+ end
+ @preloaded_records.group_by do |record|
+ convert_key(record[association_key_name])
+ end
end
- @preloaded_records.group_by do |record|
- convert_key(record[association_key_name])
+
+ def reflection_scope
+ @reflection_scope ||= reflection.scope ? klass.unscoped.instance_exec(nil, &reflection.scope) : klass.unscoped
end
- end
- def reflection_scope
- @reflection_scope ||= reflection.scope ? klass.unscoped.instance_exec(nil, &reflection.scope) : klass.unscoped
- end
+ def build_scope
+ scope = klass.unscoped
- def build_scope
- scope = klass.unscoped
+ values = reflection_scope.values
+ preload_values = preload_scope.values
- values = reflection_scope.values
- preload_values = preload_scope.values
+ scope.where_clause = reflection_scope.where_clause + preload_scope.where_clause
+ scope.references_values = Array(values[:references]) + Array(preload_values[:references])
- scope.where_clause = reflection_scope.where_clause + preload_scope.where_clause
- scope.references_values = Array(values[:references]) + Array(preload_values[:references])
+ if preload_values[:select] || values[:select]
+ scope._select!(preload_values[:select] || values[:select])
+ end
+ scope.includes! preload_values[:includes] || values[:includes]
+ if preload_scope.joins_values.any?
+ scope.joins!(preload_scope.joins_values)
+ else
+ scope.joins!(reflection_scope.joins_values)
+ end
- if preload_values[:select] || values[:select]
- scope._select!(preload_values[:select] || values[:select])
- end
- scope.includes! preload_values[:includes] || values[:includes]
- if preload_scope.joins_values.any?
- scope.joins!(preload_scope.joins_values)
- else
- scope.joins!(reflection_scope.joins_values)
- end
+ if order_values = preload_values[:order] || values[:order]
+ scope.order!(order_values)
+ end
- if order_values = preload_values[:order] || values[:order]
- scope.order!(order_values)
- end
+ if preload_values[:reordering] || values[:reordering]
+ scope.reordering_value = true
+ end
- if preload_values[:reordering] || values[:reordering]
- scope.reordering_value = true
- end
+ if preload_values[:readonly] || values[:readonly]
+ scope.readonly!
+ end
- if preload_values[:readonly] || values[:readonly]
- scope.readonly!
- end
+ if options[:as]
+ scope.where!(klass.table_name => { reflection.type => model.base_class.sti_name })
+ end
- if options[:as]
- scope.where!(klass.table_name => { reflection.type => model.base_class.sti_name })
+ scope.unscope_values = Array(values[:unscope]) + Array(preload_values[:unscope])
+ klass.default_scoped.merge(scope)
end
-
- scope.unscope_values = Array(values[:unscope]) + Array(preload_values[:unscope])
- klass.default_scoped.merge(scope)
- end
end
end
end
diff --git a/activerecord/lib/active_record/associations/preloader/collection_association.rb b/activerecord/lib/active_record/associations/preloader/collection_association.rb
index 9939280fa4..24b8e01029 100644
--- a/activerecord/lib/active_record/associations/preloader/collection_association.rb
+++ b/activerecord/lib/active_record/associations/preloader/collection_association.rb
@@ -4,14 +4,14 @@ module ActiveRecord
class CollectionAssociation < Association #:nodoc:
private
- def preload(preloader)
- associated_records_by_owner(preloader).each do |owner, records|
- association = owner.association(reflection.name)
- association.loaded!
- association.target.concat(records)
- records.each { |record| association.set_inverse_instance(record) }
+ def preload(preloader)
+ associated_records_by_owner(preloader).each do |owner, records|
+ association = owner.association(reflection.name)
+ association.loaded!
+ association.target.concat(records)
+ records.each { |record| association.set_inverse_instance(record) }
+ end
end
- end
end
end
end
diff --git a/activerecord/lib/active_record/associations/preloader/singular_association.rb b/activerecord/lib/active_record/associations/preloader/singular_association.rb
index f60647a81e..9f8d98c5a5 100644
--- a/activerecord/lib/active_record/associations/preloader/singular_association.rb
+++ b/activerecord/lib/active_record/associations/preloader/singular_association.rb
@@ -5,15 +5,15 @@ module ActiveRecord
private
- def preload(preloader)
- associated_records_by_owner(preloader).each do |owner, associated_records|
- record = associated_records.first
+ def preload(preloader)
+ associated_records_by_owner(preloader).each do |owner, associated_records|
+ record = associated_records.first
- association = owner.association(reflection.name)
- association.target = record
- association.set_inverse_instance(record) if record
+ association = owner.association(reflection.name)
+ association.target = record
+ association.set_inverse_instance(record) if record
+ end
end
- end
end
end
diff --git a/activerecord/lib/active_record/associations/preloader/through_association.rb b/activerecord/lib/active_record/associations/preloader/through_association.rb
index b0203909ce..f53c30f80e 100644
--- a/activerecord/lib/active_record/associations/preloader/through_association.rb
+++ b/activerecord/lib/active_record/associations/preloader/through_association.rb
@@ -61,48 +61,48 @@ module ActiveRecord
private
- def id_to_index_map(ids)
- id_map = {}
- ids.each_with_index { |id, index| id_map[id] = index }
- id_map
- end
+ def id_to_index_map(ids)
+ id_map = {}
+ ids.each_with_index { |id, index| id_map[id] = index }
+ id_map
+ end
- def reset_association(owners, association_name)
- should_reset = (through_scope != through_reflection.klass.unscoped) ||
- (reflection.options[:source_type] && through_reflection.collection?)
+ def reset_association(owners, association_name)
+ should_reset = (through_scope != through_reflection.klass.unscoped) ||
+ (reflection.options[:source_type] && through_reflection.collection?)
- # Don't cache the association - we would only be caching a subset
- if should_reset
- owners.each { |owner|
- owner.association(association_name).reset
- }
+ # Don't cache the association - we would only be caching a subset
+ if should_reset
+ owners.each { |owner|
+ owner.association(association_name).reset
+ }
+ end
end
- end
- def through_scope
- scope = through_reflection.klass.unscoped
+ def through_scope
+ scope = through_reflection.klass.unscoped
- if options[:source_type]
- scope.where! reflection.foreign_type => options[:source_type]
- else
- unless reflection_scope.where_clause.empty?
- scope.includes_values = Array(reflection_scope.values[:includes] || options[:source])
- scope.where_clause = reflection_scope.where_clause
- end
+ if options[:source_type]
+ scope.where! reflection.foreign_type => options[:source_type]
+ else
+ unless reflection_scope.where_clause.empty?
+ scope.includes_values = Array(reflection_scope.values[:includes] || options[:source])
+ scope.where_clause = reflection_scope.where_clause
+ end
- scope.references! reflection_scope.values[:references]
- if scope.eager_loading? && order_values = reflection_scope.values[:order]
- scope = scope.order(order_values)
+ scope.references! reflection_scope.values[:references]
+ if scope.eager_loading? && order_values = reflection_scope.values[:order]
+ scope = scope.order(order_values)
+ end
end
- end
- scope
- end
+ scope
+ end
- def target_records_from_association(association)
- association.loaded? ? association.target : association.reader
- end
+ def target_records_from_association(association)
+ association.loaded? ? association.target : association.reader
+ end
end
end
end
diff --git a/activerecord/lib/active_record/attribute.rb b/activerecord/lib/active_record/attribute.rb
index 2f41e9e45b..95b3adae5f 100644
--- a/activerecord/lib/active_record/attribute.rb
+++ b/activerecord/lib/active_record/attribute.rb
@@ -130,108 +130,108 @@ module ActiveRecord
protected
- attr_reader :original_attribute
- alias_method :assigned?, :original_attribute
+ attr_reader :original_attribute
+ alias_method :assigned?, :original_attribute
- def initialize_dup(other)
- if defined?(@value) && @value.duplicable?
- @value = @value.dup
+ def initialize_dup(other)
+ if defined?(@value) && @value.duplicable?
+ @value = @value.dup
+ end
end
- end
-
- def changed_from_assignment?
- assigned? && type.changed?(original_value, value, value_before_type_cast)
- end
- def original_value_for_database
- if assigned?
- original_attribute.original_value_for_database
- else
- _original_value_for_database
+ def changed_from_assignment?
+ assigned? && type.changed?(original_value, value, value_before_type_cast)
end
- end
-
- def _original_value_for_database
- type.serialize(original_value)
- end
- class FromDatabase < Attribute # :nodoc:
- def type_cast(value)
- type.deserialize(value)
+ def original_value_for_database
+ if assigned?
+ original_attribute.original_value_for_database
+ else
+ _original_value_for_database
+ end
end
def _original_value_for_database
- value_before_type_cast
+ type.serialize(original_value)
end
- end
- class FromUser < Attribute # :nodoc:
- def type_cast(value)
- type.cast(value)
- end
+ class FromDatabase < Attribute # :nodoc:
+ def type_cast(value)
+ type.deserialize(value)
+ end
- def came_from_user?
- true
+ def _original_value_for_database
+ value_before_type_cast
+ end
end
- end
- class WithCastValue < Attribute # :nodoc:
- def type_cast(value)
- value
- end
+ class FromUser < Attribute # :nodoc:
+ def type_cast(value)
+ type.cast(value)
+ end
- def changed_in_place?
- false
+ def came_from_user?
+ true
+ end
end
- end
- class Null < Attribute # :nodoc:
- def initialize(name)
- super(name, nil, Type::Value.new)
- end
+ class WithCastValue < Attribute # :nodoc:
+ def type_cast(value)
+ value
+ end
- def type_cast(*)
- nil
+ def changed_in_place?
+ false
+ end
end
- def with_type(type)
- self.class.with_cast_value(name, nil, type)
- end
+ class Null < Attribute # :nodoc:
+ def initialize(name)
+ super(name, nil, Type::Value.new)
+ end
- def with_value_from_database(value)
- raise ActiveModel::MissingAttributeError, "can't write unknown attribute `#{name}`"
- end
- alias_method :with_value_from_user, :with_value_from_database
- end
+ def type_cast(*)
+ nil
+ end
- class Uninitialized < Attribute # :nodoc:
- UNINITIALIZED_ORIGINAL_VALUE = Object.new
+ def with_type(type)
+ self.class.with_cast_value(name, nil, type)
+ end
- def initialize(name, type)
- super(name, nil, type)
+ def with_value_from_database(value)
+ raise ActiveModel::MissingAttributeError, "can't write unknown attribute `#{name}`"
+ end
+ alias_method :with_value_from_user, :with_value_from_database
end
- def value
- if block_given?
- yield name
+ class Uninitialized < Attribute # :nodoc:
+ UNINITIALIZED_ORIGINAL_VALUE = Object.new
+
+ def initialize(name, type)
+ super(name, nil, type)
end
- end
- def original_value
- UNINITIALIZED_ORIGINAL_VALUE
- end
+ def value
+ if block_given?
+ yield name
+ end
+ end
- def value_for_database
- end
+ def original_value
+ UNINITIALIZED_ORIGINAL_VALUE
+ end
- def initialized?
- false
- end
+ def value_for_database
+ end
+
+ def initialized?
+ false
+ end
- def with_type(type)
- self.class.new(name, type)
+ def with_type(type)
+ self.class.new(name, type)
+ end
end
- end
- private_constant :FromDatabase, :FromUser, :Null, :Uninitialized, :WithCastValue
+ private_constant :FromDatabase, :FromUser, :Null, :Uninitialized, :WithCastValue
end
end
diff --git a/activerecord/lib/active_record/attribute/user_provided_default.rb b/activerecord/lib/active_record/attribute/user_provided_default.rb
index 32b9c289bb..a4e2c2ec85 100644
--- a/activerecord/lib/active_record/attribute/user_provided_default.rb
+++ b/activerecord/lib/active_record/attribute/user_provided_default.rb
@@ -22,7 +22,7 @@ module ActiveRecord
protected
- attr_reader :user_provided_value
+ attr_reader :user_provided_value
end
end
end
diff --git a/activerecord/lib/active_record/attribute_assignment.rb b/activerecord/lib/active_record/attribute_assignment.rb
index 1cccb0852e..f3ce52fdfe 100644
--- a/activerecord/lib/active_record/attribute_assignment.rb
+++ b/activerecord/lib/active_record/attribute_assignment.rb
@@ -12,27 +12,27 @@ module ActiveRecord
private
- def _assign_attributes(attributes) # :nodoc:
- multi_parameter_attributes = {}
- nested_parameter_attributes = {}
+ def _assign_attributes(attributes) # :nodoc:
+ multi_parameter_attributes = {}
+ nested_parameter_attributes = {}
- attributes.each do |k, v|
- if k.include?("(")
- multi_parameter_attributes[k] = attributes.delete(k)
- elsif v.is_a?(Hash)
- nested_parameter_attributes[k] = attributes.delete(k)
+ attributes.each do |k, v|
+ if k.include?("(")
+ multi_parameter_attributes[k] = attributes.delete(k)
+ elsif v.is_a?(Hash)
+ nested_parameter_attributes[k] = attributes.delete(k)
+ end
end
- end
- super(attributes)
+ super(attributes)
- assign_nested_parameter_attributes(nested_parameter_attributes) unless nested_parameter_attributes.empty?
- assign_multiparameter_attributes(multi_parameter_attributes) unless multi_parameter_attributes.empty?
- end
+ assign_nested_parameter_attributes(nested_parameter_attributes) unless nested_parameter_attributes.empty?
+ assign_multiparameter_attributes(multi_parameter_attributes) unless multi_parameter_attributes.empty?
+ end
# Assign any deferred nested attributes after the base attributes have been set.
- def assign_nested_parameter_attributes(pairs)
- pairs.each { |k, v| _assign_attribute(k, v) }
- end
+ def assign_nested_parameter_attributes(pairs)
+ pairs.each { |k, v| _assign_attribute(k, v) }
+ end
# Instantiates objects for all attribute classes that needs more than one constructor parameter. This is done
# by calling new on the column type or aggregation type (through composed_of) object with these parameters.
@@ -40,52 +40,52 @@ module ActiveRecord
# 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 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(
- extract_callstack_for_multiparameter_attributes(pairs)
- )
- end
+ def assign_multiparameter_attributes(pairs)
+ execute_callstack_for_multiparameter_attributes(
+ extract_callstack_for_multiparameter_attributes(pairs)
+ )
+ end
- def execute_callstack_for_multiparameter_attributes(callstack)
- errors = []
- callstack.each do |name, values_with_empty_parameters|
- begin
- if values_with_empty_parameters.each_value.all?(&:nil?)
- values = nil
- else
- values = values_with_empty_parameters
+ def execute_callstack_for_multiparameter_attributes(callstack)
+ errors = []
+ callstack.each do |name, values_with_empty_parameters|
+ begin
+ if values_with_empty_parameters.each_value.all?(&:nil?)
+ values = nil
+ else
+ values = values_with_empty_parameters
+ end
+ send("#{name}=", values)
+ rescue => ex
+ errors << AttributeAssignmentError.new("error on assignment #{values_with_empty_parameters.values.inspect} to #{name} (#{ex.message})", ex, name)
end
- send("#{name}=", values)
- rescue => ex
- errors << AttributeAssignmentError.new("error on assignment #{values_with_empty_parameters.values.inspect} to #{name} (#{ex.message})", ex, name)
+ end
+ unless errors.empty?
+ error_descriptions = errors.map(&:message).join(",")
+ raise MultiparameterAssignmentErrors.new(errors), "#{errors.size} error(s) on assignment of multiparameter attributes [#{error_descriptions}]"
end
end
- unless errors.empty?
- error_descriptions = errors.map(&:message).join(",")
- raise MultiparameterAssignmentErrors.new(errors), "#{errors.size} error(s) on assignment of multiparameter attributes [#{error_descriptions}]"
- end
- end
- def extract_callstack_for_multiparameter_attributes(pairs)
- attributes = {}
+ def extract_callstack_for_multiparameter_attributes(pairs)
+ attributes = {}
- pairs.each do |(multiparameter_name, value)|
- attribute_name = multiparameter_name.split("(").first
- attributes[attribute_name] ||= {}
+ pairs.each do |(multiparameter_name, value)|
+ attribute_name = multiparameter_name.split("(").first
+ attributes[attribute_name] ||= {}
- parameter_value = value.empty? ? nil : type_cast_attribute_value(multiparameter_name, value)
- attributes[attribute_name][find_parameter_position(multiparameter_name)] ||= parameter_value
- end
+ parameter_value = value.empty? ? nil : type_cast_attribute_value(multiparameter_name, value)
+ attributes[attribute_name][find_parameter_position(multiparameter_name)] ||= parameter_value
+ end
- attributes
- end
+ attributes
+ end
- def type_cast_attribute_value(multiparameter_name, value)
- multiparameter_name =~ /\([0-9]*([if])\)/ ? value.send("to_" + $1) : value
- end
+ def type_cast_attribute_value(multiparameter_name, value)
+ multiparameter_name =~ /\([0-9]*([if])\)/ ? value.send("to_" + $1) : value
+ end
- def find_parameter_position(multiparameter_name)
- multiparameter_name.scan(/\(([0-9]*).*\)/).first.first.to_i
- end
+ def find_parameter_position(multiparameter_name)
+ multiparameter_name.scan(/\(([0-9]*).*\)/).first.first.to_i
+ end
end
end
diff --git a/activerecord/lib/active_record/attribute_decorators.rb b/activerecord/lib/active_record/attribute_decorators.rb
index 7d0ae32411..340dfe11cf 100644
--- a/activerecord/lib/active_record/attribute_decorators.rb
+++ b/activerecord/lib/active_record/attribute_decorators.rb
@@ -24,13 +24,13 @@ module ActiveRecord
private
- def load_schema!
- super
- attribute_types.each do |name, type|
- decorated_type = attribute_type_decorations.apply(name, type)
- define_attribute(name, decorated_type)
+ def load_schema!
+ super
+ attribute_types.each do |name, type|
+ decorated_type = attribute_type_decorations.apply(name, type)
+ define_attribute(name, decorated_type)
+ end
end
- end
end
class TypeDecorator # :nodoc:
@@ -53,15 +53,15 @@ module ActiveRecord
private
- def decorators_for(name, type)
- matching(name, type).map(&:last)
- end
+ def decorators_for(name, type)
+ matching(name, type).map(&:last)
+ end
- def matching(name, type)
- @decorations.values.select do |(matcher, _)|
- matcher.call(name, type)
+ def matching(name, type)
+ @decorations.values.select do |(matcher, _)|
+ matcher.call(name, type)
+ end
end
- end
end
end
end
diff --git a/activerecord/lib/active_record/attribute_methods.rb b/activerecord/lib/active_record/attribute_methods.rb
index 12699bb30b..367e7fba84 100644
--- a/activerecord/lib/active_record/attribute_methods.rb
+++ b/activerecord/lib/active_record/attribute_methods.rb
@@ -161,7 +161,7 @@ module ActiveRecord
# # => ["id", "created_at", "updated_at", "name", "age"]
def attribute_names
@attribute_names ||= if !abstract_class? && table_exists?
- attribute_types.keys
+ attribute_types.keys
else
[]
end
@@ -394,65 +394,65 @@ module ActiveRecord
protected
- def clone_attribute_value(reader_method, attribute_name) # :nodoc:
- value = send(reader_method, attribute_name)
- value.duplicable? ? value.clone : value
- rescue TypeError, NoMethodError
- value
- end
+ def clone_attribute_value(reader_method, attribute_name) # :nodoc:
+ value = send(reader_method, attribute_name)
+ value.duplicable? ? value.clone : value
+ rescue TypeError, NoMethodError
+ value
+ end
- def arel_attributes_with_values_for_create(attribute_names) # :nodoc:
- arel_attributes_with_values(attributes_for_create(attribute_names))
- end
+ def arel_attributes_with_values_for_create(attribute_names) # :nodoc:
+ arel_attributes_with_values(attributes_for_create(attribute_names))
+ end
- def arel_attributes_with_values_for_update(attribute_names) # :nodoc:
- arel_attributes_with_values(attributes_for_update(attribute_names))
- end
+ def arel_attributes_with_values_for_update(attribute_names) # :nodoc:
+ arel_attributes_with_values(attributes_for_update(attribute_names))
+ end
- def attribute_method?(attr_name) # :nodoc:
- # We check defined? because Syck calls respond_to? before actually calling initialize.
- defined?(@attributes) && @attributes.key?(attr_name)
- end
+ def attribute_method?(attr_name) # :nodoc:
+ # We check defined? because Syck calls respond_to? before actually calling initialize.
+ defined?(@attributes) && @attributes.key?(attr_name)
+ end
private
# Returns a Hash of the Arel::Attributes and attribute values that have been
# typecasted for use in an Arel insert/update method.
- def arel_attributes_with_values(attribute_names)
- attrs = {}
- arel_table = self.class.arel_table
+ def arel_attributes_with_values(attribute_names)
+ attrs = {}
+ arel_table = self.class.arel_table
- attribute_names.each do |name|
- attrs[arel_table[name]] = typecasted_attribute_value(name)
+ attribute_names.each do |name|
+ attrs[arel_table[name]] = typecasted_attribute_value(name)
+ end
+ attrs
end
- attrs
- end
# Filters the primary keys and readonly attributes from the attribute names.
- def attributes_for_update(attribute_names)
- attribute_names.reject do |name|
- readonly_attribute?(name)
+ def attributes_for_update(attribute_names)
+ attribute_names.reject do |name|
+ readonly_attribute?(name)
+ end
end
- end
# Filters out the primary keys, from the attribute names, when the primary
# key is to be generated (e.g. the id attribute has no value).
- def attributes_for_create(attribute_names)
- attribute_names.reject do |name|
- pk_attribute?(name) && id.nil?
+ def attributes_for_create(attribute_names)
+ attribute_names.reject do |name|
+ pk_attribute?(name) && id.nil?
+ end
end
- end
- def readonly_attribute?(name)
- self.class.readonly_attributes.include?(name)
- end
+ def readonly_attribute?(name)
+ self.class.readonly_attributes.include?(name)
+ end
- def pk_attribute?(name)
- name == self.class.primary_key
- end
+ def pk_attribute?(name)
+ name == self.class.primary_key
+ end
- def typecasted_attribute_value(name)
- _read_attribute(name)
- end
+ def typecasted_attribute_value(name)
+ _read_attribute(name)
+ end
end
end
diff --git a/activerecord/lib/active_record/attribute_methods/before_type_cast.rb b/activerecord/lib/active_record/attribute_methods/before_type_cast.rb
index 1db6776688..92f124078c 100644
--- a/activerecord/lib/active_record/attribute_methods/before_type_cast.rb
+++ b/activerecord/lib/active_record/attribute_methods/before_type_cast.rb
@@ -64,13 +64,13 @@ module ActiveRecord
private
# Handle *_before_type_cast for method_missing.
- def attribute_before_type_cast(attribute_name)
- read_attribute_before_type_cast(attribute_name)
- end
+ def attribute_before_type_cast(attribute_name)
+ read_attribute_before_type_cast(attribute_name)
+ end
- def attribute_came_from_user?(attribute_name)
- @attributes[attribute_name].came_from_user?
- end
+ def attribute_came_from_user?(attribute_name)
+ @attributes[attribute_name].came_from_user?
+ end
end
end
end
diff --git a/activerecord/lib/active_record/attribute_methods/dirty.rb b/activerecord/lib/active_record/attribute_methods/dirty.rb
index 50d7e1df7a..c9638bf70b 100644
--- a/activerecord/lib/active_record/attribute_methods/dirty.rb
+++ b/activerecord/lib/active_record/attribute_methods/dirty.rb
@@ -100,52 +100,52 @@ module ActiveRecord
private
- def mutation_tracker
- unless defined?(@mutation_tracker)
- @mutation_tracker = nil
+ def mutation_tracker
+ unless defined?(@mutation_tracker)
+ @mutation_tracker = nil
+ end
+ @mutation_tracker ||= AttributeMutationTracker.new(@attributes)
end
- @mutation_tracker ||= AttributeMutationTracker.new(@attributes)
- end
- def changes_include?(attr_name)
- super || mutation_tracker.changed?(attr_name)
- end
+ def changes_include?(attr_name)
+ super || mutation_tracker.changed?(attr_name)
+ end
- def clear_attribute_change(attr_name)
- mutation_tracker.forget_change(attr_name)
- end
+ def clear_attribute_change(attr_name)
+ mutation_tracker.forget_change(attr_name)
+ end
- def _update_record(*)
- partial_writes? ? super(keys_for_partial_write) : super
- end
+ def _update_record(*)
+ partial_writes? ? super(keys_for_partial_write) : super
+ end
- def _create_record(*)
- partial_writes? ? super(keys_for_partial_write) : super
- end
+ def _create_record(*)
+ partial_writes? ? super(keys_for_partial_write) : super
+ end
- def keys_for_partial_write
- changed & self.class.column_names
- end
+ def keys_for_partial_write
+ changed & self.class.column_names
+ end
- def store_original_attributes
- @attributes = @attributes.map(&:forgetting_assignment)
- @mutation_tracker = nil
- end
+ def store_original_attributes
+ @attributes = @attributes.map(&:forgetting_assignment)
+ @mutation_tracker = nil
+ end
- def previous_mutation_tracker
- @previous_mutation_tracker ||= NullMutationTracker.instance
- end
+ def previous_mutation_tracker
+ @previous_mutation_tracker ||= NullMutationTracker.instance
+ end
- def cache_changed_attributes
- @cached_changed_attributes = changed_attributes
- yield
- ensure
- clear_changed_attributes_cache
- end
+ def cache_changed_attributes
+ @cached_changed_attributes = changed_attributes
+ yield
+ ensure
+ clear_changed_attributes_cache
+ end
- def clear_changed_attributes_cache
- remove_instance_variable(:@cached_changed_attributes) if defined?(@cached_changed_attributes)
- end
+ def clear_changed_attributes_cache
+ remove_instance_variable(:@cached_changed_attributes) if defined?(@cached_changed_attributes)
+ end
end
end
end
diff --git a/activerecord/lib/active_record/attribute_methods/primary_key.rb b/activerecord/lib/active_record/attribute_methods/primary_key.rb
index 162a564a49..9e99ed8ac1 100644
--- a/activerecord/lib/active_record/attribute_methods/primary_key.rb
+++ b/activerecord/lib/active_record/attribute_methods/primary_key.rb
@@ -47,95 +47,95 @@ module ActiveRecord
protected
- def attribute_method?(attr_name)
- attr_name == "id" || super
- end
+ def attribute_method?(attr_name)
+ attr_name == "id" || super
+ end
- module ClassMethods
- def define_method_attribute(attr_name)
- super
+ module ClassMethods
+ def define_method_attribute(attr_name)
+ super
- if attr_name == primary_key && attr_name != "id"
- generated_attribute_methods.send(:alias_method, :id, primary_key)
+ if attr_name == primary_key && attr_name != "id"
+ generated_attribute_methods.send(:alias_method, :id, primary_key)
+ end
end
- end
- ID_ATTRIBUTE_METHODS = %w(id id= id? id_before_type_cast id_was).to_set
+ ID_ATTRIBUTE_METHODS = %w(id id= id? id_before_type_cast id_was).to_set
- def dangerous_attribute_method?(method_name)
- super && !ID_ATTRIBUTE_METHODS.include?(method_name)
- end
+ def dangerous_attribute_method?(method_name)
+ super && !ID_ATTRIBUTE_METHODS.include?(method_name)
+ end
- # Defines the primary key field -- can be overridden in subclasses.
- # Overwriting will negate any effect of the +primary_key_prefix_type+
- # setting, though.
- def primary_key
- @primary_key = reset_primary_key unless defined? @primary_key
- @primary_key
- end
+ # Defines the primary key field -- can be overridden in subclasses.
+ # Overwriting will negate any effect of the +primary_key_prefix_type+
+ # setting, though.
+ def primary_key
+ @primary_key = reset_primary_key unless defined? @primary_key
+ @primary_key
+ end
- # Returns a quoted version of the primary key name, used to construct
- # SQL statements.
- def quoted_primary_key
- @quoted_primary_key ||= connection.quote_column_name(primary_key)
- end
+ # Returns a quoted version of the primary key name, used to construct
+ # SQL statements.
+ def quoted_primary_key
+ @quoted_primary_key ||= connection.quote_column_name(primary_key)
+ end
- def reset_primary_key #:nodoc:
- if self == base_class
- self.primary_key = get_primary_key(base_class.name)
- else
- self.primary_key = base_class.primary_key
+ def reset_primary_key #:nodoc:
+ if self == base_class
+ self.primary_key = get_primary_key(base_class.name)
+ else
+ self.primary_key = base_class.primary_key
+ end
end
- end
- def get_primary_key(base_name) #:nodoc:
- if base_name && primary_key_prefix_type == :table_name
- base_name.foreign_key(false)
- elsif base_name && primary_key_prefix_type == :table_name_with_underscore
- base_name.foreign_key
- else
- if ActiveRecord::Base != self && table_exists?
- pk = connection.schema_cache.primary_keys(table_name)
- suppress_composite_primary_key(pk)
+ def get_primary_key(base_name) #:nodoc:
+ if base_name && primary_key_prefix_type == :table_name
+ base_name.foreign_key(false)
+ elsif base_name && primary_key_prefix_type == :table_name_with_underscore
+ base_name.foreign_key
else
- "id"
+ if ActiveRecord::Base != self && table_exists?
+ pk = connection.schema_cache.primary_keys(table_name)
+ suppress_composite_primary_key(pk)
+ else
+ "id"
+ end
end
end
- end
- # Sets the name of the primary key column.
- #
- # class Project < ActiveRecord::Base
- # self.primary_key = 'sysid'
- # end
- #
- # You can also define the #primary_key method yourself:
- #
- # class Project < ActiveRecord::Base
- # def self.primary_key
- # 'foo_' + super
- # end
- # end
- #
- # Project.primary_key # => "foo_id"
- def primary_key=(value)
- @primary_key = value && value.to_s
- @quoted_primary_key = nil
- @attributes_builder = nil
- end
+ # Sets the name of the primary key column.
+ #
+ # class Project < ActiveRecord::Base
+ # self.primary_key = 'sysid'
+ # end
+ #
+ # You can also define the #primary_key method yourself:
+ #
+ # class Project < ActiveRecord::Base
+ # def self.primary_key
+ # 'foo_' + super
+ # end
+ # end
+ #
+ # Project.primary_key # => "foo_id"
+ def primary_key=(value)
+ @primary_key = value && value.to_s
+ @quoted_primary_key = nil
+ @attributes_builder = nil
+ end
- private
+ private
- def suppress_composite_primary_key(pk)
- return pk unless pk.is_a?(Array)
+ def suppress_composite_primary_key(pk)
+ return pk unless pk.is_a?(Array)
- warn <<-WARNING.strip_heredoc
+ warn <<-WARNING.strip_heredoc
WARNING: Active Record does not support composite primary key.
#{table_name} has composite primary key. Composite primary key is ignored.
WARNING
+ end
end
- end
end
end
end
diff --git a/activerecord/lib/active_record/attribute_methods/read.rb b/activerecord/lib/active_record/attribute_methods/read.rb
index a7310130fe..95853501db 100644
--- a/activerecord/lib/active_record/attribute_methods/read.rb
+++ b/activerecord/lib/active_record/attribute_methods/read.rb
@@ -24,24 +24,24 @@ module ActiveRecord
# to allocate an object on each call to the attribute method.
# Making it frozen means that it doesn't get duped when used to
# key the @attributes in read_attribute.
- def define_method_attribute(name)
- safe_name = name.unpack("h*".freeze).first
- temp_method = "__temp__#{safe_name}"
+ def define_method_attribute(name)
+ safe_name = name.unpack("h*".freeze).first
+ temp_method = "__temp__#{safe_name}"
- ActiveRecord::AttributeMethods::AttrNames.set_name_cache safe_name, name
+ ActiveRecord::AttributeMethods::AttrNames.set_name_cache safe_name, name
- generated_attribute_methods.module_eval <<-STR, __FILE__, __LINE__ + 1
+ generated_attribute_methods.module_eval <<-STR, __FILE__, __LINE__ + 1
def #{temp_method}
name = ::ActiveRecord::AttributeMethods::AttrNames::ATTR_#{safe_name}
_read_attribute(name) { |n| missing_attribute(n, caller) }
end
STR
- generated_attribute_methods.module_eval do
- alias_method name, temp_method
- undef_method temp_method
+ generated_attribute_methods.module_eval do
+ alias_method name, temp_method
+ undef_method temp_method
+ end
end
- end
end
# Returns the value of the attribute identified by <tt>attr_name</tt> after
diff --git a/activerecord/lib/active_record/attribute_methods/serialization.rb b/activerecord/lib/active_record/attribute_methods/serialization.rb
index 65978aea2a..8fb29fb358 100644
--- a/activerecord/lib/active_record/attribute_methods/serialization.rb
+++ b/activerecord/lib/active_record/attribute_methods/serialization.rb
@@ -50,7 +50,7 @@ module ActiveRecord
# to ensure special objects (e.g. Active Record models) are dumped correctly
# using the #as_json hook.
coder = if class_name_or_coder == ::JSON
- Coders::JSON
+ Coders::JSON
elsif [:load, :dump].all? { |x| class_name_or_coder.respond_to?(x) }
class_name_or_coder
else
diff --git a/activerecord/lib/active_record/attribute_methods/time_zone_conversion.rb b/activerecord/lib/active_record/attribute_methods/time_zone_conversion.rb
index d7b5f8b262..ff9fd206c0 100644
--- a/activerecord/lib/active_record/attribute_methods/time_zone_conversion.rb
+++ b/activerecord/lib/active_record/attribute_methods/time_zone_conversion.rb
@@ -26,31 +26,31 @@ module ActiveRecord
private
- def convert_time_to_time_zone(value)
- return if value.nil?
+ def convert_time_to_time_zone(value)
+ return if value.nil?
- if value.acts_like?(:time)
- value.in_time_zone
- elsif value.is_a?(::Float)
- value
- else
- map_avoiding_infinite_recursion(value) { |v| convert_time_to_time_zone(v) }
+ if value.acts_like?(:time)
+ value.in_time_zone
+ elsif value.is_a?(::Float)
+ value
+ else
+ map_avoiding_infinite_recursion(value) { |v| convert_time_to_time_zone(v) }
+ end
end
- end
- def set_time_zone_without_conversion(value)
- ::Time.zone.local_to_utc(value).in_time_zone if value
- end
+ def set_time_zone_without_conversion(value)
+ ::Time.zone.local_to_utc(value).in_time_zone if value
+ end
- def map_avoiding_infinite_recursion(value)
- map(value) do |v|
- if value.equal?(v)
- nil
- else
- yield(v)
+ def map_avoiding_infinite_recursion(value)
+ map(value) do |v|
+ if value.equal?(v)
+ nil
+ else
+ yield(v)
+ end
end
end
- end
end
extend ActiveSupport::Concern
@@ -69,31 +69,31 @@ module ActiveRecord
module ClassMethods
private
- def inherited(subclass)
- # We need to apply this decorator here, rather than on module inclusion. The closure
- # created by the matcher would otherwise evaluate for `ActiveRecord::Base`, not the
- # sub class being decorated. As such, changes to `time_zone_aware_attributes`, or
- # `skip_time_zone_conversion_for_attributes` would not be picked up.
- subclass.class_eval do
- matcher = ->(name, type) { create_time_zone_conversion_attribute?(name, type) }
- decorate_matching_attribute_types(matcher, :_time_zone_conversion) do |type|
- TimeZoneConverter.new(type)
+ def inherited(subclass)
+ # We need to apply this decorator here, rather than on module inclusion. The closure
+ # created by the matcher would otherwise evaluate for `ActiveRecord::Base`, not the
+ # sub class being decorated. As such, changes to `time_zone_aware_attributes`, or
+ # `skip_time_zone_conversion_for_attributes` would not be picked up.
+ subclass.class_eval do
+ matcher = ->(name, type) { create_time_zone_conversion_attribute?(name, type) }
+ decorate_matching_attribute_types(matcher, :_time_zone_conversion) do |type|
+ TimeZoneConverter.new(type)
+ end
end
+ super
end
- super
- end
- def create_time_zone_conversion_attribute?(name, cast_type)
- enabled_for_column = time_zone_aware_attributes &&
- !self.skip_time_zone_conversion_for_attributes.include?(name.to_sym)
- result = enabled_for_column &&
- time_zone_aware_types.include?(cast_type.type)
-
- if enabled_for_column &&
- !result &&
- cast_type.type == :time &&
- time_zone_aware_types.include?(:not_explicitly_configured)
- ActiveSupport::Deprecation.warn(<<-MESSAGE.strip_heredoc)
+ def create_time_zone_conversion_attribute?(name, cast_type)
+ enabled_for_column = time_zone_aware_attributes &&
+ !self.skip_time_zone_conversion_for_attributes.include?(name.to_sym)
+ result = enabled_for_column &&
+ time_zone_aware_types.include?(cast_type.type)
+
+ if enabled_for_column &&
+ !result &&
+ cast_type.type == :time &&
+ time_zone_aware_types.include?(:not_explicitly_configured)
+ ActiveSupport::Deprecation.warn(<<-MESSAGE.strip_heredoc)
Time columns will become time zone aware in Rails 5.1. This
still causes `String`s to be parsed as if they were in `Time.zone`,
and `Time`s to be converted to `Time.zone`.
@@ -106,10 +106,10 @@ module ActiveRecord
config.active_record.time_zone_aware_types = [:datetime, :time]
MESSAGE
- end
+ end
- result
- end
+ result
+ end
end
end
end
diff --git a/activerecord/lib/active_record/attribute_methods/write.rb b/activerecord/lib/active_record/attribute_methods/write.rb
index e7f62197c3..5822414129 100644
--- a/activerecord/lib/active_record/attribute_methods/write.rb
+++ b/activerecord/lib/active_record/attribute_methods/write.rb
@@ -10,11 +10,11 @@ module ActiveRecord
module ClassMethods
protected
- def define_method_attribute=(name)
- safe_name = name.unpack("h*".freeze).first
- ActiveRecord::AttributeMethods::AttrNames.set_name_cache safe_name, name
+ def define_method_attribute=(name)
+ safe_name = name.unpack("h*".freeze).first
+ ActiveRecord::AttributeMethods::AttrNames.set_name_cache safe_name, name
- generated_attribute_methods.module_eval <<-STR, __FILE__, __LINE__ + 1
+ generated_attribute_methods.module_eval <<-STR, __FILE__, __LINE__ + 1
def __temp__#{safe_name}=(value)
name = ::ActiveRecord::AttributeMethods::AttrNames::ATTR_#{safe_name}
write_attribute(name, value)
@@ -22,7 +22,7 @@ module ActiveRecord
alias_method #{(name + '=').inspect}, :__temp__#{safe_name}=
undef_method :__temp__#{safe_name}=
STR
- end
+ end
end
# Updates the attribute identified by <tt>attr_name</tt> with the
@@ -38,22 +38,22 @@ module ActiveRecord
private
# Handle *= for method_missing.
- def attribute=(attribute_name, value)
- write_attribute(attribute_name, value)
- end
+ def attribute=(attribute_name, value)
+ write_attribute(attribute_name, value)
+ end
- def write_attribute_with_type_cast(attr_name, value, should_type_cast)
- attr_name = attr_name.to_s
- attr_name = self.class.primary_key if attr_name == "id" && self.class.primary_key
+ def write_attribute_with_type_cast(attr_name, value, should_type_cast)
+ attr_name = attr_name.to_s
+ attr_name = self.class.primary_key if attr_name == "id" && self.class.primary_key
- if should_type_cast
- @attributes.write_from_user(attr_name, value)
- else
- @attributes.write_cast_value(attr_name, value)
- end
+ if should_type_cast
+ @attributes.write_from_user(attr_name, value)
+ else
+ @attributes.write_cast_value(attr_name, value)
+ end
- value
- end
+ value
+ end
end
end
end
diff --git a/activerecord/lib/active_record/attribute_mutation_tracker.rb b/activerecord/lib/active_record/attribute_mutation_tracker.rb
index 0133b4d0be..c257aef52f 100644
--- a/activerecord/lib/active_record/attribute_mutation_tracker.rb
+++ b/activerecord/lib/active_record/attribute_mutation_tracker.rb
@@ -36,13 +36,13 @@ module ActiveRecord
protected
- attr_reader :attributes
+ attr_reader :attributes
private
- def attr_names
- attributes.keys
- end
+ def attr_names
+ attributes.keys
+ end
end
class NullMutationTracker # :nodoc:
diff --git a/activerecord/lib/active_record/attribute_set.rb b/activerecord/lib/active_record/attribute_set.rb
index fd569d869a..5bde1f107c 100644
--- a/activerecord/lib/active_record/attribute_set.rb
+++ b/activerecord/lib/active_record/attribute_set.rb
@@ -100,12 +100,12 @@ module ActiveRecord
protected
- attr_reader :attributes
+ attr_reader :attributes
private
- def initialized_attributes
- attributes.select { |_, attr| attr.initialized? }
- end
+ def initialized_attributes
+ attributes.select { |_, attr| attr.initialized? }
+ end
end
end
diff --git a/activerecord/lib/active_record/attribute_set/builder.rb b/activerecord/lib/active_record/attribute_set/builder.rb
index b4d98ca3c0..661f996e1a 100644
--- a/activerecord/lib/active_record/attribute_set/builder.rb
+++ b/activerecord/lib/active_record/attribute_set/builder.rb
@@ -92,31 +92,31 @@ module ActiveRecord
protected
- attr_reader :types, :values, :additional_types, :delegate_hash, :default
-
- def materialize
- unless @materialized
- values.each_key { |key| self[key] }
- types.each_key { |key| self[key] }
- unless frozen?
- @materialized = true
+ attr_reader :types, :values, :additional_types, :delegate_hash, :default
+
+ def materialize
+ unless @materialized
+ values.each_key { |key| self[key] }
+ types.each_key { |key| self[key] }
+ unless frozen?
+ @materialized = true
+ end
end
+ delegate_hash
end
- delegate_hash
- end
private
- def assign_default_value(name)
- type = additional_types.fetch(name, types[name])
- value_present = true
- value = values.fetch(name) { value_present = false }
+ def assign_default_value(name)
+ type = additional_types.fetch(name, types[name])
+ value_present = true
+ value = values.fetch(name) { value_present = false }
- if value_present
- delegate_hash[name] = Attribute.from_database(name, value, type)
- elsif types.key?(name)
- delegate_hash[name] = default.call(name) || Attribute.uninitialized(name, type)
+ if value_present
+ delegate_hash[name] = Attribute.from_database(name, value, type)
+ elsif types.key?(name)
+ delegate_hash[name] = default.call(name) || Attribute.uninitialized(name, type)
+ end
end
- end
end
end
diff --git a/activerecord/lib/active_record/attribute_set/yaml_encoder.rb b/activerecord/lib/active_record/attribute_set/yaml_encoder.rb
index 52ffe719f4..c86cfc4263 100644
--- a/activerecord/lib/active_record/attribute_set/yaml_encoder.rb
+++ b/activerecord/lib/active_record/attribute_set/yaml_encoder.rb
@@ -33,7 +33,7 @@ module ActiveRecord
protected
- attr_reader :default_types
+ attr_reader :default_types
end
end
end
diff --git a/activerecord/lib/active_record/attributes.rb b/activerecord/lib/active_record/attributes.rb
index 880d9a2b84..4b92e5835f 100644
--- a/activerecord/lib/active_record/attributes.rb
+++ b/activerecord/lib/active_record/attributes.rb
@@ -242,24 +242,24 @@ module ActiveRecord
private
- NO_DEFAULT_PROVIDED = Object.new # :nodoc:
- private_constant :NO_DEFAULT_PROVIDED
+ NO_DEFAULT_PROVIDED = Object.new # :nodoc:
+ private_constant :NO_DEFAULT_PROVIDED
- def define_default_attribute(name, value, type, from_user:)
- if value == NO_DEFAULT_PROVIDED
- default_attribute = _default_attributes[name].with_type(type)
- elsif from_user
- default_attribute = Attribute::UserProvidedDefault.new(
- name,
- value,
- type,
- _default_attributes.fetch(name.to_s) { nil },
- )
- else
- default_attribute = Attribute.from_database(name, value, type)
+ def define_default_attribute(name, value, type, from_user:)
+ if value == NO_DEFAULT_PROVIDED
+ default_attribute = _default_attributes[name].with_type(type)
+ elsif from_user
+ default_attribute = Attribute::UserProvidedDefault.new(
+ name,
+ value,
+ type,
+ _default_attributes.fetch(name.to_s) { nil },
+ )
+ else
+ default_attribute = Attribute.from_database(name, value, type)
+ end
+ _default_attributes[name] = default_attribute
end
- _default_attributes[name] = default_attribute
- end
end
end
end
diff --git a/activerecord/lib/active_record/coders/yaml_column.rb b/activerecord/lib/active_record/coders/yaml_column.rb
index 8b98d9ccd7..ee38172742 100644
--- a/activerecord/lib/active_record/coders/yaml_column.rb
+++ b/activerecord/lib/active_record/coders/yaml_column.rb
@@ -39,13 +39,13 @@ module ActiveRecord
private
- def check_arity_of_constructor
- begin
- load(nil)
- rescue ArgumentError
- raise ArgumentError, "Cannot serialize #{object_class}. Classes passed to `serialize` must have a 0 argument constructor."
+ def check_arity_of_constructor
+ begin
+ load(nil)
+ rescue ArgumentError
+ raise ArgumentError, "Cannot serialize #{object_class}. Classes passed to `serialize` must have a 0 argument constructor."
+ end
end
- end
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 db798bc303..535d79b525 100644
--- a/activerecord/lib/active_record/connection_adapters/abstract/connection_pool.rb
+++ b/activerecord/lib/active_record/connection_adapters/abstract/connection_pool.rb
@@ -150,61 +150,61 @@ module ActiveRecord
private
- def internal_poll(timeout)
- no_wait_poll || (timeout && wait_poll(timeout))
- end
+ def internal_poll(timeout)
+ no_wait_poll || (timeout && wait_poll(timeout))
+ end
- def synchronize(&block)
- @lock.synchronize(&block)
- end
+ def synchronize(&block)
+ @lock.synchronize(&block)
+ end
# Test if the queue currently contains any elements.
- def any?
- !@queue.empty?
- end
+ def any?
+ !@queue.empty?
+ end
# A thread can remove an element from the queue without
# waiting if and only if the number of currently available
# connections is strictly greater than the number of waiting
# threads.
- def can_remove_no_wait?
- @queue.size > @num_waiting
- end
+ def can_remove_no_wait?
+ @queue.size > @num_waiting
+ end
# Removes and returns the head of the queue if possible, or nil.
- def remove
- @queue.shift
- end
+ def remove
+ @queue.shift
+ end
# Remove and return the head the queue if the number of
# available elements is strictly greater than the number of
# threads currently waiting. Otherwise, return nil.
- def no_wait_poll
- remove if can_remove_no_wait?
- end
+ def no_wait_poll
+ remove if can_remove_no_wait?
+ end
# Waits on the queue up to +timeout+ seconds, then removes and
# returns the head of the queue.
- def wait_poll(timeout)
- @num_waiting += 1
+ def wait_poll(timeout)
+ @num_waiting += 1
- t0 = Time.now
- elapsed = 0
- loop do
- @cond.wait(timeout - elapsed)
+ t0 = Time.now
+ elapsed = 0
+ loop do
+ @cond.wait(timeout - elapsed)
- return remove if any?
+ return remove if any?
- elapsed = Time.now - t0
- if elapsed >= timeout
- msg = "could not obtain a connection from the pool within %0.3f seconds (waited %0.3f seconds); all pooled connections were in use" %
- [timeout, elapsed]
- raise ConnectionTimeoutError, msg
+ elapsed = Time.now - t0
+ if elapsed >= timeout
+ msg = "could not obtain a connection from the pool within %0.3f seconds (waited %0.3f seconds); all pooled connections were in use" %
+ [timeout, elapsed]
+ raise ConnectionTimeoutError, msg
+ end
end
+ ensure
+ @num_waiting -= 1
end
- ensure
- @num_waiting -= 1
- end
end
# Adds the ability to turn a basic fair FIFO queue into one
@@ -274,11 +274,11 @@ module ActiveRecord
include BiasableQueue
private
- def internal_poll(timeout)
- conn = super
- conn.lease if conn
- conn
- end
+ def internal_poll(timeout)
+ conn = super
+ conn.lease if conn
+ conn
+ end
end
# Every +frequency+ seconds, the reaper will call +reap+ on +pool+.
@@ -584,111 +584,111 @@ module ActiveRecord
private
#--
# this is unfortunately not concurrent
- def bulk_make_new_connections(num_new_conns_needed)
- num_new_conns_needed.times do
- # try_to_checkout_new_connection will not exceed pool's @size limit
- if new_conn = try_to_checkout_new_connection
- # make the new_conn available to the starving threads stuck @available Queue
- checkin(new_conn)
+ def bulk_make_new_connections(num_new_conns_needed)
+ num_new_conns_needed.times do
+ # try_to_checkout_new_connection will not exceed pool's @size limit
+ if new_conn = try_to_checkout_new_connection
+ # make the new_conn available to the starving threads stuck @available Queue
+ checkin(new_conn)
+ end
end
end
- end
#--
# From the discussion on GitHub:
# https://github.com/rails/rails/pull/14938#commitcomment-6601951
# This hook-in method allows for easier monkey-patching fixes needed by
# JRuby users that use Fibers.
- def connection_cache_key(thread)
- thread
- end
+ def connection_cache_key(thread)
+ thread
+ end
# Take control of all existing connections so a "group" action such as
# reload/disconnect can be performed safely. It is no longer enough to
# wrap it in +synchronize+ because some pool's actions are allowed
# to be performed outside of the main +synchronize+ block.
- def with_exclusively_acquired_all_connections(raise_on_acquisition_timeout = true)
- with_new_connections_blocked do
- attempt_to_checkout_all_existing_connections(raise_on_acquisition_timeout)
- yield
+ def with_exclusively_acquired_all_connections(raise_on_acquisition_timeout = true)
+ with_new_connections_blocked do
+ attempt_to_checkout_all_existing_connections(raise_on_acquisition_timeout)
+ yield
+ end
end
- end
- def attempt_to_checkout_all_existing_connections(raise_on_acquisition_timeout = true)
- collected_conns = synchronize do
- # account for our own connections
- @connections.select {|conn| conn.owner == Thread.current}
- end
+ def attempt_to_checkout_all_existing_connections(raise_on_acquisition_timeout = true)
+ collected_conns = synchronize do
+ # account for our own connections
+ @connections.select {|conn| conn.owner == Thread.current}
+ end
- newly_checked_out = []
- timeout_time = Time.now + (@checkout_timeout * 2)
+ newly_checked_out = []
+ timeout_time = Time.now + (@checkout_timeout * 2)
- @available.with_a_bias_for(Thread.current) do
- loop do
- synchronize do
- return if collected_conns.size == @connections.size && @now_connecting == 0
- remaining_timeout = timeout_time - Time.now
- remaining_timeout = 0 if remaining_timeout < 0
- conn = checkout_for_exclusive_access(remaining_timeout)
- collected_conns << conn
- newly_checked_out << conn
+ @available.with_a_bias_for(Thread.current) do
+ loop do
+ synchronize do
+ return if collected_conns.size == @connections.size && @now_connecting == 0
+ remaining_timeout = timeout_time - Time.now
+ remaining_timeout = 0 if remaining_timeout < 0
+ conn = checkout_for_exclusive_access(remaining_timeout)
+ collected_conns << conn
+ newly_checked_out << conn
+ end
end
end
- end
- rescue ExclusiveConnectionTimeoutError
- # <tt>raise_on_acquisition_timeout == false</tt> means we are directed to ignore any
- # timeouts and are expected to just give up: we've obtained as many connections
- # as possible, note that in a case like that we don't return any of the
- # +newly_checked_out+ connections.
-
- if raise_on_acquisition_timeout
+ rescue ExclusiveConnectionTimeoutError
+ # <tt>raise_on_acquisition_timeout == false</tt> means we are directed to ignore any
+ # timeouts and are expected to just give up: we've obtained as many connections
+ # as possible, note that in a case like that we don't return any of the
+ # +newly_checked_out+ connections.
+
+ if raise_on_acquisition_timeout
+ release_newly_checked_out = true
+ raise
+ end
+ rescue Exception # if something else went wrong
+ # this can't be a "naked" rescue, because we have should return conns
+ # even for non-StandardErrors
release_newly_checked_out = true
raise
+ ensure
+ if release_newly_checked_out && newly_checked_out
+ # releasing only those conns that were checked out in this method, conns
+ # checked outside this method (before it was called) are not for us to release
+ newly_checked_out.each {|conn| checkin(conn)}
+ end
end
- rescue Exception # if something else went wrong
- # this can't be a "naked" rescue, because we have should return conns
- # even for non-StandardErrors
- release_newly_checked_out = true
- raise
- ensure
- if release_newly_checked_out && newly_checked_out
- # releasing only those conns that were checked out in this method, conns
- # checked outside this method (before it was called) are not for us to release
- newly_checked_out.each {|conn| checkin(conn)}
- end
- end
#--
# Must be called in a synchronize block.
- def checkout_for_exclusive_access(checkout_timeout)
- checkout(checkout_timeout)
- rescue ConnectionTimeoutError
- # this block can't be easily moved into attempt_to_checkout_all_existing_connections's
- # rescue block, because doing so would put it outside of synchronize section, without
- # being in a critical section thread_report might become inaccurate
- msg = "could not obtain ownership of all database connections in #{checkout_timeout} seconds"
-
- thread_report = []
- @connections.each do |conn|
- unless conn.owner == Thread.current
- thread_report << "#{conn} is owned by #{conn.owner}"
+ def checkout_for_exclusive_access(checkout_timeout)
+ checkout(checkout_timeout)
+ rescue ConnectionTimeoutError
+ # this block can't be easily moved into attempt_to_checkout_all_existing_connections's
+ # rescue block, because doing so would put it outside of synchronize section, without
+ # being in a critical section thread_report might become inaccurate
+ msg = "could not obtain ownership of all database connections in #{checkout_timeout} seconds"
+
+ thread_report = []
+ @connections.each do |conn|
+ unless conn.owner == Thread.current
+ thread_report << "#{conn} is owned by #{conn.owner}"
+ end
end
- end
- msg << " (#{thread_report.join(', ')})" if thread_report.any?
+ msg << " (#{thread_report.join(', ')})" if thread_report.any?
- raise ExclusiveConnectionTimeoutError, msg
- end
+ raise ExclusiveConnectionTimeoutError, msg
+ end
- def with_new_connections_blocked
- previous_value = nil
- synchronize do
- previous_value, @new_cons_enabled = @new_cons_enabled, false
+ def with_new_connections_blocked
+ previous_value = nil
+ synchronize do
+ previous_value, @new_cons_enabled = @new_cons_enabled, false
+ end
+ yield
+ ensure
+ synchronize { @new_cons_enabled = previous_value }
end
- yield
- ensure
- synchronize { @new_cons_enabled = previous_value }
- end
# Acquire a connection by one of 1) immediately removing one
# from the queue of available connections, 2) creating a new
@@ -701,86 +701,86 @@ module ActiveRecord
#--
# Implementation detail: the connection returned by +acquire_connection+
# will already be "+connection.lease+ -ed" to the current thread.
- def acquire_connection(checkout_timeout)
- # NOTE: we rely on +@available.poll+ and +try_to_checkout_new_connection+ to
- # +conn.lease+ the returned connection (and to do this in a +synchronized+
- # section). This is not the cleanest implementation, as ideally we would
- # <tt>synchronize { conn.lease }</tt> in this method, but by leaving it to +@available.poll+
- # and +try_to_checkout_new_connection+ we can piggyback on +synchronize+ sections
- # of the said methods and avoid an additional +synchronize+ overhead.
- if conn = @available.poll || try_to_checkout_new_connection
- conn
- else
- reap
- @available.poll(checkout_timeout)
+ def acquire_connection(checkout_timeout)
+ # NOTE: we rely on +@available.poll+ and +try_to_checkout_new_connection+ to
+ # +conn.lease+ the returned connection (and to do this in a +synchronized+
+ # section). This is not the cleanest implementation, as ideally we would
+ # <tt>synchronize { conn.lease }</tt> in this method, but by leaving it to +@available.poll+
+ # and +try_to_checkout_new_connection+ we can piggyback on +synchronize+ sections
+ # of the said methods and avoid an additional +synchronize+ overhead.
+ if conn = @available.poll || try_to_checkout_new_connection
+ conn
+ else
+ reap
+ @available.poll(checkout_timeout)
+ end
end
- end
#--
# if owner_thread param is omitted, this must be called in synchronize block
- def remove_connection_from_thread_cache(conn, owner_thread = conn.owner)
- @thread_cached_conns.delete_pair(connection_cache_key(owner_thread), conn)
- end
- alias_method :release, :remove_connection_from_thread_cache
+ def remove_connection_from_thread_cache(conn, owner_thread = conn.owner)
+ @thread_cached_conns.delete_pair(connection_cache_key(owner_thread), conn)
+ end
+ alias_method :release, :remove_connection_from_thread_cache
- def new_connection
- Base.send(spec.adapter_method, spec.config).tap do |conn|
- conn.schema_cache = schema_cache.dup if schema_cache
+ def new_connection
+ Base.send(spec.adapter_method, spec.config).tap do |conn|
+ conn.schema_cache = schema_cache.dup if schema_cache
+ end
end
- end
# If the pool is not at a +@size+ limit, establish new connection. Connecting
# to the DB is done outside main synchronized section.
#--
# Implementation constraint: a newly established connection returned by this
# method must be in the +.leased+ state.
- def try_to_checkout_new_connection
- # first in synchronized section check if establishing new conns is allowed
- # and increment @now_connecting, to prevent overstepping this pool's @size
- # constraint
- do_checkout = synchronize do
- if @new_cons_enabled && (@connections.size + @now_connecting) < @size
- @now_connecting += 1
- end
- end
- if do_checkout
- begin
- # if successfully incremented @now_connecting establish new connection
- # outside of synchronized section
- conn = checkout_new_connection
- ensure
- synchronize do
- if conn
- adopt_connection(conn)
- # returned conn needs to be already leased
- conn.lease
+ def try_to_checkout_new_connection
+ # first in synchronized section check if establishing new conns is allowed
+ # and increment @now_connecting, to prevent overstepping this pool's @size
+ # constraint
+ do_checkout = synchronize do
+ if @new_cons_enabled && (@connections.size + @now_connecting) < @size
+ @now_connecting += 1
+ end
+ end
+ if do_checkout
+ begin
+ # if successfully incremented @now_connecting establish new connection
+ # outside of synchronized section
+ conn = checkout_new_connection
+ ensure
+ synchronize do
+ if conn
+ adopt_connection(conn)
+ # returned conn needs to be already leased
+ conn.lease
+ end
+ @now_connecting -= 1
end
- @now_connecting -= 1
end
end
end
- end
- def adopt_connection(conn)
- conn.pool = self
- @connections << conn
- end
+ def adopt_connection(conn)
+ conn.pool = self
+ @connections << conn
+ end
- def checkout_new_connection
- raise ConnectionNotEstablished unless @automatic_reconnect
- new_connection
- end
+ def checkout_new_connection
+ raise ConnectionNotEstablished unless @automatic_reconnect
+ new_connection
+ end
- def checkout_and_verify(c)
- c._run_checkout_callbacks do
- c.verify!
+ def checkout_and_verify(c)
+ c._run_checkout_callbacks do
+ c.verify!
+ end
+ c
+ rescue
+ remove c
+ c.disconnect!
+ raise
end
- c
- rescue
- remove c
- c.disconnect!
- raise
- end
end
# ConnectionHandler is a collection of ConnectionPool objects. It is used
@@ -942,14 +942,14 @@ module ActiveRecord
private
- def owner_to_pool
- @owner_to_pool[Process.pid]
- end
+ def owner_to_pool
+ @owner_to_pool[Process.pid]
+ end
- def pool_from_any_process_for(spec_name)
- owner_to_pool = @owner_to_pool.values.find { |v| v[spec_name] }
- owner_to_pool && owner_to_pool[spec_name]
- end
+ def pool_from_any_process_for(spec_name)
+ owner_to_pool = @owner_to_pool.values.find { |v| v[spec_name] }
+ owner_to_pool && owner_to_pool[spec_name]
+ end
end
end
end
diff --git a/activerecord/lib/active_record/connection_adapters/abstract/query_cache.rb b/activerecord/lib/active_record/connection_adapters/abstract/query_cache.rb
index 47f24df22f..10c60080d5 100644
--- a/activerecord/lib/active_record/connection_adapters/abstract/query_cache.rb
+++ b/activerecord/lib/active_record/connection_adapters/abstract/query_cache.rb
@@ -73,23 +73,23 @@ module ActiveRecord
private
- def cache_sql(sql, binds)
- result =
- if @query_cache[sql].key?(binds)
- ActiveSupport::Notifications.instrument("sql.active_record",
- sql: sql, binds: binds, name: "CACHE", connection_id: object_id)
- @query_cache[sql][binds]
- else
- @query_cache[sql][binds] = yield
- end
- result.dup
- end
+ def cache_sql(sql, binds)
+ result =
+ if @query_cache[sql].key?(binds)
+ ActiveSupport::Notifications.instrument("sql.active_record",
+ sql: sql, binds: binds, name: "CACHE", connection_id: object_id)
+ @query_cache[sql][binds]
+ else
+ @query_cache[sql][binds] = yield
+ end
+ result.dup
+ end
# If arel is locked this is a SELECT ... FOR UPDATE or somesuch. Such
# queries should not be cached.
- def locked?(arel)
- arel.respond_to?(:locked) && arel.locked
- end
+ def locked?(arel)
+ arel.respond_to?(:locked) && arel.locked
+ end
end
end
end
diff --git a/activerecord/lib/active_record/connection_adapters/abstract/quoting.rb b/activerecord/lib/active_record/connection_adapters/abstract/quoting.rb
index 20d009bbf8..bbd52b8a91 100644
--- a/activerecord/lib/active_record/connection_adapters/abstract/quoting.rb
+++ b/activerecord/lib/active_record/connection_adapters/abstract/quoting.rb
@@ -152,47 +152,47 @@ module ActiveRecord
private
- def type_casted_binds(binds)
- binds.map { |attr| type_cast(attr.value_for_database) }
- end
-
- def types_which_need_no_typecasting
- [nil, Numeric, String]
- end
-
- def _quote(value)
- case value
- when String, ActiveSupport::Multibyte::Chars, Type::Binary::Data
- "'#{quote_string(value.to_s)}'"
- when true then quoted_true
- when false then quoted_false
- when nil then "NULL"
- # BigDecimals need to be put in a non-normalized form and quoted.
- when BigDecimal then value.to_s("F")
- when Numeric, ActiveSupport::Duration then value.to_s
- when Type::Time::Value then "'#{quoted_time(value)}'"
- when Date, Time then "'#{quoted_date(value)}'"
- when Symbol then "'#{quote_string(value.to_s)}'"
- when Class then "'#{value}'"
- else raise TypeError, "can't quote #{value.class.name}"
+ def type_casted_binds(binds)
+ binds.map { |attr| type_cast(attr.value_for_database) }
end
- end
- def _type_cast(value)
- case value
- when Symbol, ActiveSupport::Multibyte::Chars, Type::Binary::Data
- value.to_s
- when true then unquoted_true
- when false then unquoted_false
- # BigDecimals need to be put in a non-normalized form and quoted.
- when BigDecimal then value.to_s("F")
- when Type::Time::Value then quoted_time(value)
- when Date, Time then quoted_date(value)
- when *types_which_need_no_typecasting
- value
- else raise TypeError
+ def types_which_need_no_typecasting
+ [nil, Numeric, String]
+ end
+
+ def _quote(value)
+ case value
+ when String, ActiveSupport::Multibyte::Chars, Type::Binary::Data
+ "'#{quote_string(value.to_s)}'"
+ when true then quoted_true
+ when false then quoted_false
+ when nil then "NULL"
+ # BigDecimals need to be put in a non-normalized form and quoted.
+ when BigDecimal then value.to_s("F")
+ when Numeric, ActiveSupport::Duration then value.to_s
+ when Type::Time::Value then "'#{quoted_time(value)}'"
+ when Date, Time then "'#{quoted_date(value)}'"
+ when Symbol then "'#{quote_string(value.to_s)}'"
+ when Class then "'#{value}'"
+ else raise TypeError, "can't quote #{value.class.name}"
+ end
+ end
+
+ def _type_cast(value)
+ case value
+ when Symbol, ActiveSupport::Multibyte::Chars, Type::Binary::Data
+ value.to_s
+ when true then unquoted_true
+ when false then unquoted_false
+ # BigDecimals need to be put in a non-normalized form and quoted.
+ when BigDecimal then value.to_s("F")
+ when Type::Time::Value then quoted_time(value)
+ when Date, Time then quoted_date(value)
+ when *types_which_need_no_typecasting
+ value
+ else raise TypeError
+ end
end
- end
end
end
end
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 c1fc99ce1f..1d18a58eab 100644
--- a/activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb
+++ b/activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb
@@ -61,9 +61,9 @@ module ActiveRecord
end
private
- def default_primary_key
- "id"
- end
+ def default_primary_key
+ "id"
+ end
end
class ReferenceDefinition # :nodoc:
@@ -103,51 +103,51 @@ module ActiveRecord
protected
- attr_reader :name, :polymorphic, :index, :foreign_key, :type, :options
+ attr_reader :name, :polymorphic, :index, :foreign_key, :type, :options
private
- def as_options(value, default = {})
- if value.is_a?(Hash)
- value
- else
- default
+ def as_options(value, default = {})
+ if value.is_a?(Hash)
+ value
+ else
+ default
+ end
end
- end
- def polymorphic_options
- as_options(polymorphic, options)
- end
+ def polymorphic_options
+ as_options(polymorphic, options)
+ end
- def index_options
- as_options(index)
- end
+ def index_options
+ as_options(index)
+ end
- def foreign_key_options
- as_options(foreign_key).merge(column: column_name)
- end
+ def foreign_key_options
+ as_options(foreign_key).merge(column: column_name)
+ end
- def columns
- result = [[column_name, type, options]]
- if polymorphic
- result.unshift(["#{name}_type", :string, polymorphic_options])
+ def columns
+ result = [[column_name, type, options]]
+ if polymorphic
+ result.unshift(["#{name}_type", :string, polymorphic_options])
+ end
+ result
end
- result
- end
- def column_name
- "#{name}_id"
- end
+ def column_name
+ "#{name}_id"
+ end
- def column_names
- columns.map(&:first)
- end
+ def column_names
+ columns.map(&:first)
+ end
- def foreign_table_name
- foreign_key_options.fetch(:to_table) do
- Base.pluralize_table_names ? name.to_s.pluralize : name
+ def foreign_table_name
+ foreign_key_options.fetch(:to_table) do
+ Base.pluralize_table_names ? name.to_s.pluralize : name
+ end
end
- end
end
module ColumnMethods
@@ -383,13 +383,13 @@ module ActiveRecord
end
private
- def create_column_definition(name, type)
- ColumnDefinition.new name, type
- end
+ def create_column_definition(name, type)
+ ColumnDefinition.new name, type
+ end
- def aliased_types(name, fallback)
- "timestamp" == name ? :datetime : fallback
- end
+ def aliased_types(name, fallback)
+ "timestamp" == name ? :datetime : fallback
+ end
end
class AlterTable # :nodoc:
diff --git a/activerecord/lib/active_record/connection_adapters/abstract/schema_dumper.rb b/activerecord/lib/active_record/connection_adapters/abstract/schema_dumper.rb
index 321e08c5ca..8bb7362c2e 100644
--- a/activerecord/lib/active_record/connection_adapters/abstract/schema_dumper.rb
+++ b/activerecord/lib/active_record/connection_adapters/abstract/schema_dumper.rb
@@ -58,48 +58,48 @@ module ActiveRecord
private
- def default_primary_key?(column)
- schema_type(column) == :integer
- end
+ def default_primary_key?(column)
+ schema_type(column) == :integer
+ end
- def schema_type(column)
- if column.bigint?
- :bigint
- else
- column.type
+ def schema_type(column)
+ if column.bigint?
+ :bigint
+ else
+ column.type
+ end
end
- end
- def schema_limit(column)
- limit = column.limit unless column.bigint?
- limit.inspect if limit && limit != native_database_types[column.type][:limit]
- end
+ def schema_limit(column)
+ limit = column.limit unless column.bigint?
+ limit.inspect if limit && limit != native_database_types[column.type][:limit]
+ end
- def schema_precision(column)
- column.precision.inspect if column.precision
- end
+ def schema_precision(column)
+ column.precision.inspect if column.precision
+ end
- def schema_scale(column)
- column.scale.inspect if column.scale
- end
+ def schema_scale(column)
+ column.scale.inspect if column.scale
+ end
- def schema_default(column)
- type = lookup_cast_type_from_column(column)
- default = type.deserialize(column.default)
- if default.nil?
- schema_expression(column)
- else
- type.type_cast_for_schema(default)
+ def schema_default(column)
+ type = lookup_cast_type_from_column(column)
+ default = type.deserialize(column.default)
+ if default.nil?
+ schema_expression(column)
+ else
+ type.type_cast_for_schema(default)
+ end
end
- end
- def schema_expression(column)
- "-> { #{column.default_function.inspect} }" if column.default_function
- end
+ def schema_expression(column)
+ "-> { #{column.default_function.inspect} }" if column.default_function
+ end
- def schema_collation(column)
- column.collation.inspect if column.collation
- end
+ def schema_collation(column)
+ column.collation.inspect if column.collation
+ end
end
end
end
diff --git a/activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb b/activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb
index f2134fe035..d2ebc36fff 100644
--- a/activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb
+++ b/activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb
@@ -1245,49 +1245,49 @@ module ActiveRecord
end
private
- def create_table_definition(*args)
- TableDefinition.new(*args)
- end
-
- def create_alter_table(name)
- AlterTable.new create_table_definition(name)
- end
+ def create_table_definition(*args)
+ TableDefinition.new(*args)
+ end
- def index_name_options(column_names) # :nodoc:
- if column_names.is_a?(String)
- column_names = column_names.scan(/\w+/).join("_")
+ def create_alter_table(name)
+ AlterTable.new create_table_definition(name)
end
- { column: column_names }
- end
+ def index_name_options(column_names) # :nodoc:
+ if column_names.is_a?(String)
+ column_names = column_names.scan(/\w+/).join("_")
+ end
- def foreign_key_name(table_name, options) # :nodoc:
- identifier = "#{table_name}_#{options.fetch(:column)}_fk"
- hashed_identifier = Digest::SHA256.hexdigest(identifier).first(10)
- options.fetch(:name) do
- "fk_rails_#{hashed_identifier}"
+ { column: column_names }
+ end
+
+ def foreign_key_name(table_name, options) # :nodoc:
+ identifier = "#{table_name}_#{options.fetch(:column)}_fk"
+ hashed_identifier = Digest::SHA256.hexdigest(identifier).first(10)
+ options.fetch(:name) do
+ "fk_rails_#{hashed_identifier}"
+ end
end
- end
- def validate_index_length!(table_name, new_name, internal = false) # :nodoc:
- max_index_length = internal ? index_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"
+ 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
- end
- def extract_new_default_value(default_or_changes)
- if default_or_changes.is_a?(Hash) && default_or_changes.has_key?(:from) && default_or_changes.has_key?(:to)
- default_or_changes[:to]
- else
- default_or_changes
+ def extract_new_default_value(default_or_changes)
+ if default_or_changes.is_a?(Hash) && default_or_changes.has_key?(:from) && default_or_changes.has_key?(:to)
+ default_or_changes[:to]
+ else
+ default_or_changes
+ end
end
- end
- def can_remove_index_by_name?(options)
- options.is_a?(Hash) && options.key?(:name) && options.except(:name, :algorithm).empty?
- end
+ def can_remove_index_by_name?(options)
+ options.is_a?(Hash) && options.key?(:name) && options.except(:name, :algorithm).empty?
+ end
end
end
end
diff --git a/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb b/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb
index 7ba3b5f43b..8a2a1fafb1 100644
--- a/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb
+++ b/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb
@@ -497,115 +497,115 @@ module ActiveRecord
protected
- def initialize_type_map(m) # :nodoc:
- register_class_with_limit m, %r(boolean)i, Type::Boolean
- register_class_with_limit m, %r(char)i, Type::String
- register_class_with_limit m, %r(binary)i, Type::Binary
- register_class_with_limit m, %r(text)i, Type::Text
- register_class_with_precision m, %r(date)i, Type::Date
- register_class_with_precision m, %r(time)i, Type::Time
- register_class_with_precision m, %r(datetime)i, Type::DateTime
- register_class_with_limit m, %r(float)i, Type::Float
- register_class_with_limit m, %r(int)i, Type::Integer
-
- m.alias_type %r(blob)i, "binary"
- m.alias_type %r(clob)i, "text"
- m.alias_type %r(timestamp)i, "datetime"
- m.alias_type %r(numeric)i, "decimal"
- m.alias_type %r(number)i, "decimal"
- m.alias_type %r(double)i, "float"
-
- m.register_type(%r(decimal)i) do |sql_type|
- scale = extract_scale(sql_type)
- precision = extract_precision(sql_type)
-
- if scale == 0
- # FIXME: Remove this class as well
- Type::DecimalWithoutScale.new(precision: precision)
- else
- Type::Decimal.new(precision: precision, scale: scale)
+ def initialize_type_map(m) # :nodoc:
+ register_class_with_limit m, %r(boolean)i, Type::Boolean
+ register_class_with_limit m, %r(char)i, Type::String
+ register_class_with_limit m, %r(binary)i, Type::Binary
+ register_class_with_limit m, %r(text)i, Type::Text
+ register_class_with_precision m, %r(date)i, Type::Date
+ register_class_with_precision m, %r(time)i, Type::Time
+ register_class_with_precision m, %r(datetime)i, Type::DateTime
+ register_class_with_limit m, %r(float)i, Type::Float
+ register_class_with_limit m, %r(int)i, Type::Integer
+
+ m.alias_type %r(blob)i, "binary"
+ m.alias_type %r(clob)i, "text"
+ m.alias_type %r(timestamp)i, "datetime"
+ m.alias_type %r(numeric)i, "decimal"
+ m.alias_type %r(number)i, "decimal"
+ m.alias_type %r(double)i, "float"
+
+ m.register_type(%r(decimal)i) do |sql_type|
+ scale = extract_scale(sql_type)
+ precision = extract_precision(sql_type)
+
+ if scale == 0
+ # FIXME: Remove this class as well
+ Type::DecimalWithoutScale.new(precision: precision)
+ else
+ Type::Decimal.new(precision: precision, scale: scale)
+ end
end
end
- end
-
- def reload_type_map # :nodoc:
- type_map.clear
- initialize_type_map(type_map)
- end
- def register_class_with_limit(mapping, key, klass) # :nodoc:
- mapping.register_type(key) do |*args|
- limit = extract_limit(args.last)
- klass.new(limit: limit)
+ def reload_type_map # :nodoc:
+ type_map.clear
+ initialize_type_map(type_map)
end
- end
- def register_class_with_precision(mapping, key, klass) # :nodoc:
- mapping.register_type(key) do |*args|
- precision = extract_precision(args.last)
- klass.new(precision: precision)
+ def register_class_with_limit(mapping, key, klass) # :nodoc:
+ mapping.register_type(key) do |*args|
+ limit = extract_limit(args.last)
+ klass.new(limit: limit)
+ end
end
- end
- def extract_scale(sql_type) # :nodoc:
- case sql_type
- when /\((\d+)\)/ then 0
- when /\((\d+)(,(\d+))\)/ then $3.to_i
+ def register_class_with_precision(mapping, key, klass) # :nodoc:
+ mapping.register_type(key) do |*args|
+ precision = extract_precision(args.last)
+ klass.new(precision: precision)
+ end
end
- end
- def extract_precision(sql_type) # :nodoc:
- $1.to_i if sql_type =~ /\((\d+)(,\d+)?\)/
- end
+ def extract_scale(sql_type) # :nodoc:
+ case sql_type
+ when /\((\d+)\)/ then 0
+ when /\((\d+)(,(\d+))\)/ then $3.to_i
+ end
+ end
- def extract_limit(sql_type) # :nodoc:
- case sql_type
- when /^bigint/i
- 8
- when /\((.*)\)/
- $1.to_i
+ def extract_precision(sql_type) # :nodoc:
+ $1.to_i if sql_type =~ /\((\d+)(,\d+)?\)/
end
- end
- def translate_exception_class(e, sql)
- begin
- message = "#{e.class.name}: #{e.message}: #{sql}"
- rescue Encoding::CompatibilityError
- message = "#{e.class.name}: #{e.message.force_encoding sql.encoding}: #{sql}"
+ def extract_limit(sql_type) # :nodoc:
+ case sql_type
+ when /^bigint/i
+ 8
+ when /\((.*)\)/
+ $1.to_i
+ end
end
- exception = translate_exception(e, message)
- exception.set_backtrace e.backtrace
- exception
- end
+ def translate_exception_class(e, sql)
+ begin
+ message = "#{e.class.name}: #{e.message}: #{sql}"
+ rescue Encoding::CompatibilityError
+ message = "#{e.class.name}: #{e.message.force_encoding sql.encoding}: #{sql}"
+ end
- def log(sql, name = "SQL", binds = [], type_casted_binds = [], statement_name = nil)
- @instrumenter.instrument(
- "sql.active_record",
- sql: sql,
- name: name,
- binds: binds,
- type_casted_binds: type_casted_binds,
- statement_name: statement_name,
- connection_id: object_id) { yield }
- rescue => e
- raise translate_exception_class(e, sql)
- end
+ exception = translate_exception(e, message)
+ exception.set_backtrace e.backtrace
+ exception
+ end
- def translate_exception(exception, message)
- # override in derived class
- ActiveRecord::StatementInvalid.new(message)
- end
+ def log(sql, name = "SQL", binds = [], type_casted_binds = [], statement_name = nil)
+ @instrumenter.instrument(
+ "sql.active_record",
+ sql: sql,
+ name: name,
+ binds: binds,
+ type_casted_binds: type_casted_binds,
+ statement_name: statement_name,
+ connection_id: object_id) { yield }
+ rescue => e
+ raise translate_exception_class(e, sql)
+ end
- def without_prepared_statement?(binds)
- !prepared_statements || binds.empty?
- end
+ def translate_exception(exception, message)
+ # override in derived class
+ ActiveRecord::StatementInvalid.new(message)
+ end
- def column_for(table_name, column_name) # :nodoc:
- column_name = column_name.to_s
- columns(table_name).detect { |c| c.name == column_name } ||
- raise(ActiveRecordError, "No such column: #{table_name}.#{column_name}")
- end
+ def without_prepared_statement?(binds)
+ !prepared_statements || binds.empty?
+ end
+
+ def column_for(table_name, column_name) # :nodoc:
+ column_name = column_name.to_s
+ columns(table_name).detect { |c| c.name == column_name } ||
+ raise(ActiveRecordError, "No such column: #{table_name}.#{column_name}")
+ end
end
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 8ac8996d21..bea8d8dda6 100644
--- a/activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb
+++ b/activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb
@@ -651,340 +651,340 @@ module ActiveRecord
protected
- def initialize_type_map(m) # :nodoc:
- super
-
- register_class_with_limit m, %r(char)i, MysqlString
-
- m.register_type %r(tinytext)i, Type::Text.new(limit: 2**8 - 1)
- m.register_type %r(tinyblob)i, Type::Binary.new(limit: 2**8 - 1)
- m.register_type %r(text)i, Type::Text.new(limit: 2**16 - 1)
- m.register_type %r(blob)i, Type::Binary.new(limit: 2**16 - 1)
- m.register_type %r(mediumtext)i, Type::Text.new(limit: 2**24 - 1)
- m.register_type %r(mediumblob)i, Type::Binary.new(limit: 2**24 - 1)
- m.register_type %r(longtext)i, Type::Text.new(limit: 2**32 - 1)
- m.register_type %r(longblob)i, Type::Binary.new(limit: 2**32 - 1)
- m.register_type %r(^float)i, Type::Float.new(limit: 24)
- m.register_type %r(^double)i, Type::Float.new(limit: 53)
- m.register_type %r(^json)i, MysqlJson.new
-
- register_integer_type m, %r(^bigint)i, limit: 8
- register_integer_type m, %r(^int)i, limit: 4
- register_integer_type m, %r(^mediumint)i, limit: 3
- register_integer_type m, %r(^smallint)i, limit: 2
- register_integer_type m, %r(^tinyint)i, limit: 1
-
- m.register_type %r(^tinyint\(1\))i, Type::Boolean.new if emulate_booleans
- m.alias_type %r(year)i, "integer"
- m.alias_type %r(bit)i, "binary"
-
- m.register_type(%r(enum)i) do |sql_type|
- limit = sql_type[/^enum\((.+)\)/i, 1]
- .split(",").map{|enum| enum.strip.length - 2}.max
- MysqlString.new(limit: limit)
- end
-
- m.register_type(%r(^set)i) do |sql_type|
- limit = sql_type[/^set\((.+)\)/i, 1]
- .split(",").map{|set| set.strip.length - 1}.sum - 1
- MysqlString.new(limit: limit)
- end
- end
-
- def register_integer_type(mapping, key, options) # :nodoc:
- mapping.register_type(key) do |sql_type|
- if /\bunsigned\z/ === sql_type
- Type::UnsignedInteger.new(options)
- else
- Type::Integer.new(options)
+ def initialize_type_map(m) # :nodoc:
+ super
+
+ register_class_with_limit m, %r(char)i, MysqlString
+
+ m.register_type %r(tinytext)i, Type::Text.new(limit: 2**8 - 1)
+ m.register_type %r(tinyblob)i, Type::Binary.new(limit: 2**8 - 1)
+ m.register_type %r(text)i, Type::Text.new(limit: 2**16 - 1)
+ m.register_type %r(blob)i, Type::Binary.new(limit: 2**16 - 1)
+ m.register_type %r(mediumtext)i, Type::Text.new(limit: 2**24 - 1)
+ m.register_type %r(mediumblob)i, Type::Binary.new(limit: 2**24 - 1)
+ m.register_type %r(longtext)i, Type::Text.new(limit: 2**32 - 1)
+ m.register_type %r(longblob)i, Type::Binary.new(limit: 2**32 - 1)
+ m.register_type %r(^float)i, Type::Float.new(limit: 24)
+ m.register_type %r(^double)i, Type::Float.new(limit: 53)
+ m.register_type %r(^json)i, MysqlJson.new
+
+ register_integer_type m, %r(^bigint)i, limit: 8
+ register_integer_type m, %r(^int)i, limit: 4
+ register_integer_type m, %r(^mediumint)i, limit: 3
+ register_integer_type m, %r(^smallint)i, limit: 2
+ register_integer_type m, %r(^tinyint)i, limit: 1
+
+ m.register_type %r(^tinyint\(1\))i, Type::Boolean.new if emulate_booleans
+ m.alias_type %r(year)i, "integer"
+ m.alias_type %r(bit)i, "binary"
+
+ m.register_type(%r(enum)i) do |sql_type|
+ limit = sql_type[/^enum\((.+)\)/i, 1]
+ .split(",").map{|enum| enum.strip.length - 2}.max
+ MysqlString.new(limit: limit)
end
- end
- end
- def extract_precision(sql_type)
- if /time/ === sql_type
- super || 0
- else
- super
+ m.register_type(%r(^set)i) do |sql_type|
+ limit = sql_type[/^set\((.+)\)/i, 1]
+ .split(",").map{|set| set.strip.length - 1}.sum - 1
+ MysqlString.new(limit: limit)
+ end
end
- end
- def fetch_type_metadata(sql_type, extra = "")
- MySQL::TypeMetadata.new(super(sql_type), extra: extra, strict: strict_mode?)
- end
+ def register_integer_type(mapping, key, options) # :nodoc:
+ mapping.register_type(key) do |sql_type|
+ if /\bunsigned\z/ === sql_type
+ Type::UnsignedInteger.new(options)
+ else
+ Type::Integer.new(options)
+ end
+ end
+ end
- def add_index_length(option_strings, column_names, options = {})
- if options.is_a?(Hash) && length = options[:length]
- case length
- when Hash
- column_names.each {|name| option_strings[name] += "(#{length[name]})" if length.has_key?(name) && length[name].present?}
- when Integer
- column_names.each {|name| option_strings[name] += "(#{length})"}
+ def extract_precision(sql_type)
+ if /time/ === sql_type
+ super || 0
+ else
+ super
end
end
- return option_strings
- end
+ def fetch_type_metadata(sql_type, extra = "")
+ MySQL::TypeMetadata.new(super(sql_type), extra: extra, strict: strict_mode?)
+ end
- def quoted_columns_for_index(column_names, options = {})
- option_strings = Hash[column_names.map {|name| [name, ""]}]
+ def add_index_length(option_strings, column_names, options = {})
+ if options.is_a?(Hash) && length = options[:length]
+ case length
+ when Hash
+ column_names.each {|name| option_strings[name] += "(#{length[name]})" if length.has_key?(name) && length[name].present?}
+ when Integer
+ column_names.each {|name| option_strings[name] += "(#{length})"}
+ end
+ end
- # add index length
- option_strings = add_index_length(option_strings, column_names, options)
+ return option_strings
+ end
- # add index sort order
- option_strings = add_index_sort_order(option_strings, column_names, options)
+ def quoted_columns_for_index(column_names, options = {})
+ option_strings = Hash[column_names.map {|name| [name, ""]}]
- column_names.map {|name| quote_column_name(name) + option_strings[name]}
- end
+ # add index length
+ option_strings = add_index_length(option_strings, column_names, options)
+
+ # add index sort order
+ option_strings = add_index_sort_order(option_strings, column_names, options)
+
+ 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 ER_DUP_ENTRY
- RecordNotUnique.new(message)
- when ER_NO_REFERENCED_ROW_2
- InvalidForeignKey.new(message)
- when ER_DATA_TOO_LONG
- ValueTooLong.new(message)
- when ER_LOCK_DEADLOCK
- Deadlocked.new(message)
- else
- super
+ 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 ER_DUP_ENTRY
+ RecordNotUnique.new(message)
+ when ER_NO_REFERENCED_ROW_2
+ InvalidForeignKey.new(message)
+ when ER_DATA_TOO_LONG
+ ValueTooLong.new(message)
+ when ER_LOCK_DEADLOCK
+ Deadlocked.new(message)
+ else
+ super
+ end
end
- end
- def add_column_sql(table_name, column_name, type, options = {})
- td = create_table_definition(table_name)
- cd = td.new_column_definition(column_name, type, options)
- schema_creation.accept(AddColumnDefinition.new(cd))
- end
+ def add_column_sql(table_name, column_name, type, options = {})
+ td = create_table_definition(table_name)
+ cd = td.new_column_definition(column_name, type, options)
+ schema_creation.accept(AddColumnDefinition.new(cd))
+ end
- def change_column_sql(table_name, column_name, type, options = {})
- column = column_for(table_name, column_name)
+ def change_column_sql(table_name, column_name, type, options = {})
+ column = column_for(table_name, column_name)
- unless options_include_default?(options)
- options[:default] = column.default
- end
+ unless options_include_default?(options)
+ options[:default] = column.default
+ end
- unless options.has_key?(:null)
- options[:null] = column.null
- end
+ unless options.has_key?(:null)
+ options[:null] = column.null
+ end
- td = create_table_definition(table_name)
- cd = td.new_column_definition(column.name, type, options)
- schema_creation.accept(ChangeColumnDefinition.new(cd, column.name))
- end
+ td = create_table_definition(table_name)
+ cd = td.new_column_definition(column.name, type, options)
+ schema_creation.accept(ChangeColumnDefinition.new(cd, column.name))
+ end
- def rename_column_sql(table_name, column_name, new_column_name)
- column = column_for(table_name, column_name)
- options = {
- default: column.default,
- null: column.null,
- auto_increment: column.auto_increment?
- }
+ def rename_column_sql(table_name, column_name, new_column_name)
+ column = column_for(table_name, column_name)
+ options = {
+ default: column.default,
+ null: column.null,
+ auto_increment: column.auto_increment?
+ }
- current_type = select_one("SHOW COLUMNS FROM #{quote_table_name(table_name)} LIKE '#{column_name}'", "SCHEMA")["Type"]
- td = create_table_definition(table_name)
- cd = td.new_column_definition(new_column_name, current_type, options)
- schema_creation.accept(ChangeColumnDefinition.new(cd, column.name))
- end
+ current_type = select_one("SHOW COLUMNS FROM #{quote_table_name(table_name)} LIKE '#{column_name}'", "SCHEMA")["Type"]
+ td = create_table_definition(table_name)
+ cd = td.new_column_definition(new_column_name, current_type, options)
+ schema_creation.accept(ChangeColumnDefinition.new(cd, column.name))
+ end
- def remove_column_sql(table_name, column_name, type = nil, options = {})
- "DROP #{quote_column_name(column_name)}"
- end
+ def remove_column_sql(table_name, column_name, type = nil, options = {})
+ "DROP #{quote_column_name(column_name)}"
+ end
- def remove_columns_sql(table_name, *column_names)
- column_names.map {|column_name| remove_column_sql(table_name, column_name) }
- end
+ def remove_columns_sql(table_name, *column_names)
+ column_names.map {|column_name| remove_column_sql(table_name, column_name) }
+ end
- def add_index_sql(table_name, column_name, options = {})
- index_name, index_type, index_columns, _, index_algorithm, index_using = add_index_options(table_name, column_name, options)
- index_algorithm[0, 0] = ", " if index_algorithm.present?
- "ADD #{index_type} INDEX #{quote_column_name(index_name)} #{index_using} (#{index_columns})#{index_algorithm}"
- end
+ def add_index_sql(table_name, column_name, options = {})
+ index_name, index_type, index_columns, _, index_algorithm, index_using = add_index_options(table_name, column_name, options)
+ index_algorithm[0, 0] = ", " if index_algorithm.present?
+ "ADD #{index_type} INDEX #{quote_column_name(index_name)} #{index_using} (#{index_columns})#{index_algorithm}"
+ end
- def remove_index_sql(table_name, options = {})
- index_name = index_name_for_remove(table_name, options)
- "DROP INDEX #{index_name}"
- end
+ def remove_index_sql(table_name, options = {})
+ index_name = index_name_for_remove(table_name, options)
+ "DROP INDEX #{index_name}"
+ end
- def add_timestamps_sql(table_name, options = {})
- [add_column_sql(table_name, :created_at, :datetime, options), add_column_sql(table_name, :updated_at, :datetime, options)]
- end
+ def add_timestamps_sql(table_name, options = {})
+ [add_column_sql(table_name, :created_at, :datetime, options), add_column_sql(table_name, :updated_at, :datetime, options)]
+ end
- def remove_timestamps_sql(table_name, options = {})
- [remove_column_sql(table_name, :updated_at), remove_column_sql(table_name, :created_at)]
- end
+ def remove_timestamps_sql(table_name, options = {})
+ [remove_column_sql(table_name, :updated_at), remove_column_sql(table_name, :created_at)]
+ end
private
# MySQL is too stupid to create a temporary table for use subquery, so we have
# to give it some prompting in the form of a subsubquery. Ugh!
- def subquery_for(key, select)
- subsubselect = select.clone
- subsubselect.projections = [key]
+ def subquery_for(key, select)
+ subsubselect = select.clone
+ subsubselect.projections = [key]
- # Materialize subquery by adding distinct
- # to work with MySQL 5.7.6 which sets optimizer_switch='derived_merge=on'
- subsubselect.distinct unless select.limit || select.offset || select.orders.any?
+ # Materialize subquery by adding distinct
+ # to work with MySQL 5.7.6 which sets optimizer_switch='derived_merge=on'
+ subsubselect.distinct unless select.limit || select.offset || select.orders.any?
- subselect = Arel::SelectManager.new(select.engine)
- subselect.project Arel.sql(key.name)
- subselect.from subsubselect.as("__active_record_temp")
- end
+ subselect = Arel::SelectManager.new(select.engine)
+ subselect.project Arel.sql(key.name)
+ subselect.from subsubselect.as("__active_record_temp")
+ end
- def supports_rename_index?
- mariadb? ? false : version >= "5.7.6"
- end
+ def supports_rename_index?
+ mariadb? ? false : version >= "5.7.6"
+ end
- def configure_connection
- variables = @config.fetch(:variables, {}).stringify_keys
+ def configure_connection
+ variables = @config.fetch(:variables, {}).stringify_keys
- # By default, MySQL 'where id is null' selects the last inserted id; Turn this off.
- variables["sql_auto_is_null"] = 0
+ # By default, MySQL 'where id is null' selects the last inserted id; Turn this off.
+ variables["sql_auto_is_null"] = 0
- # Increase timeout so the server doesn't disconnect us.
- wait_timeout = @config[:wait_timeout]
- wait_timeout = 2147483 unless wait_timeout.is_a?(Integer)
- variables["wait_timeout"] = self.class.type_cast_config_to_integer(wait_timeout)
+ # Increase timeout so the server doesn't disconnect us.
+ wait_timeout = @config[:wait_timeout]
+ 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
+ defaults = [":default", :default].to_set
- # Make MySQL reject illegal values rather than truncating or blanking them, see
- # http://dev.mysql.com/doc/refman/5.7/en/sql-mode.html#sqlmode_strict_all_tables
- # If the user has provided another value for sql_mode, don't replace it.
- if sql_mode = variables.delete("sql_mode")
- sql_mode = quote(sql_mode)
- elsif !defaults.include?(strict_mode?)
- if strict_mode?
- sql_mode = "CONCAT(@@sql_mode, ',STRICT_ALL_TABLES')"
- else
- sql_mode = "REPLACE(@@sql_mode, 'STRICT_TRANS_TABLES', '')"
- sql_mode = "REPLACE(#{sql_mode}, 'STRICT_ALL_TABLES', '')"
- sql_mode = "REPLACE(#{sql_mode}, 'TRADITIONAL', '')"
+ # Make MySQL reject illegal values rather than truncating or blanking them, see
+ # http://dev.mysql.com/doc/refman/5.7/en/sql-mode.html#sqlmode_strict_all_tables
+ # If the user has provided another value for sql_mode, don't replace it.
+ if sql_mode = variables.delete("sql_mode")
+ sql_mode = quote(sql_mode)
+ elsif !defaults.include?(strict_mode?)
+ if strict_mode?
+ sql_mode = "CONCAT(@@sql_mode, ',STRICT_ALL_TABLES')"
+ else
+ sql_mode = "REPLACE(@@sql_mode, 'STRICT_TRANS_TABLES', '')"
+ sql_mode = "REPLACE(#{sql_mode}, 'STRICT_ALL_TABLES', '')"
+ sql_mode = "REPLACE(#{sql_mode}, 'TRADITIONAL', '')"
+ end
+ sql_mode = "CONCAT(#{sql_mode}, ',NO_AUTO_VALUE_ON_ZERO')"
end
- sql_mode = "CONCAT(#{sql_mode}, ',NO_AUTO_VALUE_ON_ZERO')"
- end
- sql_mode_assignment = "@@SESSION.sql_mode = #{sql_mode}, " if sql_mode
-
- # NAMES does not have an equals sign, see
- # http://dev.mysql.com/doc/refman/5.7/en/set-statement.html#id944430
- # (trailing comma because variable_assignments will always have content)
- if @config[:encoding]
- encoding = "NAMES #{@config[:encoding]}"
- encoding << " COLLATE #{@config[:collation]}" if @config[:collation]
- encoding << ", "
- end
-
- # Gather up all of the SET variables...
- variable_assignments = variables.map do |k, v|
- if defaults.include?(v)
- "@@SESSION.#{k} = DEFAULT" # Sets the value to the global or compile default
- elsif !v.nil?
- "@@SESSION.#{k} = #{quote(v)}"
+ sql_mode_assignment = "@@SESSION.sql_mode = #{sql_mode}, " if sql_mode
+
+ # NAMES does not have an equals sign, see
+ # http://dev.mysql.com/doc/refman/5.7/en/set-statement.html#id944430
+ # (trailing comma because variable_assignments will always have content)
+ if @config[:encoding]
+ encoding = "NAMES #{@config[:encoding]}"
+ encoding << " COLLATE #{@config[:collation]}" if @config[:collation]
+ encoding << ", "
end
- # or else nil; compact to clear nils out
- end.compact.join(", ")
- # ...and send them all in one query
- @connection.query "SET #{encoding} #{sql_mode_assignment} #{variable_assignments}"
- end
+ # Gather up all of the SET variables...
+ variable_assignments = variables.map do |k, v|
+ if defaults.include?(v)
+ "@@SESSION.#{k} = DEFAULT" # Sets the value to the global or compile default
+ elsif !v.nil?
+ "@@SESSION.#{k} = #{quote(v)}"
+ end
+ # or else nil; compact to clear nils out
+ end.compact.join(", ")
- def column_definitions(table_name) # :nodoc:
- execute_and_free("SHOW FULL FIELDS FROM #{quote_table_name(table_name)}", "SCHEMA") do |result|
- each_hash(result)
+ # ...and send them all in one query
+ @connection.query "SET #{encoding} #{sql_mode_assignment} #{variable_assignments}"
end
- end
- def extract_foreign_key_action(specifier) # :nodoc:
- case specifier
- when "CASCADE"; :cascade
- when "SET NULL"; :nullify
+ def column_definitions(table_name) # :nodoc:
+ execute_and_free("SHOW FULL FIELDS FROM #{quote_table_name(table_name)}", "SCHEMA") do |result|
+ each_hash(result)
+ end
end
- end
-
- def create_table_info(table_name) # :nodoc:
- select_one("SHOW CREATE TABLE #{quote_table_name(table_name)}")["Create Table"]
- end
- def create_table_definition(*args) # :nodoc:
- MySQL::TableDefinition.new(*args)
- end
+ def extract_foreign_key_action(specifier) # :nodoc:
+ case specifier
+ when "CASCADE"; :cascade
+ when "SET NULL"; :nullify
+ end
+ end
- def extract_schema_qualified_name(string) # :nodoc:
- schema, name = string.to_s.scan(/[^`.\s]+|`[^`]*`/)
- schema, name = @config[:database], schema unless name
- [schema, name]
- end
+ def create_table_info(table_name) # :nodoc:
+ select_one("SHOW CREATE TABLE #{quote_table_name(table_name)}")["Create Table"]
+ end
- def integer_to_sql(limit) # :nodoc:
- case limit
- when 1; "tinyint"
- when 2; "smallint"
- when 3; "mediumint"
- when nil, 4; "int"
- when 5..8; "bigint"
- else raise(ActiveRecordError, "No integer type has byte size #{limit}")
+ def create_table_definition(*args) # :nodoc:
+ MySQL::TableDefinition.new(*args)
end
- end
- def text_to_sql(limit) # :nodoc:
- case limit
- when 0..0xff; "tinytext"
- when nil, 0x100..0xffff; "text"
- when 0x10000..0xffffff; "mediumtext"
- when 0x1000000..0xffffffff; "longtext"
- else raise(ActiveRecordError, "No text type has byte length #{limit}")
+ def extract_schema_qualified_name(string) # :nodoc:
+ schema, name = string.to_s.scan(/[^`.\s]+|`[^`]*`/)
+ schema, name = @config[:database], schema unless name
+ [schema, name]
end
- end
- def binary_to_sql(limit) # :nodoc:
- case limit
- when 0..0xff; "tinyblob"
- when nil, 0x100..0xffff; "blob"
- when 0x10000..0xffffff; "mediumblob"
- when 0x1000000..0xffffffff; "longblob"
- else raise(ActiveRecordError, "No binary type has byte length #{limit}")
+ def integer_to_sql(limit) # :nodoc:
+ case limit
+ when 1; "tinyint"
+ when 2; "smallint"
+ when 3; "mediumint"
+ when nil, 4; "int"
+ when 5..8; "bigint"
+ else raise(ActiveRecordError, "No integer type has byte size #{limit}")
+ end
end
- end
- class MysqlJson < Type::Internal::AbstractJson # :nodoc:
- def changed_in_place?(raw_old_value, new_value)
- # Normalization is required because MySQL JSON data format includes
- # the space between the elements.
- super(serialize(deserialize(raw_old_value)), new_value)
+ def text_to_sql(limit) # :nodoc:
+ case limit
+ when 0..0xff; "tinytext"
+ when nil, 0x100..0xffff; "text"
+ when 0x10000..0xffffff; "mediumtext"
+ when 0x1000000..0xffffffff; "longtext"
+ else raise(ActiveRecordError, "No text type has byte length #{limit}")
+ end
end
- end
- class MysqlString < Type::String # :nodoc:
- def serialize(value)
- case value
- when true then MySQL::Quoting::QUOTED_TRUE
- when false then MySQL::Quoting::QUOTED_FALSE
- else super
+ def binary_to_sql(limit) # :nodoc:
+ case limit
+ when 0..0xff; "tinyblob"
+ when nil, 0x100..0xffff; "blob"
+ when 0x10000..0xffffff; "mediumblob"
+ when 0x1000000..0xffffffff; "longblob"
+ else raise(ActiveRecordError, "No binary type has byte length #{limit}")
end
end
- private
+ class MysqlJson < Type::Internal::AbstractJson # :nodoc:
+ def changed_in_place?(raw_old_value, new_value)
+ # Normalization is required because MySQL JSON data format includes
+ # the space between the elements.
+ super(serialize(deserialize(raw_old_value)), new_value)
+ end
+ end
- def cast_value(value)
- case value
- when true then MySQL::Quoting::QUOTED_TRUE
- when false then MySQL::Quoting::QUOTED_FALSE
- else super
+ class MysqlString < Type::String # :nodoc:
+ def serialize(value)
+ case value
+ when true then MySQL::Quoting::QUOTED_TRUE
+ when false then MySQL::Quoting::QUOTED_FALSE
+ else super
+ end
end
+
+ private
+
+ def cast_value(value)
+ case value
+ when true then MySQL::Quoting::QUOTED_TRUE
+ when false then MySQL::Quoting::QUOTED_FALSE
+ else super
+ end
+ end
end
- end
- ActiveRecord::Type.register(:json, MysqlJson, adapter: :mysql2)
- ActiveRecord::Type.register(:string, MysqlString, adapter: :mysql2)
- ActiveRecord::Type.register(:unsigned_integer, Type::UnsignedInteger, adapter: :mysql2)
+ ActiveRecord::Type.register(:json, MysqlJson, adapter: :mysql2)
+ ActiveRecord::Type.register(:string, MysqlString, adapter: :mysql2)
+ ActiveRecord::Type.register(:unsigned_integer, Type::UnsignedInteger, adapter: :mysql2)
end
end
end
diff --git a/activerecord/lib/active_record/connection_adapters/column.rb b/activerecord/lib/active_record/connection_adapters/column.rb
index 28f0c8686a..1808173592 100644
--- a/activerecord/lib/active_record/connection_adapters/column.rb
+++ b/activerecord/lib/active_record/connection_adapters/column.rb
@@ -52,9 +52,9 @@ module ActiveRecord
protected
- def attributes_for_hash
- [self.class, name, default, sql_type_metadata, null, table_name, default_function, collation]
- end
+ def attributes_for_hash
+ [self.class, name, default, sql_type_metadata, null, table_name, default_function, collation]
+ end
end
class NullColumn < Column
diff --git a/activerecord/lib/active_record/connection_adapters/connection_specification.rb b/activerecord/lib/active_record/connection_adapters/connection_specification.rb
index 996075e08a..c0c7ce46b2 100644
--- a/activerecord/lib/active_record/connection_adapters/connection_specification.rb
+++ b/activerecord/lib/active_record/connection_adapters/connection_specification.rb
@@ -56,13 +56,13 @@ module ActiveRecord
private
- def uri
- @uri
- end
+ def uri
+ @uri
+ end
- def uri_parser
- @uri_parser ||= URI::Parser.new
- end
+ def uri_parser
+ @uri_parser ||= URI::Parser.new
+ end
# Converts the query parameters of the URI into a hash.
#
@@ -73,39 +73,39 @@ module ActiveRecord
#
# "localhost"
# # => {}
- def query_hash
- Hash[(@query || "").split("&").map { |pair| pair.split("=") }]
- end
+ def query_hash
+ Hash[(@query || "").split("&").map { |pair| pair.split("=") }]
+ end
- def raw_config
- if uri.opaque
- query_hash.merge( "adapter" => @adapter,
- "database" => uri.opaque)
- else
- query_hash.merge( "adapter" => @adapter,
- "username" => uri.user,
- "password" => uri.password,
- "port" => uri.port,
- "database" => database_from_path,
- "host" => uri.hostname)
+ def raw_config
+ if uri.opaque
+ query_hash.merge( "adapter" => @adapter,
+ "database" => uri.opaque)
+ else
+ query_hash.merge( "adapter" => @adapter,
+ "username" => uri.user,
+ "password" => uri.password,
+ "port" => uri.port,
+ "database" => database_from_path,
+ "host" => uri.hostname)
+ end
end
- end
# Returns name of the database.
- def database_from_path
- if @adapter == "sqlite3"
- # 'sqlite3:/foo' is absolute, because that makes sense. The
- # corresponding relative version, 'sqlite3:foo', is handled
- # elsewhere, as an "opaque".
+ def database_from_path
+ if @adapter == "sqlite3"
+ # 'sqlite3:/foo' is absolute, because that makes sense. The
+ # corresponding relative version, 'sqlite3:foo', is handled
+ # elsewhere, as an "opaque".
- uri.path
- else
- # Only SQLite uses a filename as the "database" name; for
- # anything else, a leading slash would be silly.
+ uri.path
+ else
+ # Only SQLite uses a filename as the "database" name; for
+ # anything else, a leading slash would be silly.
- uri.path.sub(%r{^/}, "")
+ uri.path.sub(%r{^/}, "")
+ end
end
- end
end
##
@@ -211,16 +211,16 @@ module ActiveRecord
# Resolver.new({}).resolve_connection("postgresql://localhost/foo")
# # => { "host" => "localhost", "database" => "foo", "adapter" => "postgresql" }
#
- def resolve_connection(spec)
- case spec
- when Symbol
- resolve_symbol_connection spec
- when String
- resolve_url_connection spec
- when Hash
- resolve_hash_connection spec
+ def resolve_connection(spec)
+ case spec
+ when Symbol
+ resolve_symbol_connection spec
+ when String
+ resolve_url_connection spec
+ when Hash
+ resolve_hash_connection spec
+ end
end
- end
# Takes the environment such as +:production+ or +:development+.
# This requires that the @configurations was initialized with a key that
@@ -229,34 +229,34 @@ module ActiveRecord
# Resolver.new("production" => {}).resolve_symbol_connection(:production)
# # => {}
#
- def resolve_symbol_connection(spec)
- if config = configurations[spec.to_s]
- resolve_connection(config).merge("name" => spec.to_s)
- else
- raise(AdapterNotSpecified, "'#{spec}' database is not configured. Available: #{configurations.keys.inspect}")
+ def resolve_symbol_connection(spec)
+ if config = configurations[spec.to_s]
+ resolve_connection(config).merge("name" => spec.to_s)
+ else
+ raise(AdapterNotSpecified, "'#{spec}' database is not configured. Available: #{configurations.keys.inspect}")
+ end
end
- end
# Accepts a hash. Expands the "url" key that contains a
# URL database connection to a full connection
# hash and merges with the rest of the hash.
# Connection details inside of the "url" key win any merge conflicts
- def resolve_hash_connection(spec)
- if spec["url"] && spec["url"] !~ /^jdbc:/
- connection_hash = resolve_url_connection(spec.delete("url"))
- spec.merge!(connection_hash)
+ def resolve_hash_connection(spec)
+ if spec["url"] && spec["url"] !~ /^jdbc:/
+ connection_hash = resolve_url_connection(spec.delete("url"))
+ spec.merge!(connection_hash)
+ end
+ spec
end
- spec
- end
# Takes a connection URL.
#
# Resolver.new({}).resolve_url_connection("postgresql://localhost/foo")
# # => { "host" => "localhost", "database" => "foo", "adapter" => "postgresql" }
#
- def resolve_url_connection(url)
- ConnectionUrlResolver.new(url).to_hash
- end
+ def resolve_url_connection(url)
+ ConnectionUrlResolver.new(url).to_hash
+ end
end
end
end
diff --git a/activerecord/lib/active_record/connection_adapters/mysql/column.rb b/activerecord/lib/active_record/connection_adapters/mysql/column.rb
index cb068a61c7..5452e44c84 100644
--- a/activerecord/lib/active_record/connection_adapters/mysql/column.rb
+++ b/activerecord/lib/active_record/connection_adapters/mysql/column.rb
@@ -32,11 +32,11 @@ module ActiveRecord
private
- def extract_default
- if blob_or_text_column?
- @default = null || strict ? nil : ""
+ def extract_default
+ if blob_or_text_column?
+ @default = null || strict ? nil : ""
+ end
end
- end
end
end
end
diff --git a/activerecord/lib/active_record/connection_adapters/mysql/database_statements.rb b/activerecord/lib/active_record/connection_adapters/mysql/database_statements.rb
index cd606d11a7..c8238eb266 100644
--- a/activerecord/lib/active_record/connection_adapters/mysql/database_statements.rb
+++ b/activerecord/lib/active_record/connection_adapters/mysql/database_statements.rb
@@ -56,56 +56,56 @@ module ActiveRecord
protected
- def last_inserted_id(result)
- @connection.last_id
- end
+ def last_inserted_id(result)
+ @connection.last_id
+ end
private
- def select_result(sql, name = nil, binds = [])
- if without_prepared_statement?(binds)
- execute_and_free(sql, name) { |result| yield result }
- else
- exec_stmt_and_free(sql, name, binds, cache_stmt: true) { |_, result| yield result }
- end
- end
-
- def exec_stmt_and_free(sql, name, binds, cache_stmt: false)
- if @connection
- # make sure we carry over any changes to ActiveRecord::Base.default_timezone that have been
- # made since we established the connection
- @connection.query_options[:database_timezone] = ActiveRecord::Base.default_timezone
+ def select_result(sql, name = nil, binds = [])
+ if without_prepared_statement?(binds)
+ execute_and_free(sql, name) { |result| yield result }
+ else
+ exec_stmt_and_free(sql, name, binds, cache_stmt: true) { |_, result| yield result }
+ end
end
- type_casted_binds = type_casted_binds(binds)
-
- log(sql, name, binds, type_casted_binds) do
- if cache_stmt
- cache = @statements[sql] ||= {
- stmt: @connection.prepare(sql)
- }
- stmt = cache[:stmt]
- else
- stmt = @connection.prepare(sql)
+ def exec_stmt_and_free(sql, name, binds, cache_stmt: false)
+ if @connection
+ # make sure we carry over any changes to ActiveRecord::Base.default_timezone that have been
+ # made since we established the connection
+ @connection.query_options[:database_timezone] = ActiveRecord::Base.default_timezone
end
- begin
- result = stmt.execute(*type_casted_binds)
- rescue Mysql2::Error => e
+ type_casted_binds = type_casted_binds(binds)
+
+ log(sql, name, binds, type_casted_binds) do
if cache_stmt
- @statements.delete(sql)
+ cache = @statements[sql] ||= {
+ stmt: @connection.prepare(sql)
+ }
+ stmt = cache[:stmt]
else
- stmt.close
+ stmt = @connection.prepare(sql)
+ end
+
+ begin
+ result = stmt.execute(*type_casted_binds)
+ rescue Mysql2::Error => e
+ if cache_stmt
+ @statements.delete(sql)
+ else
+ stmt.close
+ end
+ raise e
end
- raise e
- end
- ret = yield stmt, result
- result.free if result
- stmt.close unless cache_stmt
- ret
+ ret = yield stmt, result
+ result.free if result
+ stmt.close unless cache_stmt
+ ret
+ end
end
- end
end
end
end
diff --git a/activerecord/lib/active_record/connection_adapters/mysql/explain_pretty_printer.rb b/activerecord/lib/active_record/connection_adapters/mysql/explain_pretty_printer.rb
index 5a6b33cb04..0b7dea232f 100644
--- a/activerecord/lib/active_record/connection_adapters/mysql/explain_pretty_printer.rb
+++ b/activerecord/lib/active_record/connection_adapters/mysql/explain_pretty_printer.rb
@@ -36,34 +36,34 @@ module ActiveRecord
private
- def compute_column_widths(result)
- [].tap do |widths|
- result.columns.each_with_index do |column, i|
- cells_in_column = [column] + result.rows.map {|r| r[i].nil? ? "NULL" : r[i].to_s}
- widths << cells_in_column.map(&:length).max
+ def compute_column_widths(result)
+ [].tap do |widths|
+ result.columns.each_with_index do |column, i|
+ cells_in_column = [column] + result.rows.map {|r| r[i].nil? ? "NULL" : r[i].to_s}
+ widths << cells_in_column.map(&:length).max
+ end
end
end
- end
- def build_separator(widths)
- padding = 1
- "+" + widths.map {|w| "-" * (w + (padding*2))}.join("+") + "+"
- end
+ def build_separator(widths)
+ padding = 1
+ "+" + widths.map {|w| "-" * (w + (padding*2))}.join("+") + "+"
+ end
- def build_cells(items, widths)
- cells = []
- items.each_with_index do |item, i|
- item = "NULL" if item.nil?
- justifier = item.is_a?(Numeric) ? "rjust" : "ljust"
- cells << item.to_s.send(justifier, widths[i])
+ def build_cells(items, widths)
+ cells = []
+ items.each_with_index do |item, i|
+ item = "NULL" if item.nil?
+ justifier = item.is_a?(Numeric) ? "rjust" : "ljust"
+ cells << item.to_s.send(justifier, widths[i])
+ end
+ "| " + cells.join(" | ") + " |"
end
- "| " + cells.join(" | ") + " |"
- end
- def build_footer(nrows, elapsed)
- rows_label = nrows == 1 ? "row" : "rows"
- "#{nrows} #{rows_label} in set (%.2f sec)" % elapsed
- end
+ def build_footer(nrows, elapsed)
+ rows_label = nrows == 1 ? "row" : "rows"
+ "#{nrows} #{rows_label} in set (%.2f sec)" % elapsed
+ end
end
end
end
diff --git a/activerecord/lib/active_record/connection_adapters/mysql/quoting.rb b/activerecord/lib/active_record/connection_adapters/mysql/quoting.rb
index 381787868b..9d11ad28d4 100644
--- a/activerecord/lib/active_record/connection_adapters/mysql/quoting.rb
+++ b/activerecord/lib/active_record/connection_adapters/mysql/quoting.rb
@@ -38,13 +38,13 @@ module ActiveRecord
private
- def _quote(value)
- if value.is_a?(Type::Binary::Data)
- "x'#{value.hex}'"
- else
- super
+ def _quote(value)
+ if value.is_a?(Type::Binary::Data)
+ "x'#{value.hex}'"
+ else
+ super
+ end
end
- end
end
end
end
diff --git a/activerecord/lib/active_record/connection_adapters/mysql/schema_creation.rb b/activerecord/lib/active_record/connection_adapters/mysql/schema_creation.rb
index fd2dc2aee8..d808b50332 100644
--- a/activerecord/lib/active_record/connection_adapters/mysql/schema_creation.rb
+++ b/activerecord/lib/active_record/connection_adapters/mysql/schema_creation.rb
@@ -7,60 +7,60 @@ module ActiveRecord
private
- def visit_DropForeignKey(name)
- "DROP FOREIGN KEY #{name}"
- end
-
- def visit_ColumnDefinition(o)
- o.sql_type = type_to_sql(o.type, o.limit, o.precision, o.scale, o.unsigned)
- super
- end
-
- def visit_AddColumnDefinition(o)
- add_column_position!(super, column_options(o.column))
- end
+ def visit_DropForeignKey(name)
+ "DROP FOREIGN KEY #{name}"
+ end
- def visit_ChangeColumnDefinition(o)
- change_column_sql = "CHANGE #{quote_column_name(o.name)} #{accept(o.column)}"
- add_column_position!(change_column_sql, column_options(o.column))
- end
+ def visit_ColumnDefinition(o)
+ o.sql_type = type_to_sql(o.type, o.limit, o.precision, o.scale, o.unsigned)
+ super
+ end
- def add_table_options!(create_sql, options)
- add_sql_comment!(super, options[:comment])
- end
+ def visit_AddColumnDefinition(o)
+ add_column_position!(super, column_options(o.column))
+ end
- def column_options(o)
- column_options = super
- column_options[:charset] = o.charset
- column_options
- end
+ def visit_ChangeColumnDefinition(o)
+ change_column_sql = "CHANGE #{quote_column_name(o.name)} #{accept(o.column)}"
+ add_column_position!(change_column_sql, column_options(o.column))
+ end
- def add_column_options!(sql, options)
- if charset = options[:charset]
- sql << " CHARACTER SET #{charset}"
+ def add_table_options!(create_sql, options)
+ add_sql_comment!(super, options[:comment])
end
- if collation = options[:collation]
- sql << " COLLATE #{collation}"
+ def column_options(o)
+ column_options = super
+ column_options[:charset] = o.charset
+ column_options
end
- add_sql_comment!(super, options[:comment])
- end
+ def add_column_options!(sql, options)
+ if charset = options[:charset]
+ sql << " CHARACTER SET #{charset}"
+ end
+
+ if collation = options[:collation]
+ sql << " COLLATE #{collation}"
+ end
- def add_column_position!(sql, options)
- if options[:first]
- sql << " FIRST"
- elsif options[:after]
- sql << " AFTER #{quote_column_name(options[:after])}"
+ add_sql_comment!(super, options[:comment])
end
- sql
- end
+ def add_column_position!(sql, options)
+ if options[:first]
+ sql << " FIRST"
+ elsif options[:after]
+ sql << " AFTER #{quote_column_name(options[:after])}"
+ end
- def index_in_create(table_name, column_name, options)
- index_name, index_type, index_columns, _, _, index_using, comment = @conn.add_index_options(table_name, column_name, options)
- add_sql_comment!("#{index_type} INDEX #{quote_column_name(index_name)} #{index_using} (#{index_columns})", comment)
- end
+ sql
+ end
+
+ def index_in_create(table_name, column_name, options)
+ index_name, index_type, index_columns, _, _, index_using, comment = @conn.add_index_options(table_name, column_name, options)
+ add_sql_comment!("#{index_type} INDEX #{quote_column_name(index_name)} #{index_using} (#{index_columns})", comment)
+ end
end
end
end
diff --git a/activerecord/lib/active_record/connection_adapters/mysql/schema_definitions.rb b/activerecord/lib/active_record/connection_adapters/mysql/schema_definitions.rb
index 157e75dbf7..ce773ed75b 100644
--- a/activerecord/lib/active_record/connection_adapters/mysql/schema_definitions.rb
+++ b/activerecord/lib/active_record/connection_adapters/mysql/schema_definitions.rb
@@ -80,9 +80,9 @@ module ActiveRecord
private
- def create_column_definition(name, type)
- MySQL::ColumnDefinition.new(name, type)
- end
+ def create_column_definition(name, type)
+ MySQL::ColumnDefinition.new(name, type)
+ end
end
class Table < ActiveRecord::ConnectionAdapters::Table
diff --git a/activerecord/lib/active_record/connection_adapters/mysql/schema_dumper.rb b/activerecord/lib/active_record/connection_adapters/mysql/schema_dumper.rb
index 3e644f386f..39221eeb0c 100644
--- a/activerecord/lib/active_record/connection_adapters/mysql/schema_dumper.rb
+++ b/activerecord/lib/active_record/connection_adapters/mysql/schema_dumper.rb
@@ -25,29 +25,29 @@ module ActiveRecord
private
- def default_primary_key?(column)
- super && column.auto_increment?
- end
+ def default_primary_key?(column)
+ super && column.auto_increment?
+ end
- def schema_type(column)
- if column.sql_type == "tinyblob"
- :blob
- else
- super
+ def schema_type(column)
+ if column.sql_type == "tinyblob"
+ :blob
+ else
+ super
+ end
end
- end
- def schema_precision(column)
- super unless /time/ === column.sql_type && column.precision == 0
- end
+ def schema_precision(column)
+ super unless /time/ === column.sql_type && column.precision == 0
+ end
- def schema_collation(column)
- if column.collation && table_name = column.table_name
- @table_collation_cache ||= {}
- @table_collation_cache[table_name] ||= select_one("SHOW TABLE STATUS LIKE '#{table_name}'")["Collation"]
- column.collation.inspect if column.collation != @table_collation_cache[table_name]
+ def schema_collation(column)
+ if column.collation && table_name = column.table_name
+ @table_collation_cache ||= {}
+ @table_collation_cache[table_name] ||= select_one("SHOW TABLE STATUS LIKE '#{table_name}'")["Collation"]
+ column.collation.inspect if column.collation != @table_collation_cache[table_name]
+ end
end
- end
end
end
end
diff --git a/activerecord/lib/active_record/connection_adapters/mysql/type_metadata.rb b/activerecord/lib/active_record/connection_adapters/mysql/type_metadata.rb
index e1e3f7b472..1be5cb4740 100644
--- a/activerecord/lib/active_record/connection_adapters/mysql/type_metadata.rb
+++ b/activerecord/lib/active_record/connection_adapters/mysql/type_metadata.rb
@@ -23,9 +23,9 @@ module ActiveRecord
protected
- def attributes_for_hash
- [self.class, @type_metadata, extra, strict]
- end
+ def attributes_for_hash
+ [self.class, @type_metadata, extra, strict]
+ end
end
end
end
diff --git a/activerecord/lib/active_record/connection_adapters/mysql2_adapter.rb b/activerecord/lib/active_record/connection_adapters/mysql2_adapter.rb
index 154f0b2d3a..0130b4ef62 100644
--- a/activerecord/lib/active_record/connection_adapters/mysql2_adapter.rb
+++ b/activerecord/lib/active_record/connection_adapters/mysql2_adapter.rb
@@ -113,19 +113,19 @@ module ActiveRecord
private
- def connect
- @connection = Mysql2::Client.new(@config)
- configure_connection
- end
+ def connect
+ @connection = Mysql2::Client.new(@config)
+ configure_connection
+ end
- def configure_connection
- @connection.query_options.merge!(as: :array)
- super
- end
+ def configure_connection
+ @connection.query_options.merge!(as: :array)
+ super
+ end
- def full_version
- @full_version ||= @connection.server_info[:version]
- end
+ def full_version
+ @full_version ||= @connection.server_info[:version]
+ end
end
end
end
diff --git a/activerecord/lib/active_record/connection_adapters/postgresql/database_statements.rb b/activerecord/lib/active_record/connection_adapters/postgresql/database_statements.rb
index b5a3340c18..87338986b9 100644
--- a/activerecord/lib/active_record/connection_adapters/postgresql/database_statements.rb
+++ b/activerecord/lib/active_record/connection_adapters/postgresql/database_statements.rb
@@ -169,9 +169,9 @@ module ActiveRecord
private
- def suppress_composite_primary_key(pk)
- pk unless pk.is_a?(Array)
- end
+ def suppress_composite_primary_key(pk)
+ pk unless pk.is_a?(Array)
+ end
end
end
end
diff --git a/activerecord/lib/active_record/connection_adapters/postgresql/oid/array.rb b/activerecord/lib/active_record/connection_adapters/postgresql/oid/array.rb
index 9e0e6732c3..1a66afb23a 100644
--- a/activerecord/lib/active_record/connection_adapters/postgresql/oid/array.rb
+++ b/activerecord/lib/active_record/connection_adapters/postgresql/oid/array.rb
@@ -56,13 +56,13 @@ module ActiveRecord
private
- def type_cast_array(value, method)
- if value.is_a?(::Array)
- value.map { |item| type_cast_array(item, method) }
- else
- @subtype.public_send(method, value)
+ def type_cast_array(value, method)
+ if value.is_a?(::Array)
+ value.map { |item| type_cast_array(item, method) }
+ else
+ @subtype.public_send(method, value)
+ end
end
- end
end
end
end
diff --git a/activerecord/lib/active_record/connection_adapters/postgresql/oid/bit.rb b/activerecord/lib/active_record/connection_adapters/postgresql/oid/bit.rb
index ea0fa2517f..a6b5a89ec0 100644
--- a/activerecord/lib/active_record/connection_adapters/postgresql/oid/bit.rb
+++ b/activerecord/lib/active_record/connection_adapters/postgresql/oid/bit.rb
@@ -43,7 +43,7 @@ module ActiveRecord
protected
- attr_reader :value
+ attr_reader :value
end
end
end
diff --git a/activerecord/lib/active_record/connection_adapters/postgresql/oid/enum.rb b/activerecord/lib/active_record/connection_adapters/postgresql/oid/enum.rb
index 91d339f32c..950d23d516 100644
--- a/activerecord/lib/active_record/connection_adapters/postgresql/oid/enum.rb
+++ b/activerecord/lib/active_record/connection_adapters/postgresql/oid/enum.rb
@@ -9,9 +9,9 @@ module ActiveRecord
private
- def cast_value(value)
- value.to_s
- end
+ def cast_value(value)
+ value.to_s
+ end
end
end
end
diff --git a/activerecord/lib/active_record/connection_adapters/postgresql/oid/hstore.rb b/activerecord/lib/active_record/connection_adapters/postgresql/oid/hstore.rb
index 2e55a5f8b8..2d3e6a925d 100644
--- a/activerecord/lib/active_record/connection_adapters/postgresql/oid/hstore.rb
+++ b/activerecord/lib/active_record/connection_adapters/postgresql/oid/hstore.rb
@@ -35,23 +35,23 @@ module ActiveRecord
private
- HstorePair = begin
- quoted_string = /"[^"\\]*(?:\\.[^"\\]*)*"/
- unquoted_string = /(?:\\.|[^\s,])[^\s=,\\]*(?:\\.[^\s=,\\]*|=[^,>])*/
- /(#{quoted_string}|#{unquoted_string})\s*=>\s*(#{quoted_string}|#{unquoted_string})/
- end
+ HstorePair = begin
+ quoted_string = /"[^"\\]*(?:\\.[^"\\]*)*"/
+ unquoted_string = /(?:\\.|[^\s,])[^\s=,\\]*(?:\\.[^\s=,\\]*|=[^,>])*/
+ /(#{quoted_string}|#{unquoted_string})\s*=>\s*(#{quoted_string}|#{unquoted_string})/
+ end
- def escape_hstore(value)
- if value.nil?
- "NULL"
- else
- if value == ""
- '""'
+ def escape_hstore(value)
+ if value.nil?
+ "NULL"
else
- '"%s"' % value.to_s.gsub(/(["\\])/, '\\\\\1')
+ if value == ""
+ '""'
+ else
+ '"%s"' % value.to_s.gsub(/(["\\])/, '\\\\\1')
+ end
end
end
- end
end
end
end
diff --git a/activerecord/lib/active_record/connection_adapters/postgresql/oid/point.rb b/activerecord/lib/active_record/connection_adapters/postgresql/oid/point.rb
index 3657f20433..bb4db2564c 100644
--- a/activerecord/lib/active_record/connection_adapters/postgresql/oid/point.rb
+++ b/activerecord/lib/active_record/connection_adapters/postgresql/oid/point.rb
@@ -33,9 +33,9 @@ module ActiveRecord
private
- def number_for_point(number)
- number.to_s.gsub(/\.0$/, "")
- end
+ def number_for_point(number)
+ number.to_s.gsub(/\.0$/, "")
+ end
end
end
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 3a52f05091..845ff5b6a9 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
@@ -15,7 +15,7 @@ module ActiveRecord
case value
when ::String
return if value.blank?
-
+
if value[0] == "(" && value[-1] == ")"
value = value[1...-1]
end
@@ -38,13 +38,13 @@ module ActiveRecord
private
- def number_for_point(number)
- number.to_s.gsub(/\.0$/, "")
- end
+ def number_for_point(number)
+ number.to_s.gsub(/\.0$/, "")
+ end
- def build_point(x, y)
- ActiveRecord::Point.new(Float(x), Float(y))
- end
+ def build_point(x, y)
+ ActiveRecord::Point.new(Float(x), Float(y))
+ end
end
end
end
diff --git a/activerecord/lib/active_record/connection_adapters/postgresql/oid/range.rb b/activerecord/lib/active_record/connection_adapters/postgresql/oid/range.rb
index 58bf5c5640..2c714f4018 100644
--- a/activerecord/lib/active_record/connection_adapters/postgresql/oid/range.rb
+++ b/activerecord/lib/active_record/connection_adapters/postgresql/oid/range.rb
@@ -55,37 +55,37 @@ module ActiveRecord
private
- def type_cast_single(value)
- infinity?(value) ? value : @subtype.deserialize(value)
- end
+ def type_cast_single(value)
+ infinity?(value) ? value : @subtype.deserialize(value)
+ end
- def type_cast_single_for_database(value)
- infinity?(value) ? "" : @subtype.serialize(value)
- end
+ def type_cast_single_for_database(value)
+ infinity?(value) ? "" : @subtype.serialize(value)
+ end
- def extract_bounds(value)
- from, to = value[1..-2].split(",")
- {
- from: (value[1] == "," || from == "-infinity") ? infinity(negative: true) : from,
- to: (value[-2] == "," || to == "infinity") ? infinity : to,
- exclude_start: (value[0] == "("),
- exclude_end: (value[-1] == ")")
- }
- end
+ def extract_bounds(value)
+ from, to = value[1..-2].split(",")
+ {
+ from: (value[1] == "," || from == "-infinity") ? infinity(negative: true) : from,
+ to: (value[-2] == "," || to == "infinity") ? infinity : to,
+ exclude_start: (value[0] == "("),
+ exclude_end: (value[-1] == ")")
+ }
+ end
- def infinity(negative: false)
- if subtype.respond_to?(:infinity)
- subtype.infinity(negative: negative)
- elsif negative
- -::Float::INFINITY
- else
- ::Float::INFINITY
+ def infinity(negative: false)
+ if subtype.respond_to?(:infinity)
+ subtype.infinity(negative: negative)
+ elsif negative
+ -::Float::INFINITY
+ else
+ ::Float::INFINITY
+ end
end
- end
- def infinity?(value)
- value.respond_to?(:infinite?) && value.infinite?
- end
+ def infinity?(value)
+ value.respond_to?(:infinite?) && value.infinite?
+ end
end
end
end
diff --git a/activerecord/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb b/activerecord/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb
index 3a75e8d69d..d9ae1aa7a2 100644
--- a/activerecord/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb
+++ b/activerecord/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb
@@ -42,66 +42,66 @@ module ActiveRecord
end
private
- def register_mapped_type(row)
- alias_type row["oid"], row["typname"]
- end
+ def register_mapped_type(row)
+ alias_type row["oid"], row["typname"]
+ end
- def register_enum_type(row)
- register row["oid"], OID::Enum.new
- end
+ def register_enum_type(row)
+ register row["oid"], OID::Enum.new
+ end
- def register_array_type(row)
- register_with_subtype(row["oid"], row["typelem"].to_i) do |subtype|
- OID::Array.new(subtype, row["typdelim"])
+ def register_array_type(row)
+ register_with_subtype(row["oid"], row["typelem"].to_i) do |subtype|
+ OID::Array.new(subtype, row["typdelim"])
+ end
end
- end
- def register_range_type(row)
- register_with_subtype(row["oid"], row["rngsubtype"].to_i) do |subtype|
- OID::Range.new(subtype, row["typname"].to_sym)
+ def register_range_type(row)
+ register_with_subtype(row["oid"], row["rngsubtype"].to_i) do |subtype|
+ OID::Range.new(subtype, row["typname"].to_sym)
+ end
end
- end
- def register_domain_type(row)
- if base_type = @store.lookup(row["typbasetype"].to_i)
- register row["oid"], base_type
- else
- warn "unknown base type (OID: #{row["typbasetype"]}) for domain #{row["typname"]}."
+ def register_domain_type(row)
+ if base_type = @store.lookup(row["typbasetype"].to_i)
+ register row["oid"], base_type
+ else
+ warn "unknown base type (OID: #{row["typbasetype"]}) for domain #{row["typname"]}."
+ end
end
- end
- def register_composite_type(row)
- if subtype = @store.lookup(row["typelem"].to_i)
- register row["oid"], OID::Vector.new(row["typdelim"], subtype)
+ def register_composite_type(row)
+ if subtype = @store.lookup(row["typelem"].to_i)
+ register row["oid"], OID::Vector.new(row["typdelim"], subtype)
+ end
end
- end
- def register(oid, oid_type = nil, &block)
- oid = assert_valid_registration(oid, oid_type || block)
- if block_given?
- @store.register_type(oid, &block)
- else
- @store.register_type(oid, oid_type)
+ def register(oid, oid_type = nil, &block)
+ oid = assert_valid_registration(oid, oid_type || block)
+ if block_given?
+ @store.register_type(oid, &block)
+ else
+ @store.register_type(oid, oid_type)
+ end
end
- end
- def alias_type(oid, target)
- oid = assert_valid_registration(oid, target)
- @store.alias_type(oid, target)
- end
+ def alias_type(oid, target)
+ oid = assert_valid_registration(oid, target)
+ @store.alias_type(oid, target)
+ end
- def register_with_subtype(oid, target_oid)
- if @store.key?(target_oid)
- register(oid) do |_, *args|
- yield @store.lookup(target_oid, *args)
+ def register_with_subtype(oid, target_oid)
+ if @store.key?(target_oid)
+ register(oid) do |_, *args|
+ yield @store.lookup(target_oid, *args)
+ end
end
end
- end
- def assert_valid_registration(oid, oid_type)
- raise ArgumentError, "can't register nil type for OID #{oid}" if oid_type.nil?
- oid.to_i
- end
+ def assert_valid_registration(oid, oid_type)
+ raise ArgumentError, "can't register nil type for OID #{oid}" if oid_type.nil?
+ oid.to_i
+ end
end
end
end
diff --git a/activerecord/lib/active_record/connection_adapters/postgresql/quoting.rb b/activerecord/lib/active_record/connection_adapters/postgresql/quoting.rb
index 90e88b1f3c..b5031d890f 100644
--- a/activerecord/lib/active_record/connection_adapters/postgresql/quoting.rb
+++ b/activerecord/lib/active_record/connection_adapters/postgresql/quoting.rb
@@ -74,42 +74,42 @@ module ActiveRecord
private
- def _quote(value)
- case value
- when Type::Binary::Data
- "'#{escape_bytea(value.to_s)}'"
- when OID::Xml::Data
- "xml '#{quote_string(value.to_s)}'"
- when OID::Bit::Data
- if value.binary?
- "B'#{value}'"
- elsif value.hex?
- "X'#{value}'"
- end
- when Float
- if value.infinite? || value.nan?
- "'#{value}'"
+ def _quote(value)
+ case value
+ when Type::Binary::Data
+ "'#{escape_bytea(value.to_s)}'"
+ when OID::Xml::Data
+ "xml '#{quote_string(value.to_s)}'"
+ when OID::Bit::Data
+ if value.binary?
+ "B'#{value}'"
+ elsif value.hex?
+ "X'#{value}'"
+ end
+ when Float
+ if value.infinite? || value.nan?
+ "'#{value}'"
+ else
+ super
+ end
else
super
end
- else
- super
end
- end
- def _type_cast(value)
- case value
- when Type::Binary::Data
- # Return a bind param hash with format as binary.
- # See http://deveiate.org/code/pg/PGconn.html#method-i-exec_prepared-doc
- # for more information
- { value: value.to_s, format: 1 }
- when OID::Xml::Data, OID::Bit::Data
- value.to_s
- else
- super
+ def _type_cast(value)
+ case value
+ when Type::Binary::Data
+ # Return a bind param hash with format as binary.
+ # See http://deveiate.org/code/pg/PGconn.html#method-i-exec_prepared-doc
+ # for more information
+ { value: value.to_s, format: 1 }
+ when OID::Xml::Data, OID::Bit::Data
+ value.to_s
+ else
+ super
+ end
end
- end
end
end
end
diff --git a/activerecord/lib/active_record/connection_adapters/postgresql/schema_dumper.rb b/activerecord/lib/active_record/connection_adapters/postgresql/schema_dumper.rb
index 2ed8f29b24..c20baf655c 100644
--- a/activerecord/lib/active_record/connection_adapters/postgresql/schema_dumper.rb
+++ b/activerecord/lib/active_record/connection_adapters/postgresql/schema_dumper.rb
@@ -24,23 +24,23 @@ module ActiveRecord
private
- def default_primary_key?(column)
- schema_type(column) == :serial
- end
+ def default_primary_key?(column)
+ schema_type(column) == :serial
+ end
- def schema_type(column)
- return super unless column.serial?
+ def schema_type(column)
+ return super unless column.serial?
- if column.bigint?
- :bigserial
- else
- :serial
+ if column.bigint?
+ :bigserial
+ else
+ :serial
+ end
end
- end
- def schema_expression(column)
- super unless column.serial?
- end
+ def schema_expression(column)
+ super unless column.serial?
+ 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 55c5fcafa6..56280f15e9 100644
--- a/activerecord/lib/active_record/connection_adapters/postgresql/schema_statements.rb
+++ b/activerecord/lib/active_record/connection_adapters/postgresql/schema_statements.rb
@@ -6,17 +6,17 @@ module ActiveRecord
class SchemaCreation < AbstractAdapter::SchemaCreation
private
- def visit_ColumnDefinition(o)
- o.sql_type = type_to_sql(o.type, o.limit, o.precision, o.scale, o.array)
- super
- end
+ def visit_ColumnDefinition(o)
+ o.sql_type = type_to_sql(o.type, o.limit, o.precision, o.scale, o.array)
+ super
+ end
- def add_column_options!(sql, options)
- if options[:collation]
- sql << " COLLATE \"#{options[:collation]}\""
+ def add_column_options!(sql, options)
+ if options[:collation]
+ sql << " COLLATE \"#{options[:collation]}\""
+ end
+ super
end
- super
- end
end
module SchemaStatements
diff --git a/activerecord/lib/active_record/connection_adapters/postgresql/type_metadata.rb b/activerecord/lib/active_record/connection_adapters/postgresql/type_metadata.rb
index b2c49989a4..bcef8ac715 100644
--- a/activerecord/lib/active_record/connection_adapters/postgresql/type_metadata.rb
+++ b/activerecord/lib/active_record/connection_adapters/postgresql/type_metadata.rb
@@ -27,9 +27,9 @@ module ActiveRecord
protected
- def attributes_for_hash
- [self.class, @type_metadata, oid, fmod]
- end
+ def attributes_for_hash
+ [self.class, @type_metadata, oid, fmod]
+ end
end
end
end
diff --git a/activerecord/lib/active_record/connection_adapters/sql_type_metadata.rb b/activerecord/lib/active_record/connection_adapters/sql_type_metadata.rb
index ccb7e154ee..9e12ae0de8 100644
--- a/activerecord/lib/active_record/connection_adapters/sql_type_metadata.rb
+++ b/activerecord/lib/active_record/connection_adapters/sql_type_metadata.rb
@@ -24,9 +24,9 @@ module ActiveRecord
protected
- def attributes_for_hash
- [self.class, sql_type, type, limit, precision, scale]
- end
+ def attributes_for_hash
+ [self.class, sql_type, type, limit, precision, scale]
+ end
end
end
end
diff --git a/activerecord/lib/active_record/connection_adapters/sqlite3/quoting.rb b/activerecord/lib/active_record/connection_adapters/sqlite3/quoting.rb
index fa20175b0e..f01ed67b0f 100644
--- a/activerecord/lib/active_record/connection_adapters/sqlite3/quoting.rb
+++ b/activerecord/lib/active_record/connection_adapters/sqlite3/quoting.rb
@@ -20,28 +20,28 @@ module ActiveRecord
private
- def _quote(value)
- if value.is_a?(Type::Binary::Data)
- "x'#{value.hex}'"
- else
- super
+ def _quote(value)
+ if value.is_a?(Type::Binary::Data)
+ "x'#{value.hex}'"
+ else
+ super
+ end
end
- end
- def _type_cast(value)
- case value
- when BigDecimal
- value.to_f
- when String
- if value.encoding == Encoding::ASCII_8BIT
- super(value.encode(Encoding::UTF_8))
+ def _type_cast(value)
+ case value
+ when BigDecimal
+ value.to_f
+ when String
+ if value.encoding == Encoding::ASCII_8BIT
+ super(value.encode(Encoding::UTF_8))
+ else
+ super
+ end
else
super
end
- else
- super
end
- end
end
end
end
diff --git a/activerecord/lib/active_record/connection_adapters/sqlite3_adapter.rb b/activerecord/lib/active_record/connection_adapters/sqlite3_adapter.rb
index 4558e1f80f..57699badba 100644
--- a/activerecord/lib/active_record/connection_adapters/sqlite3_adapter.rb
+++ b/activerecord/lib/active_record/connection_adapters/sqlite3_adapter.rb
@@ -70,9 +70,9 @@ module ActiveRecord
class StatementPool < ConnectionAdapters::StatementPool
private
- def dealloc(stmt)
- stmt[:stmt].close unless stmt[:stmt].closed?
- end
+ def dealloc(stmt)
+ stmt[:stmt].close unless stmt[:stmt].closed?
+ end
end
def schema_creation # :nodoc:
diff --git a/activerecord/lib/active_record/connection_adapters/statement_pool.rb b/activerecord/lib/active_record/connection_adapters/statement_pool.rb
index 9b0ed3e08b..273b1b0b5c 100644
--- a/activerecord/lib/active_record/connection_adapters/statement_pool.rb
+++ b/activerecord/lib/active_record/connection_adapters/statement_pool.rb
@@ -47,13 +47,13 @@ module ActiveRecord
private
- def cache
- @cache[Process.pid]
- end
+ def cache
+ @cache[Process.pid]
+ end
- def dealloc(stmt)
- raise NotImplementedError
- end
+ def dealloc(stmt)
+ raise NotImplementedError
+ end
end
end
end
diff --git a/activerecord/lib/active_record/core.rb b/activerecord/lib/active_record/core.rb
index 26a00e62d1..19a2720913 100644
--- a/activerecord/lib/active_record/core.rb
+++ b/activerecord/lib/active_record/core.rb
@@ -299,26 +299,26 @@ module ActiveRecord
private
- def cached_find_by_statement(key, &block) # :nodoc:
- cache = @find_by_statement_cache[connection.prepared_statements]
- cache[key] || cache.synchronize {
- cache[key] ||= StatementCache.create(connection, &block)
- }
- end
+ def cached_find_by_statement(key, &block) # :nodoc:
+ cache = @find_by_statement_cache[connection.prepared_statements]
+ cache[key] || cache.synchronize {
+ cache[key] ||= StatementCache.create(connection, &block)
+ }
+ end
- def relation # :nodoc:
- relation = Relation.create(self, arel_table, predicate_builder)
+ def relation # :nodoc:
+ relation = Relation.create(self, arel_table, predicate_builder)
- if finder_needs_type_condition? && !ignore_default_scope?
- relation.where(type_condition).create_with(inheritance_column.to_sym => sti_name)
- else
- relation
+ if finder_needs_type_condition? && !ignore_default_scope?
+ relation.where(type_condition).create_with(inheritance_column.to_sym => sti_name)
+ else
+ relation
+ end
end
- end
- def table_metadata # :nodoc:
- TableMetadata.new(self, arel_table)
- end
+ def table_metadata # :nodoc:
+ TableMetadata.new(self, arel_table)
+ end
end
# New objects can be instantiated as either empty (pass no construction parameter) or pre-set with
@@ -498,11 +498,11 @@ module ActiveRecord
# We check defined?(@attributes) not to issue warnings if the object is
# allocated but not initialized.
inspection = if defined?(@attributes) && @attributes
- self.class.column_names.collect { |name|
- if has_attribute?(name)
- "#{name}: #{attribute_for_inspect(name)}"
- end
- }.compact.join(", ")
+ self.class.column_names.collect { |name|
+ if has_attribute?(name)
+ "#{name}: #{attribute_for_inspect(name)}"
+ end
+ }.compact.join(", ")
else
"not initialized"
end
@@ -548,32 +548,32 @@ module ActiveRecord
# So we can avoid the method_missing hit by explicitly defining #to_ary as nil here.
#
# See also http://tenderlovemaking.com/2011/06/28/til-its-ok-to-return-nil-from-to_ary.html
- def to_ary # :nodoc:
- nil
- end
+ def to_ary # :nodoc:
+ nil
+ end
- def init_internals
- @readonly = false
- @destroyed = false
- @marked_for_destruction = false
- @destroyed_by_association = nil
- @new_record = true
- @txn = nil
- @_start_transaction_state = {}
- @transaction_state = nil
- end
+ def init_internals
+ @readonly = false
+ @destroyed = false
+ @marked_for_destruction = false
+ @destroyed_by_association = nil
+ @new_record = true
+ @txn = nil
+ @_start_transaction_state = {}
+ @transaction_state = nil
+ end
- def initialize_internals_callback
- end
+ def initialize_internals_callback
+ end
- def thaw
- if frozen?
- @attributes = @attributes.dup
+ def thaw
+ if frozen?
+ @attributes = @attributes.dup
+ end
end
- end
- def custom_inspect_method_defined?
- self.class.instance_method(:inspect).owner != ActiveRecord::Base.instance_method(:inspect).owner
- end
+ def custom_inspect_method_defined?
+ self.class.instance_method(:inspect).owner != ActiveRecord::Base.instance_method(:inspect).owner
+ end
end
end
diff --git a/activerecord/lib/active_record/dynamic_matchers.rb b/activerecord/lib/active_record/dynamic_matchers.rb
index b41546064b..fd2fa7410a 100644
--- a/activerecord/lib/active_record/dynamic_matchers.rb
+++ b/activerecord/lib/active_record/dynamic_matchers.rb
@@ -13,111 +13,111 @@ module ActiveRecord
private
- def method_missing(name, *arguments, &block)
- match = Method.match(self, name)
+ def method_missing(name, *arguments, &block)
+ match = Method.match(self, name)
- if match && match.valid?
- match.define
- send(name, *arguments, &block)
- else
- super
+ if match && match.valid?
+ match.define
+ send(name, *arguments, &block)
+ else
+ super
+ end
end
- end
- class Method
- @matchers = []
+ class Method
+ @matchers = []
- class << self
- attr_reader :matchers
+ class << self
+ attr_reader :matchers
- def match(model, name)
- klass = matchers.find { |k| k.pattern.match?(name) }
- klass.new(model, name) if klass
- end
+ def match(model, name)
+ klass = matchers.find { |k| k.pattern.match?(name) }
+ klass.new(model, name) if klass
+ end
- def pattern
- @pattern ||= /\A#{prefix}_([_a-zA-Z]\w*)#{suffix}\Z/
- end
+ def pattern
+ @pattern ||= /\A#{prefix}_([_a-zA-Z]\w*)#{suffix}\Z/
+ end
- def prefix
- raise NotImplementedError
- end
+ def prefix
+ raise NotImplementedError
+ end
- def suffix
- ""
+ def suffix
+ ""
+ end
end
- end
- attr_reader :model, :name, :attribute_names
+ attr_reader :model, :name, :attribute_names
- def initialize(model, name)
- @model = model
- @name = name.to_s
- @attribute_names = @name.match(self.class.pattern)[1].split("_and_")
- @attribute_names.map! { |n| @model.attribute_aliases[n] || n }
- end
+ def initialize(model, name)
+ @model = model
+ @name = name.to_s
+ @attribute_names = @name.match(self.class.pattern)[1].split("_and_")
+ @attribute_names.map! { |n| @model.attribute_aliases[n] || n }
+ end
- def valid?
- attribute_names.all? { |name| model.columns_hash[name] || model.reflect_on_aggregation(name.to_sym) }
- end
+ def valid?
+ attribute_names.all? { |name| model.columns_hash[name] || model.reflect_on_aggregation(name.to_sym) }
+ end
- def define
- model.class_eval <<-CODE, __FILE__, __LINE__ + 1
+ def define
+ model.class_eval <<-CODE, __FILE__, __LINE__ + 1
def self.#{name}(#{signature})
#{body}
end
CODE
- end
+ end
- private
+ private
- def body
- "#{finder}(#{attributes_hash})"
- end
+ def body
+ "#{finder}(#{attributes_hash})"
+ end
- # The parameters in the signature may have reserved Ruby words, in order
- # to prevent errors, we start each param name with `_`.
- def signature
- attribute_names.map { |name| "_#{name}" }.join(", ")
- end
+ # The parameters in the signature may have reserved Ruby words, in order
+ # to prevent errors, we start each param name with `_`.
+ def signature
+ attribute_names.map { |name| "_#{name}" }.join(", ")
+ end
- # Given that the parameters starts with `_`, the finder needs to use the
- # same parameter name.
- def attributes_hash
- "{" + attribute_names.map { |name| ":#{name} => _#{name}" }.join(",") + "}"
- end
+ # Given that the parameters starts with `_`, the finder needs to use the
+ # same parameter name.
+ def attributes_hash
+ "{" + attribute_names.map { |name| ":#{name} => _#{name}" }.join(",") + "}"
+ end
- def finder
- raise NotImplementedError
+ def finder
+ raise NotImplementedError
+ end
end
- end
- class FindBy < Method
- Method.matchers << self
+ class FindBy < Method
+ Method.matchers << self
- def self.prefix
- "find_by"
- end
+ def self.prefix
+ "find_by"
+ end
- def finder
- "find_by"
+ def finder
+ "find_by"
+ end
end
- end
- class FindByBang < Method
- Method.matchers << self
+ class FindByBang < Method
+ Method.matchers << self
- def self.prefix
- "find_by"
- end
+ def self.prefix
+ "find_by"
+ end
- def self.suffix
- "!"
- end
+ def self.suffix
+ "!"
+ end
- def finder
- "find_by!"
+ def finder
+ "find_by!"
+ end
end
- end
end
end
diff --git a/activerecord/lib/active_record/enum.rb b/activerecord/lib/active_record/enum.rb
index dcf1004879..73f122cfd7 100644
--- a/activerecord/lib/active_record/enum.rb
+++ b/activerecord/lib/active_record/enum.rb
@@ -142,7 +142,7 @@ module ActiveRecord
protected
- attr_reader :name, :mapping, :subtype
+ attr_reader :name, :mapping, :subtype
end
def enum(definitions)
diff --git a/activerecord/lib/active_record/fixtures.rb b/activerecord/lib/active_record/fixtures.rb
index babff9c284..0dc64c8853 100644
--- a/activerecord/lib/active_record/fixtures.rb
+++ b/activerecord/lib/active_record/fixtures.rb
@@ -426,9 +426,9 @@ module ActiveRecord
end
def self.default_fixture_table_name(fixture_set_name, config = ActiveRecord::Base) # :nodoc:
- "#{ config.table_name_prefix }"\
- "#{ fixture_set_name.tr('/', '_') }"\
- "#{ config.table_name_suffix }".to_sym
+ "#{ config.table_name_prefix }"\
+ "#{ fixture_set_name.tr('/', '_') }"\
+ "#{ config.table_name_suffix }".to_sym
end
def self.reset_cache
@@ -494,18 +494,18 @@ module ActiveRecord
private
- def insert_class(class_names, name, klass)
- # We only want to deal with AR objects.
- if klass && klass < ActiveRecord::Base
- class_names[name] = klass
- else
- class_names[name] = nil
+ def insert_class(class_names, name, klass)
+ # We only want to deal with AR objects.
+ if klass && klass < ActiveRecord::Base
+ class_names[name] = klass
+ else
+ class_names[name] = nil
+ end
end
- end
- def default_fixture_model(fs_name, config)
- ActiveRecord::FixtureSet.default_fixture_model_name(fs_name, config)
- end
+ def default_fixture_model(fs_name, config)
+ ActiveRecord::FixtureSet.default_fixture_model_name(fs_name, config)
+ end
end
def self.create_fixtures(fixtures_directory, fixture_set_names, class_names = {}, config = ActiveRecord::Base)
diff --git a/activerecord/lib/active_record/inheritance.rb b/activerecord/lib/active_record/inheritance.rb
index 5863f622b5..4adcd7e65c 100644
--- a/activerecord/lib/active_record/inheritance.rb
+++ b/activerecord/lib/active_record/inheritance.rb
@@ -134,83 +134,83 @@ module ActiveRecord
# Returns the class type of the record using the current module as a prefix. So descendants of
# MyApp::Business::Account would appear as MyApp::Business::AccountSubclass.
- def compute_type(type_name)
- if type_name.match(/^::/)
- # If the type is prefixed with a scope operator then we assume that
- # the type_name is an absolute reference.
- ActiveSupport::Dependencies.constantize(type_name)
- else
- # Build a list of candidates to search for
- candidates = []
- name.scan(/::|$/) { candidates.unshift "#{$`}::#{type_name}" }
- candidates << type_name
-
- candidates.each do |candidate|
- constant = ActiveSupport::Dependencies.safe_constantize(candidate)
- return constant if candidate == constant.to_s
- end
+ def compute_type(type_name)
+ if type_name.match(/^::/)
+ # If the type is prefixed with a scope operator then we assume that
+ # the type_name is an absolute reference.
+ ActiveSupport::Dependencies.constantize(type_name)
+ else
+ # Build a list of candidates to search for
+ candidates = []
+ name.scan(/::|$/) { candidates.unshift "#{$`}::#{type_name}" }
+ candidates << type_name
- raise NameError.new("uninitialized constant #{candidates.first}", candidates.first)
+ candidates.each do |candidate|
+ constant = ActiveSupport::Dependencies.safe_constantize(candidate)
+ return constant if candidate == constant.to_s
+ end
+
+ raise NameError.new("uninitialized constant #{candidates.first}", candidates.first)
+ end
end
- end
private
# Called by +instantiate+ to decide which class to use for a new
# record instance. For single-table inheritance, we check the record
# for a +type+ column and return the corresponding class.
- def discriminate_class_for_record(record)
- if using_single_table_inheritance?(record)
- find_sti_class(record[inheritance_column])
- else
- super
+ def discriminate_class_for_record(record)
+ if using_single_table_inheritance?(record)
+ find_sti_class(record[inheritance_column])
+ else
+ super
+ end
end
- end
- def using_single_table_inheritance?(record)
- record[inheritance_column].present? && has_attribute?(inheritance_column)
- end
+ def using_single_table_inheritance?(record)
+ record[inheritance_column].present? && has_attribute?(inheritance_column)
+ end
- def find_sti_class(type_name)
- type_name = base_class.type_for_attribute(inheritance_column).cast(type_name)
- subclass = begin
- if store_full_sti_class
- ActiveSupport::Dependencies.constantize(type_name)
- else
- compute_type(type_name)
+ def find_sti_class(type_name)
+ type_name = base_class.type_for_attribute(inheritance_column).cast(type_name)
+ subclass = begin
+ if store_full_sti_class
+ ActiveSupport::Dependencies.constantize(type_name)
+ else
+ compute_type(type_name)
+ end
+ rescue NameError
+ raise SubclassNotFound,
+ "The single-table inheritance mechanism failed to locate the subclass: '#{type_name}'. " \
+ "This error is raised because the column '#{inheritance_column}' is reserved for storing the class in case of inheritance. " \
+ "Please rename this column if you didn't intend it to be used for storing the inheritance class " \
+ "or overwrite #{name}.inheritance_column to use another column for that information."
end
- rescue NameError
- raise SubclassNotFound,
- "The single-table inheritance mechanism failed to locate the subclass: '#{type_name}'. " \
- "This error is raised because the column '#{inheritance_column}' is reserved for storing the class in case of inheritance. " \
- "Please rename this column if you didn't intend it to be used for storing the inheritance class " \
- "or overwrite #{name}.inheritance_column to use another column for that information."
- end
- unless subclass == self || descendants.include?(subclass)
- raise SubclassNotFound, "Invalid single-table inheritance type: #{subclass.name} is not a subclass of #{name}"
+ unless subclass == self || descendants.include?(subclass)
+ raise SubclassNotFound, "Invalid single-table inheritance type: #{subclass.name} is not a subclass of #{name}"
+ end
+ subclass
end
- subclass
- end
- def type_condition(table = arel_table)
- sti_column = arel_attribute(inheritance_column, table)
- sti_names = ([self] + descendants).map(&:sti_name)
+ def type_condition(table = arel_table)
+ sti_column = arel_attribute(inheritance_column, table)
+ sti_names = ([self] + descendants).map(&:sti_name)
- sti_column.in(sti_names)
- end
+ sti_column.in(sti_names)
+ end
# Detect the subclass from the inheritance column of attrs. If the inheritance column value
# is not self or a valid subclass, raises ActiveRecord::SubclassNotFound
- def subclass_from_attributes(attrs)
- attrs = attrs.to_h if attrs.respond_to?(:permitted?)
- if attrs.is_a?(Hash)
- subclass_name = attrs.with_indifferent_access[inheritance_column]
-
- if subclass_name.present?
- find_sti_class(subclass_name)
+ def subclass_from_attributes(attrs)
+ attrs = attrs.to_h if attrs.respond_to?(:permitted?)
+ if attrs.is_a?(Hash)
+ subclass_name = attrs.with_indifferent_access[inheritance_column]
+
+ if subclass_name.present?
+ find_sti_class(subclass_name)
+ end
end
end
- end
end
def initialize_dup(other)
@@ -220,21 +220,21 @@ module ActiveRecord
private
- def initialize_internals_callback
- super
- ensure_proper_type
- end
+ def initialize_internals_callback
+ super
+ ensure_proper_type
+ end
# Sets the attribute used for single table inheritance to this class name if this is not the
# ActiveRecord::Base descendant.
# Considering the hierarchy Reply < Message < ActiveRecord::Base, this makes it possible to
# do Reply.new without having to set <tt>Reply[Reply.inheritance_column] = "Reply"</tt> yourself.
# No such attribute would be set for objects of the Message class in that example.
- def ensure_proper_type
- klass = self.class
- if klass.finder_needs_type_condition?
- write_attribute(klass.inheritance_column, klass.sti_name)
+ def ensure_proper_type
+ klass = self.class
+ if klass.finder_needs_type_condition?
+ write_attribute(klass.inheritance_column, klass.sti_name)
+ end
end
- end
end
end
diff --git a/activerecord/lib/active_record/locking/optimistic.rb b/activerecord/lib/active_record/locking/optimistic.rb
index 5e519056a3..21a6a2c55f 100644
--- a/activerecord/lib/active_record/locking/optimistic.rb
+++ b/activerecord/lib/active_record/locking/optimistic.rb
@@ -132,56 +132,56 @@ module ActiveRecord
relation
end
- module ClassMethods
- DEFAULT_LOCKING_COLUMN = "lock_version"
-
- # Returns true if the +lock_optimistically+ flag is set to true
- # (which it is, by default) and the table includes the
- # +locking_column+ column (defaults to +lock_version+).
- def locking_enabled?
- lock_optimistically && columns_hash[locking_column]
- end
+ module ClassMethods
+ DEFAULT_LOCKING_COLUMN = "lock_version"
+
+ # Returns true if the +lock_optimistically+ flag is set to true
+ # (which it is, by default) and the table includes the
+ # +locking_column+ column (defaults to +lock_version+).
+ def locking_enabled?
+ lock_optimistically && columns_hash[locking_column]
+ end
- # Set the column to use for optimistic locking. Defaults to +lock_version+.
- def locking_column=(value)
- reload_schema_from_cache
- @locking_column = value.to_s
- end
+ # Set the column to use for optimistic locking. Defaults to +lock_version+.
+ def locking_column=(value)
+ reload_schema_from_cache
+ @locking_column = value.to_s
+ end
- # The version column used for optimistic locking. Defaults to +lock_version+.
- def locking_column
- @locking_column = DEFAULT_LOCKING_COLUMN unless defined?(@locking_column)
- @locking_column
- end
+ # The version column used for optimistic locking. Defaults to +lock_version+.
+ def locking_column
+ @locking_column = DEFAULT_LOCKING_COLUMN unless defined?(@locking_column)
+ @locking_column
+ end
- # Reset the column used for optimistic locking back to the +lock_version+ default.
- def reset_locking_column
- self.locking_column = DEFAULT_LOCKING_COLUMN
- end
+ # Reset the column used for optimistic locking back to the +lock_version+ default.
+ def reset_locking_column
+ self.locking_column = DEFAULT_LOCKING_COLUMN
+ end
- # Make sure the lock version column gets updated when counters are
- # updated.
- def update_counters(id, counters)
- counters = counters.merge(locking_column => 1) if locking_enabled?
- super
- end
+ # Make sure the lock version column gets updated when counters are
+ # updated.
+ def update_counters(id, counters)
+ counters = counters.merge(locking_column => 1) if locking_enabled?
+ super
+ end
- private
-
- # We need to apply this decorator here, rather than on module inclusion. The closure
- # created by the matcher would otherwise evaluate for `ActiveRecord::Base`, not the
- # sub class being decorated. As such, changes to `lock_optimistically`, or
- # `locking_column` would not be picked up.
- def inherited(subclass)
- subclass.class_eval do
- is_lock_column = ->(name, _) { lock_optimistically && name == locking_column }
- decorate_matching_attribute_types(is_lock_column, :_optimistic_locking) do |type|
- LockingType.new(type)
+ private
+
+ # We need to apply this decorator here, rather than on module inclusion. The closure
+ # created by the matcher would otherwise evaluate for `ActiveRecord::Base`, not the
+ # sub class being decorated. As such, changes to `lock_optimistically`, or
+ # `locking_column` would not be picked up.
+ def inherited(subclass)
+ subclass.class_eval do
+ is_lock_column = ->(name, _) { lock_optimistically && name == locking_column }
+ decorate_matching_attribute_types(is_lock_column, :_optimistic_locking) do |type|
+ LockingType.new(type)
+ end
+ end
+ super
end
- end
- super
end
- end
end
diff --git a/activerecord/lib/active_record/log_subscriber.rb b/activerecord/lib/active_record/log_subscriber.rb
index c4998ba686..bb9f898cf0 100644
--- a/activerecord/lib/active_record/log_subscriber.rb
+++ b/activerecord/lib/active_record/log_subscriber.rb
@@ -57,38 +57,38 @@ module ActiveRecord
private
- def colorize_payload_name(name, payload_name)
- if payload_name.blank? || payload_name == "SQL" # SQL vs Model Load/Exists
- color(name, MAGENTA, true)
- else
- color(name, CYAN, true)
+ def colorize_payload_name(name, payload_name)
+ if payload_name.blank? || payload_name == "SQL" # SQL vs Model Load/Exists
+ color(name, MAGENTA, true)
+ else
+ color(name, CYAN, true)
+ end
end
- end
- def sql_color(sql)
- case sql
- when /\A\s*rollback/mi
- RED
- when /select .*for update/mi, /\A\s*lock/mi
- WHITE
- when /\A\s*select/i
- BLUE
- when /\A\s*insert/i
- GREEN
- when /\A\s*update/i
- YELLOW
- when /\A\s*delete/i
- RED
- when /transaction\s*\Z/i
- CYAN
- else
- MAGENTA
+ def sql_color(sql)
+ case sql
+ when /\A\s*rollback/mi
+ RED
+ when /select .*for update/mi, /\A\s*lock/mi
+ WHITE
+ when /\A\s*select/i
+ BLUE
+ when /\A\s*insert/i
+ GREEN
+ when /\A\s*update/i
+ YELLOW
+ when /\A\s*delete/i
+ RED
+ when /transaction\s*\Z/i
+ CYAN
+ else
+ MAGENTA
+ end
end
- end
- def logger
- ActiveRecord::Base.logger
- end
+ def logger
+ ActiveRecord::Base.logger
+ end
end
end
diff --git a/activerecord/lib/active_record/migration.rb b/activerecord/lib/active_record/migration.rb
index 0066d30ca6..a8dbda118e 100644
--- a/activerecord/lib/active_record/migration.rb
+++ b/activerecord/lib/active_record/migration.rb
@@ -555,9 +555,9 @@ module ActiveRecord
private
- def connection
- ActiveRecord::Base.connection
- end
+ def connection
+ ActiveRecord::Base.connection
+ end
end
class << self
@@ -922,13 +922,13 @@ module ActiveRecord
end
private
- def execute_block
- if connection.respond_to? :execute_block
- super # use normal delegation to record the block
- else
- yield
+ def execute_block
+ if connection.respond_to? :execute_block
+ super # use normal delegation to record the block
+ else
+ yield
+ end
end
- end
end
# MigrationProxy is used to defer loading of the actual migration classes
@@ -1166,145 +1166,145 @@ module ActiveRecord
private
# Used for running a specific migration.
- def run_without_lock
- migration = migrations.detect { |m| m.version == @target_version }
- raise UnknownMigrationVersionError.new(@target_version) if migration.nil?
- execute_migration_in_transaction(migration, @direction)
+ def run_without_lock
+ migration = migrations.detect { |m| m.version == @target_version }
+ raise UnknownMigrationVersionError.new(@target_version) if migration.nil?
+ execute_migration_in_transaction(migration, @direction)
- record_environment
- end
+ record_environment
+ end
# Used for running multiple migrations up to or down to a certain value.
- def migrate_without_lock
- if invalid_target?
- raise UnknownMigrationVersionError.new(@target_version)
- end
+ def migrate_without_lock
+ if invalid_target?
+ raise UnknownMigrationVersionError.new(@target_version)
+ end
- runnable.each do |migration|
- execute_migration_in_transaction(migration, @direction)
- end
+ runnable.each do |migration|
+ execute_migration_in_transaction(migration, @direction)
+ end
- record_environment
- end
+ record_environment
+ end
# Stores the current environment in the database.
- def record_environment
- return if down?
- ActiveRecord::InternalMetadata[:environment] = ActiveRecord::Migrator.current_environment
- end
+ def record_environment
+ return if down?
+ ActiveRecord::InternalMetadata[:environment] = ActiveRecord::Migrator.current_environment
+ end
- def ran?(migration)
- migrated.include?(migration.version.to_i)
- end
+ def ran?(migration)
+ migrated.include?(migration.version.to_i)
+ end
# Return true if a valid version is not provided.
- def invalid_target?
- !target && @target_version && @target_version > 0
- end
+ def invalid_target?
+ !target && @target_version && @target_version > 0
+ end
- def execute_migration_in_transaction(migration, direction)
- return if down? && !migrated.include?(migration.version.to_i)
- return if up? && migrated.include?(migration.version.to_i)
+ def execute_migration_in_transaction(migration, direction)
+ return if down? && !migrated.include?(migration.version.to_i)
+ return if up? && migrated.include?(migration.version.to_i)
- Base.logger.info "Migrating to #{migration.name} (#{migration.version})" if Base.logger
+ Base.logger.info "Migrating to #{migration.name} (#{migration.version})" if Base.logger
- ddl_transaction(migration) do
- migration.migrate(direction)
- record_version_state_after_migrating(migration.version)
+ ddl_transaction(migration) do
+ migration.migrate(direction)
+ record_version_state_after_migrating(migration.version)
+ end
+ rescue => e
+ msg = "An error has occurred, "
+ msg << "this and " if use_transaction?(migration)
+ msg << "all later migrations canceled:\n\n#{e}"
+ raise StandardError, msg, e.backtrace
end
- rescue => e
- msg = "An error has occurred, "
- msg << "this and " if use_transaction?(migration)
- msg << "all later migrations canceled:\n\n#{e}"
- raise StandardError, msg, e.backtrace
- end
- def target
- migrations.detect { |m| m.version == @target_version }
- end
+ def target
+ migrations.detect { |m| m.version == @target_version }
+ end
- def finish
- migrations.index(target) || migrations.size - 1
- end
+ def finish
+ migrations.index(target) || migrations.size - 1
+ end
- def start
- up? ? 0 : (migrations.index(current) || 0)
- end
+ def start
+ up? ? 0 : (migrations.index(current) || 0)
+ end
- def validate(migrations)
- name ,= migrations.group_by(&:name).find { |_,v| v.length > 1 }
- raise DuplicateMigrationNameError.new(name) if name
+ def validate(migrations)
+ name ,= migrations.group_by(&:name).find { |_,v| v.length > 1 }
+ raise DuplicateMigrationNameError.new(name) if name
- version ,= migrations.group_by(&:version).find { |_,v| v.length > 1 }
- raise DuplicateMigrationVersionError.new(version) if version
- end
+ version ,= migrations.group_by(&:version).find { |_,v| v.length > 1 }
+ raise DuplicateMigrationVersionError.new(version) if version
+ end
- def record_version_state_after_migrating(version)
- if down?
- migrated.delete(version)
- ActiveRecord::SchemaMigration.where(version: version.to_s).delete_all
- else
- migrated << version
- ActiveRecord::SchemaMigration.create!(version: version.to_s)
+ def record_version_state_after_migrating(version)
+ if down?
+ migrated.delete(version)
+ ActiveRecord::SchemaMigration.where(version: version.to_s).delete_all
+ else
+ migrated << version
+ ActiveRecord::SchemaMigration.create!(version: version.to_s)
+ end
end
- end
- def self.last_stored_environment
- return nil if current_version == 0
- raise NoEnvironmentInSchemaError unless ActiveRecord::InternalMetadata.table_exists?
+ def self.last_stored_environment
+ return nil if current_version == 0
+ raise NoEnvironmentInSchemaError unless ActiveRecord::InternalMetadata.table_exists?
- environment = ActiveRecord::InternalMetadata[:environment]
- raise NoEnvironmentInSchemaError unless environment
- environment
- end
+ environment = ActiveRecord::InternalMetadata[:environment]
+ raise NoEnvironmentInSchemaError unless environment
+ environment
+ end
- def self.current_environment
- ActiveRecord::ConnectionHandling::DEFAULT_ENV.call
- end
+ def self.current_environment
+ ActiveRecord::ConnectionHandling::DEFAULT_ENV.call
+ end
- def self.protected_environment?
- ActiveRecord::Base.protected_environments.include?(last_stored_environment) if last_stored_environment
- end
+ def self.protected_environment?
+ ActiveRecord::Base.protected_environments.include?(last_stored_environment) if last_stored_environment
+ end
- def up?
- @direction == :up
- end
+ def up?
+ @direction == :up
+ end
- def down?
- @direction == :down
- end
+ def down?
+ @direction == :down
+ end
# Wrap the migration in a transaction only if supported by the adapter.
- def ddl_transaction(migration)
- if use_transaction?(migration)
- Base.transaction { yield }
- else
- yield
+ def ddl_transaction(migration)
+ if use_transaction?(migration)
+ Base.transaction { yield }
+ else
+ yield
+ end
end
- end
- def use_transaction?(migration)
- !migration.disable_ddl_transaction && Base.connection.supports_ddl_transactions?
- end
+ def use_transaction?(migration)
+ !migration.disable_ddl_transaction && Base.connection.supports_ddl_transactions?
+ end
- def use_advisory_lock?
- Base.connection.supports_advisory_locks?
- end
+ def use_advisory_lock?
+ Base.connection.supports_advisory_locks?
+ end
- def with_advisory_lock
- lock_id = generate_migrator_advisory_lock_id
- got_lock = Base.connection.get_advisory_lock(lock_id)
- raise ConcurrentMigrationError unless got_lock
- load_migrated # reload schema_migrations to be sure it wasn't changed by another process before we got the lock
- yield
- ensure
- Base.connection.release_advisory_lock(lock_id) if got_lock
- end
+ def with_advisory_lock
+ lock_id = generate_migrator_advisory_lock_id
+ got_lock = Base.connection.get_advisory_lock(lock_id)
+ raise ConcurrentMigrationError unless got_lock
+ load_migrated # reload schema_migrations to be sure it wasn't changed by another process before we got the lock
+ yield
+ ensure
+ Base.connection.release_advisory_lock(lock_id) if got_lock
+ end
- MIGRATOR_SALT = 2053462845
- def generate_migrator_advisory_lock_id
- db_name_hash = Zlib.crc32(Base.connection.current_database)
- MIGRATOR_SALT * db_name_hash
- end
+ MIGRATOR_SALT = 2053462845
+ def generate_migrator_advisory_lock_id
+ db_name_hash = Zlib.crc32(Base.connection.current_database)
+ MIGRATOR_SALT * db_name_hash
+ end
end
end
diff --git a/activerecord/lib/active_record/migration/command_recorder.rb b/activerecord/lib/active_record/migration/command_recorder.rb
index 0fa665c7e0..6b2c5d8da5 100644
--- a/activerecord/lib/active_record/migration/command_recorder.rb
+++ b/activerecord/lib/active_record/migration/command_recorder.rb
@@ -112,127 +112,127 @@ module ActiveRecord
private
- module StraightReversions
- private
- { transaction: :transaction,
- execute_block: :execute_block,
- create_table: :drop_table,
- create_join_table: :drop_join_table,
- add_column: :remove_column,
- add_timestamps: :remove_timestamps,
- add_reference: :remove_reference,
- enable_extension: :disable_extension
- }.each do |cmd, inv|
- [[inv, cmd], [cmd, inv]].uniq.each do |method, inverse|
- class_eval <<-EOV, __FILE__, __LINE__ + 1
+ module StraightReversions
+ private
+ { transaction: :transaction,
+ execute_block: :execute_block,
+ create_table: :drop_table,
+ create_join_table: :drop_join_table,
+ add_column: :remove_column,
+ add_timestamps: :remove_timestamps,
+ add_reference: :remove_reference,
+ enable_extension: :disable_extension
+ }.each do |cmd, inv|
+ [[inv, cmd], [cmd, inv]].uniq.each do |method, inverse|
+ class_eval <<-EOV, __FILE__, __LINE__ + 1
def invert_#{method}(args, &block) # def invert_create_table(args, &block)
[:#{inverse}, args, block] # [:drop_table, args, block]
end # end
EOV
- end
+ end
+ end
end
- end
- include StraightReversions
+ include StraightReversions
- def invert_drop_table(args, &block)
- if args.size == 1 && block == nil
- raise ActiveRecord::IrreversibleMigration, "To avoid mistakes, drop_table is only reversible if given options or a block (can be empty)."
+ def invert_drop_table(args, &block)
+ if args.size == 1 && block == nil
+ raise ActiveRecord::IrreversibleMigration, "To avoid mistakes, drop_table is only reversible if given options or a block (can be empty)."
+ end
+ super
end
- super
- end
- def invert_rename_table(args)
- [:rename_table, args.reverse]
- end
+ def invert_rename_table(args)
+ [:rename_table, args.reverse]
+ end
- def invert_remove_column(args)
- raise ActiveRecord::IrreversibleMigration, "remove_column is only reversible if given a type." if args.size <= 2
- super
- end
+ def invert_remove_column(args)
+ raise ActiveRecord::IrreversibleMigration, "remove_column is only reversible if given a type." if args.size <= 2
+ super
+ end
- def invert_rename_index(args)
- [:rename_index, [args.first] + args.last(2).reverse]
- end
+ def invert_rename_index(args)
+ [:rename_index, [args.first] + args.last(2).reverse]
+ end
- def invert_rename_column(args)
- [:rename_column, [args.first] + args.last(2).reverse]
- end
+ def invert_rename_column(args)
+ [:rename_column, [args.first] + args.last(2).reverse]
+ end
- def invert_add_index(args)
- table, columns, options = *args
- options ||= {}
+ def invert_add_index(args)
+ table, columns, options = *args
+ options ||= {}
- index_name = options[:name]
- options_hash = index_name ? { name: index_name } : { column: columns }
+ index_name = options[:name]
+ options_hash = index_name ? { name: index_name } : { column: columns }
- [:remove_index, [table, options_hash]]
- end
+ [:remove_index, [table, options_hash]]
+ end
- def invert_remove_index(args)
- table, options_or_column = *args
- if (options = options_or_column).is_a?(Hash)
- unless options[:column]
- raise ActiveRecord::IrreversibleMigration, "remove_index is only reversible if given a :column option."
+ def invert_remove_index(args)
+ table, options_or_column = *args
+ if (options = options_or_column).is_a?(Hash)
+ unless options[:column]
+ raise ActiveRecord::IrreversibleMigration, "remove_index is only reversible if given a :column option."
+ end
+ options = options.dup
+ [:add_index, [table, options.delete(:column), options]]
+ elsif (column = options_or_column).present?
+ [:add_index, [table, column]]
end
- options = options.dup
- [:add_index, [table, options.delete(:column), options]]
- elsif (column = options_or_column).present?
- [:add_index, [table, column]]
end
- end
- alias :invert_add_belongs_to :invert_add_reference
- alias :invert_remove_belongs_to :invert_remove_reference
+ alias :invert_add_belongs_to :invert_add_reference
+ alias :invert_remove_belongs_to :invert_remove_reference
+
+ def invert_change_column_default(args)
+ table, column, options = *args
- def invert_change_column_default(args)
- table, column, options = *args
+ unless options && options.is_a?(Hash) && options.has_key?(:from) && options.has_key?(:to)
+ raise ActiveRecord::IrreversibleMigration, "change_column_default is only reversible if given a :from and :to option."
+ end
- unless options && options.is_a?(Hash) && options.has_key?(:from) && options.has_key?(:to)
- raise ActiveRecord::IrreversibleMigration, "change_column_default is only reversible if given a :from and :to option."
+ [:change_column_default, [table, column, from: options[:to], to: options[:from]]]
end
- [:change_column_default, [table, column, from: options[:to], to: options[:from]]]
- end
+ def invert_change_column_null(args)
+ args[2] = !args[2]
+ [:change_column_null, args]
+ end
- def invert_change_column_null(args)
- args[2] = !args[2]
- [:change_column_null, args]
- end
+ def invert_add_foreign_key(args)
+ from_table, to_table, add_options = args
+ add_options ||= {}
- def invert_add_foreign_key(args)
- from_table, to_table, add_options = args
- add_options ||= {}
+ if add_options[:name]
+ options = { name: add_options[:name] }
+ elsif add_options[:column]
+ options = { column: add_options[:column] }
+ else
+ options = to_table
+ end
- if add_options[:name]
- options = { name: add_options[:name] }
- elsif add_options[:column]
- options = { column: add_options[:column] }
- else
- options = to_table
+ [:remove_foreign_key, [from_table, options]]
end
- [:remove_foreign_key, [from_table, options]]
- end
-
- def invert_remove_foreign_key(args)
- from_table, to_table, remove_options = args
- raise ActiveRecord::IrreversibleMigration, "remove_foreign_key is only reversible if given a second table" if to_table.nil? || to_table.is_a?(Hash)
+ def invert_remove_foreign_key(args)
+ from_table, to_table, remove_options = args
+ raise ActiveRecord::IrreversibleMigration, "remove_foreign_key is only reversible if given a second table" if to_table.nil? || to_table.is_a?(Hash)
- reversed_args = [from_table, to_table]
- reversed_args << remove_options if remove_options
+ reversed_args = [from_table, to_table]
+ reversed_args << remove_options if remove_options
- [:add_foreign_key, reversed_args]
- end
+ [:add_foreign_key, reversed_args]
+ end
# Forwards any missing method call to the \target.
- def method_missing(method, *args, &block)
- if @delegate.respond_to?(method)
- @delegate.send(method, *args, &block)
- else
- super
+ def method_missing(method, *args, &block)
+ if @delegate.respond_to?(method)
+ @delegate.send(method, *args, &block)
+ else
+ super
+ end
end
- end
end
end
end
diff --git a/activerecord/lib/active_record/migration/compatibility.rb b/activerecord/lib/active_record/migration/compatibility.rb
index 5baca7183b..a79251f908 100644
--- a/activerecord/lib/active_record/migration/compatibility.rb
+++ b/activerecord/lib/active_record/migration/compatibility.rb
@@ -83,23 +83,23 @@ module ActiveRecord
private
- def index_name_for_remove(table_name, options = {})
- index_name = index_name(table_name, options)
+ def index_name_for_remove(table_name, options = {})
+ index_name = index_name(table_name, options)
- unless index_name_exists?(table_name, index_name, true)
- if options.is_a?(Hash) && options.has_key?(:name)
- options_without_column = options.dup
- options_without_column.delete :column
- index_name_without_column = index_name(table_name, options_without_column)
+ unless index_name_exists?(table_name, index_name, true)
+ if options.is_a?(Hash) && options.has_key?(:name)
+ options_without_column = options.dup
+ options_without_column.delete :column
+ index_name_without_column = index_name(table_name, options_without_column)
- return index_name_without_column if index_name_exists?(table_name, index_name_without_column, false)
+ return index_name_without_column if index_name_exists?(table_name, index_name_without_column, false)
+ end
+
+ raise ArgumentError, "Index name '#{index_name}' on table '#{table_name}' does not exist"
end
- raise ArgumentError, "Index name '#{index_name}' on table '#{table_name}' does not exist"
+ index_name
end
-
- index_name
- end
end
class V5_0 < V5_1
diff --git a/activerecord/lib/active_record/migration/join_table.rb b/activerecord/lib/active_record/migration/join_table.rb
index 05569fadbd..89789f00ea 100644
--- a/activerecord/lib/active_record/migration/join_table.rb
+++ b/activerecord/lib/active_record/migration/join_table.rb
@@ -3,13 +3,13 @@ module ActiveRecord
module JoinTable #:nodoc:
private
- def find_join_table_name(table_1, table_2, options = {})
- options.delete(:table_name) || join_table_name(table_1, table_2)
- end
+ def find_join_table_name(table_1, table_2, options = {})
+ options.delete(:table_name) || join_table_name(table_1, table_2)
+ end
- def join_table_name(table_1, table_2)
- ModelSchema.derive_join_table_name(table_1, table_2).to_sym
- end
+ def join_table_name(table_1, table_2)
+ ModelSchema.derive_join_table_name(table_1, table_2).to_sym
+ end
end
end
end
diff --git a/activerecord/lib/active_record/model_schema.rb b/activerecord/lib/active_record/model_schema.rb
index 63312a8d11..1537fffc22 100644
--- a/activerecord/lib/active_record/model_schema.rb
+++ b/activerecord/lib/active_record/model_schema.rb
@@ -357,80 +357,80 @@ module ActiveRecord
private
- def schema_loaded?
- defined?(@columns_hash) && @columns_hash
- end
+ def schema_loaded?
+ defined?(@columns_hash) && @columns_hash
+ end
- def load_schema
- unless schema_loaded?
- load_schema!
+ def load_schema
+ unless schema_loaded?
+ load_schema!
+ end
end
- end
- def load_schema!
- @columns_hash = connection.schema_cache.columns_hash(table_name).except(*ignored_columns)
- @columns_hash.each do |name, column|
- warn_if_deprecated_type(column)
- define_attribute(
- name,
- connection.lookup_cast_type_from_column(column),
- default: column.default,
- user_provided_default: false
- )
+ def load_schema!
+ @columns_hash = connection.schema_cache.columns_hash(table_name).except(*ignored_columns)
+ @columns_hash.each do |name, column|
+ warn_if_deprecated_type(column)
+ define_attribute(
+ name,
+ connection.lookup_cast_type_from_column(column),
+ default: column.default,
+ user_provided_default: false
+ )
+ end
end
- end
- def reload_schema_from_cache
- @arel_engine = nil
- @arel_table = nil
- @column_names = nil
- @attribute_types = nil
- @content_columns = nil
- @default_attributes = nil
- @inheritance_column = nil unless defined?(@explicit_inheritance_column) && @explicit_inheritance_column
- @attributes_builder = nil
- @columns = nil
- @columns_hash = nil
- @attribute_names = nil
- @yaml_encoder = nil
- direct_descendants.each do |descendant|
- descendant.send(:reload_schema_from_cache)
+ def reload_schema_from_cache
+ @arel_engine = nil
+ @arel_table = nil
+ @column_names = nil
+ @attribute_types = nil
+ @content_columns = nil
+ @default_attributes = nil
+ @inheritance_column = nil unless defined?(@explicit_inheritance_column) && @explicit_inheritance_column
+ @attributes_builder = nil
+ @columns = nil
+ @columns_hash = nil
+ @attribute_names = nil
+ @yaml_encoder = nil
+ direct_descendants.each do |descendant|
+ descendant.send(:reload_schema_from_cache)
+ end
end
- end
# Guesses the table name, but does not decorate it with prefix and suffix information.
- def undecorated_table_name(class_name = base_class.name)
- table_name = class_name.to_s.demodulize.underscore
- pluralize_table_names ? table_name.pluralize : table_name
- end
+ def undecorated_table_name(class_name = base_class.name)
+ table_name = class_name.to_s.demodulize.underscore
+ pluralize_table_names ? table_name.pluralize : table_name
+ end
# Computes and returns a table name according to default conventions.
- def compute_table_name
- base = base_class
- if self == base
- # Nested classes are prefixed with singular parent table name.
- if parent < Base && !parent.abstract_class?
- contained = parent.table_name
- contained = contained.singularize if parent.pluralize_table_names
- contained += "_"
+ def compute_table_name
+ base = base_class
+ if self == base
+ # Nested classes are prefixed with singular parent table name.
+ if parent < Base && !parent.abstract_class?
+ contained = parent.table_name
+ contained = contained.singularize if parent.pluralize_table_names
+ contained += "_"
+ end
+
+ "#{full_table_name_prefix}#{contained}#{undecorated_table_name(name)}#{full_table_name_suffix}"
+ else
+ # STI subclasses always use their superclass' table.
+ base.table_name
end
-
- "#{full_table_name_prefix}#{contained}#{undecorated_table_name(name)}#{full_table_name_suffix}"
- else
- # STI subclasses always use their superclass' table.
- base.table_name
end
- end
- def warn_if_deprecated_type(column)
- return if attributes_to_define_after_schema_loads.key?(column.name)
- if column.respond_to?(:oid) && column.sql_type.start_with?("point")
- if column.array?
- array_arguments = ", array: true"
- else
- array_arguments = ""
- end
- ActiveSupport::Deprecation.warn(<<-WARNING.strip_heredoc)
+ def warn_if_deprecated_type(column)
+ return if attributes_to_define_after_schema_loads.key?(column.name)
+ if column.respond_to?(:oid) && column.sql_type.start_with?("point")
+ if column.array?
+ array_arguments = ", array: true"
+ else
+ array_arguments = ""
+ end
+ ActiveSupport::Deprecation.warn(<<-WARNING.strip_heredoc)
The behavior of the `:point` type will be changing in Rails 5.1 to
return a `Point` object, rather than an `Array`. If you'd like to
keep the old behavior, you can add this line to #{self.name}:
@@ -441,8 +441,8 @@ module ActiveRecord
attribute :#{column.name}, :point#{array_arguments}
WARNING
+ end
end
- end
end
end
end
diff --git a/activerecord/lib/active_record/nested_attributes.rb b/activerecord/lib/active_record/nested_attributes.rb
index c9fe1167e8..682b404060 100644
--- a/activerecord/lib/active_record/nested_attributes.rb
+++ b/activerecord/lib/active_record/nested_attributes.rb
@@ -352,8 +352,8 @@ module ActiveRecord
# This redirects the attempts to write objects in an association through
# the helper methods defined below. Makes it seem like the nested
# associations are just regular associations.
- def generate_association_writer(association_name, type)
- generated_association_methods.module_eval <<-eoruby, __FILE__, __LINE__ + 1
+ def generate_association_writer(association_name, type)
+ generated_association_methods.module_eval <<-eoruby, __FILE__, __LINE__ + 1
if method_defined?(:#{association_name}_attributes=)
remove_method(:#{association_name}_attributes=)
end
@@ -361,7 +361,7 @@ module ActiveRecord
assign_nested_attributes_for_#{type}_association(:#{association_name}, attributes)
end
eoruby
- end
+ end
end
# Returns ActiveRecord::AutosaveAssociation::marked_for_destruction? It's
@@ -377,7 +377,7 @@ module ActiveRecord
# Attribute hash keys that should not be assigned as normal attributes.
# These hash keys are nested attributes implementation details.
- UNASSIGNABLE_KEYS = %w( id _destroy )
+ UNASSIGNABLE_KEYS = %w( id _destroy )
# Assigns the given attributes to the association.
#
@@ -392,37 +392,37 @@ module ActiveRecord
# If the given attributes include a matching <tt>:id</tt> attribute, or
# update_only is true, and a <tt>:_destroy</tt> key set to a truthy value,
# then the existing record will be marked for destruction.
- def assign_nested_attributes_for_one_to_one_association(association_name, attributes)
- options = self.nested_attributes_options[association_name]
- if attributes.respond_to?(:permitted?)
- attributes = attributes.to_h
- end
- attributes = attributes.with_indifferent_access
- existing_record = send(association_name)
+ def assign_nested_attributes_for_one_to_one_association(association_name, attributes)
+ options = self.nested_attributes_options[association_name]
+ if attributes.respond_to?(:permitted?)
+ attributes = attributes.to_h
+ end
+ attributes = attributes.with_indifferent_access
+ existing_record = send(association_name)
- if (options[:update_only] || !attributes["id"].blank?) && existing_record &&
- (options[:update_only] || existing_record.id.to_s == attributes["id"].to_s)
- assign_to_or_mark_for_destruction(existing_record, attributes, options[:allow_destroy]) unless call_reject_if(association_name, attributes)
+ if (options[:update_only] || !attributes["id"].blank?) && existing_record &&
+ (options[:update_only] || existing_record.id.to_s == attributes["id"].to_s)
+ assign_to_or_mark_for_destruction(existing_record, attributes, options[:allow_destroy]) unless call_reject_if(association_name, attributes)
- elsif attributes["id"].present?
- raise_nested_attributes_record_not_found!(association_name, attributes["id"])
+ elsif attributes["id"].present?
+ raise_nested_attributes_record_not_found!(association_name, attributes["id"])
- elsif !reject_new_record?(association_name, attributes)
- assignable_attributes = attributes.except(*UNASSIGNABLE_KEYS)
+ elsif !reject_new_record?(association_name, attributes)
+ assignable_attributes = attributes.except(*UNASSIGNABLE_KEYS)
- if existing_record && existing_record.new_record?
- existing_record.assign_attributes(assignable_attributes)
- association(association_name).initialize_attributes(existing_record)
- else
- method = "build_#{association_name}"
- if respond_to?(method)
- send(method, assignable_attributes)
+ if existing_record && existing_record.new_record?
+ existing_record.assign_attributes(assignable_attributes)
+ association(association_name).initialize_attributes(existing_record)
else
- raise ArgumentError, "Cannot build association `#{association_name}'. Are you trying to build a polymorphic one-to-one association?"
+ method = "build_#{association_name}"
+ if respond_to?(method)
+ send(method, assignable_attributes)
+ else
+ raise ArgumentError, "Cannot build association `#{association_name}'. Are you trying to build a polymorphic one-to-one association?"
+ end
end
end
end
- end
# Assigns the given attributes to the collection association.
#
@@ -451,65 +451,65 @@ module ActiveRecord
# { name: 'John' },
# { id: '2', _destroy: true }
# ])
- def assign_nested_attributes_for_collection_association(association_name, attributes_collection)
- options = self.nested_attributes_options[association_name]
- if attributes_collection.respond_to?(:permitted?)
- attributes_collection = attributes_collection.to_h
- end
+ def assign_nested_attributes_for_collection_association(association_name, attributes_collection)
+ options = self.nested_attributes_options[association_name]
+ if attributes_collection.respond_to?(:permitted?)
+ attributes_collection = attributes_collection.to_h
+ end
- unless attributes_collection.is_a?(Hash) || attributes_collection.is_a?(Array)
- raise ArgumentError, "Hash or Array expected, got #{attributes_collection.class.name} (#{attributes_collection.inspect})"
- end
+ unless attributes_collection.is_a?(Hash) || attributes_collection.is_a?(Array)
+ raise ArgumentError, "Hash or Array expected, got #{attributes_collection.class.name} (#{attributes_collection.inspect})"
+ end
- check_record_limit!(options[:limit], attributes_collection)
+ check_record_limit!(options[:limit], attributes_collection)
- if attributes_collection.is_a? Hash
- keys = attributes_collection.keys
- attributes_collection = if keys.include?("id") || keys.include?(:id)
- [attributes_collection]
- else
- attributes_collection.values
+ if attributes_collection.is_a? Hash
+ keys = attributes_collection.keys
+ attributes_collection = if keys.include?("id") || keys.include?(:id)
+ [attributes_collection]
+ else
+ attributes_collection.values
+ end
end
- end
-
- association = association(association_name)
- existing_records = if association.loaded?
- association.target
- else
- attribute_ids = attributes_collection.map {|a| a["id"] || a[:id] }.compact
- attribute_ids.empty? ? [] : association.scope.where(association.klass.primary_key => attribute_ids)
- end
+ association = association(association_name)
- attributes_collection.each do |attributes|
- if attributes.respond_to?(:permitted?)
- attributes = attributes.to_h
+ existing_records = if association.loaded?
+ association.target
+ else
+ attribute_ids = attributes_collection.map {|a| a["id"] || a[:id] }.compact
+ attribute_ids.empty? ? [] : association.scope.where(association.klass.primary_key => attribute_ids)
end
- attributes = attributes.with_indifferent_access
- if attributes["id"].blank?
- unless reject_new_record?(association_name, attributes)
- association.build(attributes.except(*UNASSIGNABLE_KEYS))
+ attributes_collection.each do |attributes|
+ if attributes.respond_to?(:permitted?)
+ attributes = attributes.to_h
end
- elsif existing_record = existing_records.detect { |record| record.id.to_s == attributes["id"].to_s }
- unless call_reject_if(association_name, attributes)
- # Make sure we are operating on the actual object which is in the association's
- # proxy_target array (either by finding it, or adding it if not found)
- # Take into account that the proxy_target may have changed due to callbacks
- target_record = association.target.detect { |record| record.id.to_s == attributes["id"].to_s }
- if target_record
- existing_record = target_record
- else
- association.add_to_target(existing_record, :skip_callbacks)
- end
+ attributes = attributes.with_indifferent_access
- assign_to_or_mark_for_destruction(existing_record, attributes, options[:allow_destroy])
+ if attributes["id"].blank?
+ unless reject_new_record?(association_name, attributes)
+ association.build(attributes.except(*UNASSIGNABLE_KEYS))
+ end
+ elsif existing_record = existing_records.detect { |record| record.id.to_s == attributes["id"].to_s }
+ unless call_reject_if(association_name, attributes)
+ # Make sure we are operating on the actual object which is in the association's
+ # proxy_target array (either by finding it, or adding it if not found)
+ # Take into account that the proxy_target may have changed due to callbacks
+ target_record = association.target.detect { |record| record.id.to_s == attributes["id"].to_s }
+ if target_record
+ existing_record = target_record
+ else
+ association.add_to_target(existing_record, :skip_callbacks)
+ end
+
+ assign_to_or_mark_for_destruction(existing_record, attributes, options[:allow_destroy])
+ end
+ else
+ raise_nested_attributes_record_not_found!(association_name, attributes["id"])
end
- else
- raise_nested_attributes_record_not_found!(association_name, attributes["id"])
end
end
- end
# Takes in a limit and checks if the attributes_collection has too many
# records. It accepts limit in the form of symbol, proc, or
@@ -517,71 +517,71 @@ module ActiveRecord
#
# Raises TooManyRecords error if the attributes_collection is
# larger than the limit.
- def check_record_limit!(limit, attributes_collection)
- if limit
- limit = case limit
- when Symbol
- send(limit)
- when Proc
- limit.call
- else
- limit
- end
+ def check_record_limit!(limit, attributes_collection)
+ if limit
+ limit = case limit
+ when Symbol
+ send(limit)
+ when Proc
+ limit.call
+ else
+ limit
+ end
- if limit && attributes_collection.size > limit
- raise TooManyRecords, "Maximum #{limit} records are allowed. Got #{attributes_collection.size} records instead."
+ if limit && attributes_collection.size > limit
+ raise TooManyRecords, "Maximum #{limit} records are allowed. Got #{attributes_collection.size} records instead."
+ end
end
end
- end
# Updates a record with the +attributes+ or marks it for destruction if
# +allow_destroy+ is +true+ and has_destroy_flag? returns +true+.
- def assign_to_or_mark_for_destruction(record, attributes, allow_destroy)
- record.assign_attributes(attributes.except(*UNASSIGNABLE_KEYS))
- record.mark_for_destruction if has_destroy_flag?(attributes) && allow_destroy
- end
+ def assign_to_or_mark_for_destruction(record, attributes, allow_destroy)
+ record.assign_attributes(attributes.except(*UNASSIGNABLE_KEYS))
+ record.mark_for_destruction if has_destroy_flag?(attributes) && allow_destroy
+ end
# Determines if a hash contains a truthy _destroy key.
- def has_destroy_flag?(hash)
- Type::Boolean.new.cast(hash["_destroy"])
- end
+ def has_destroy_flag?(hash)
+ Type::Boolean.new.cast(hash["_destroy"])
+ end
# Determines if a new record should be rejected by checking
# has_destroy_flag? or if a <tt>:reject_if</tt> proc exists for this
# association and evaluates to +true+.
- def reject_new_record?(association_name, attributes)
- will_be_destroyed?(association_name, attributes) || call_reject_if(association_name, attributes)
- end
+ def reject_new_record?(association_name, attributes)
+ will_be_destroyed?(association_name, attributes) || call_reject_if(association_name, attributes)
+ end
# Determines if a record with the particular +attributes+ should be
# rejected by calling the reject_if Symbol or Proc (if defined).
# The reject_if option is defined by +accepts_nested_attributes_for+.
#
# Returns false if there is a +destroy_flag+ on the attributes.
- def call_reject_if(association_name, attributes)
- return false if will_be_destroyed?(association_name, attributes)
-
- case callback = self.nested_attributes_options[association_name][:reject_if]
- when Symbol
- method(callback).arity == 0 ? send(callback) : send(callback, attributes)
- when Proc
- callback.call(attributes)
+ def call_reject_if(association_name, attributes)
+ return false if will_be_destroyed?(association_name, attributes)
+
+ case callback = self.nested_attributes_options[association_name][:reject_if]
+ when Symbol
+ method(callback).arity == 0 ? send(callback) : send(callback, attributes)
+ when Proc
+ callback.call(attributes)
+ end
end
- end
# Only take into account the destroy flag if <tt>:allow_destroy</tt> is true
- def will_be_destroyed?(association_name, attributes)
- allow_destroy?(association_name) && has_destroy_flag?(attributes)
- end
+ def will_be_destroyed?(association_name, attributes)
+ allow_destroy?(association_name) && has_destroy_flag?(attributes)
+ end
- def allow_destroy?(association_name)
- self.nested_attributes_options[association_name][:allow_destroy]
- end
+ def allow_destroy?(association_name)
+ self.nested_attributes_options[association_name][:allow_destroy]
+ end
- def raise_nested_attributes_record_not_found!(association_name, record_id)
- model = self.class._reflect_on_association(association_name).klass.name
- raise RecordNotFound.new("Couldn't find #{model} with ID=#{record_id} for #{self.class.name} with ID=#{id}",
- model, "id", record_id)
- end
+ def raise_nested_attributes_record_not_found!(association_name, record_id)
+ model = self.class._reflect_on_association(association_name).klass.name
+ raise RecordNotFound.new("Couldn't find #{model} with ID=#{record_id} for #{self.class.name} with ID=#{id}",
+ model, "id", record_id)
+ end
end
end
diff --git a/activerecord/lib/active_record/railties/databases.rake b/activerecord/lib/active_record/railties/databases.rake
index 3532465fee..6f0dbeb9e5 100644
--- a/activerecord/lib/active_record/railties/databases.rake
+++ b/activerecord/lib/active_record/railties/databases.rake
@@ -204,13 +204,13 @@ db_namespace = namespace :db do
base_dir = ActiveRecord::Tasks::DatabaseTasks.fixtures_path
fixtures_dir = if ENV["FIXTURES_DIR"]
- File.join base_dir, ENV["FIXTURES_DIR"]
+ File.join base_dir, ENV["FIXTURES_DIR"]
else
base_dir
end
fixture_files = if ENV["FIXTURES"]
- ENV["FIXTURES"].split(",")
+ ENV["FIXTURES"].split(",")
else
# The use of String#[] here is to support namespaced fixtures
Dir["#{fixtures_dir}/**/*.yml"].map {|f| f[(fixtures_dir.size + 1)..-5] }
diff --git a/activerecord/lib/active_record/relation.rb b/activerecord/lib/active_record/relation.rb
index e96adc9af8..60ccb73d50 100644
--- a/activerecord/lib/active_record/relation.rb
+++ b/activerecord/lib/active_record/relation.rb
@@ -685,48 +685,48 @@ module ActiveRecord
private
- def exec_queries
- @records = eager_loading? ? find_with_associations.freeze : @klass.find_by_sql(arel, bound_attributes).freeze
-
- preload = preload_values
- preload += includes_values unless eager_loading?
- preloader = build_preloader
- preload.each do |associations|
- preloader.preload @records, associations
- end
+ def exec_queries
+ @records = eager_loading? ? find_with_associations.freeze : @klass.find_by_sql(arel, bound_attributes).freeze
+
+ preload = preload_values
+ preload += includes_values unless eager_loading?
+ preloader = build_preloader
+ preload.each do |associations|
+ preloader.preload @records, associations
+ end
- @records.each(&:readonly!) if readonly_value
+ @records.each(&:readonly!) if readonly_value
- @loaded = true
- @records
- end
+ @loaded = true
+ @records
+ end
- def build_preloader
- ActiveRecord::Associations::Preloader.new
- end
+ def build_preloader
+ ActiveRecord::Associations::Preloader.new
+ end
- def references_eager_loaded_tables?
- joined_tables = arel.join_sources.map do |join|
- if join.is_a?(Arel::Nodes::StringJoin)
- tables_in_string(join.left)
- else
- [join.left.table_name, join.left.table_alias]
+ def references_eager_loaded_tables?
+ joined_tables = arel.join_sources.map do |join|
+ if join.is_a?(Arel::Nodes::StringJoin)
+ tables_in_string(join.left)
+ else
+ [join.left.table_name, join.left.table_alias]
+ end
end
- end
- joined_tables += [table.name, table.table_alias]
+ joined_tables += [table.name, table.table_alias]
- # always convert table names to downcase as in Oracle quoted table names are in uppercase
- joined_tables = joined_tables.flatten.compact.map(&:downcase).uniq
+ # always convert table names to downcase as in Oracle quoted table names are in uppercase
+ joined_tables = joined_tables.flatten.compact.map(&:downcase).uniq
- (references_values - joined_tables).any?
- end
+ (references_values - joined_tables).any?
+ end
- def tables_in_string(string)
- return [] if string.blank?
- # always convert table names to downcase as in Oracle quoted table names are in uppercase
- # ignore raw_sql_ that is used by Oracle adapter as alias for limit/offset subqueries
- string.scan(/([a-zA-Z_][.\w]+).?\./).flatten.map(&:downcase).uniq - ["raw_sql_"]
- end
+ def tables_in_string(string)
+ return [] if string.blank?
+ # always convert table names to downcase as in Oracle quoted table names are in uppercase
+ # ignore raw_sql_ that is used by Oracle adapter as alias for limit/offset subqueries
+ string.scan(/([a-zA-Z_][.\w]+).?\./).flatten.map(&:downcase).uniq - ["raw_sql_"]
+ end
end
end
diff --git a/activerecord/lib/active_record/relation/batches.rb b/activerecord/lib/active_record/relation/batches.rb
index f4dd106edf..4b2987ac6d 100644
--- a/activerecord/lib/active_record/relation/batches.rb
+++ b/activerecord/lib/active_record/relation/batches.rb
@@ -249,24 +249,24 @@ module ActiveRecord
private
- def apply_limits(relation, start, finish)
- relation = relation.where(arel_attribute(primary_key).gteq(start)) if start
- relation = relation.where(arel_attribute(primary_key).lteq(finish)) if finish
- relation
- end
+ def apply_limits(relation, start, finish)
+ relation = relation.where(arel_attribute(primary_key).gteq(start)) if start
+ relation = relation.where(arel_attribute(primary_key).lteq(finish)) if finish
+ relation
+ end
- def batch_order
- "#{quoted_table_name}.#{quoted_primary_key} ASC"
- end
+ def batch_order
+ "#{quoted_table_name}.#{quoted_primary_key} ASC"
+ end
- def act_on_ignored_order(error_on_ignore)
- raise_error = (error_on_ignore.nil? ? self.klass.error_on_ignored_order : error_on_ignore)
+ def act_on_ignored_order(error_on_ignore)
+ raise_error = (error_on_ignore.nil? ? self.klass.error_on_ignored_order : error_on_ignore)
- if raise_error
- raise ArgumentError.new(ORDER_IGNORE_MESSAGE)
- elsif logger
- logger.warn(ORDER_IGNORE_MESSAGE)
+ if raise_error
+ raise ArgumentError.new(ORDER_IGNORE_MESSAGE)
+ elsif logger
+ logger.warn(ORDER_IGNORE_MESSAGE)
+ end
end
- end
end
end
diff --git a/activerecord/lib/active_record/relation/calculations.rb b/activerecord/lib/active_record/relation/calculations.rb
index 4af9f0859a..233a0622d5 100644
--- a/activerecord/lib/active_record/relation/calculations.rb
+++ b/activerecord/lib/active_record/relation/calculations.rb
@@ -185,147 +185,147 @@ module ActiveRecord
private
- def has_include?(column_name)
- eager_loading? || (includes_values.present? && column_name && column_name != :all)
- end
+ def has_include?(column_name)
+ eager_loading? || (includes_values.present? && column_name && column_name != :all)
+ end
- def perform_calculation(operation, column_name)
- operation = operation.to_s.downcase
+ def perform_calculation(operation, column_name)
+ operation = operation.to_s.downcase
- # If #count is used with #distinct (i.e. `relation.distinct.count`) it is
- # considered distinct.
- distinct = self.distinct_value
+ # If #count is used with #distinct (i.e. `relation.distinct.count`) it is
+ # considered distinct.
+ distinct = self.distinct_value
- if operation == "count"
- column_name ||= select_for_count
+ if operation == "count"
+ column_name ||= select_for_count
+
+ unless arel.ast.grep(Arel::Nodes::OuterJoin).empty?
+ distinct = true
+ end
- unless arel.ast.grep(Arel::Nodes::OuterJoin).empty?
- distinct = true
+ column_name = primary_key if column_name == :all && distinct
+ distinct = nil if column_name =~ /\s*DISTINCT[\s(]+/i
end
- column_name = primary_key if column_name == :all && distinct
- distinct = nil if column_name =~ /\s*DISTINCT[\s(]+/i
+ if group_values.any?
+ execute_grouped_calculation(operation, column_name, distinct)
+ else
+ execute_simple_calculation(operation, column_name, distinct)
+ end
end
- if group_values.any?
- execute_grouped_calculation(operation, column_name, distinct)
- else
- execute_simple_calculation(operation, column_name, distinct)
- end
- end
+ def aggregate_column(column_name)
+ return column_name if Arel::Expressions === column_name
- def aggregate_column(column_name)
- return column_name if Arel::Expressions === column_name
+ if @klass.column_names.include?(column_name.to_s)
+ Arel::Attribute.new(@klass.unscoped.table, column_name)
+ else
+ Arel.sql(column_name == :all ? "*" : column_name.to_s)
+ end
+ end
- if @klass.column_names.include?(column_name.to_s)
- Arel::Attribute.new(@klass.unscoped.table, column_name)
- else
- Arel.sql(column_name == :all ? "*" : column_name.to_s)
+ def operation_over_aggregate_column(column, operation, distinct)
+ operation == "count" ? column.count(distinct) : column.send(operation)
end
- end
- def operation_over_aggregate_column(column, operation, distinct)
- operation == "count" ? column.count(distinct) : column.send(operation)
- end
+ def execute_simple_calculation(operation, column_name, distinct) #:nodoc:
+ # PostgreSQL doesn't like ORDER BY when there are no GROUP BY
+ relation = unscope(:order)
- def execute_simple_calculation(operation, column_name, distinct) #:nodoc:
- # PostgreSQL doesn't like ORDER BY when there are no GROUP BY
- relation = unscope(:order)
+ column_alias = column_name
- column_alias = column_name
+ if operation == "count" && (relation.limit_value || relation.offset_value)
+ # Shortcut when limit is zero.
+ return 0 if relation.limit_value == 0
- if operation == "count" && (relation.limit_value || relation.offset_value)
- # Shortcut when limit is zero.
- return 0 if relation.limit_value == 0
+ query_builder = build_count_subquery(relation, column_name, distinct)
+ else
+ column = aggregate_column(column_name)
- query_builder = build_count_subquery(relation, column_name, distinct)
- else
- column = aggregate_column(column_name)
+ select_value = operation_over_aggregate_column(column, operation, distinct)
- select_value = operation_over_aggregate_column(column, operation, distinct)
+ column_alias = select_value.alias
+ column_alias ||= @klass.connection.column_name_for_operation(operation, select_value)
+ relation.select_values = [select_value]
- column_alias = select_value.alias
- column_alias ||= @klass.connection.column_name_for_operation(operation, select_value)
- relation.select_values = [select_value]
+ query_builder = relation.arel
+ end
- query_builder = relation.arel
- end
+ result = @klass.connection.select_all(query_builder, nil, bound_attributes)
+ row = result.first
+ value = row && row.values.first
+ column = result.column_types.fetch(column_alias) do
+ type_for(column_name)
+ end
- result = @klass.connection.select_all(query_builder, nil, bound_attributes)
- row = result.first
- value = row && row.values.first
- column = result.column_types.fetch(column_alias) do
- type_for(column_name)
+ type_cast_calculated_value(value, column, operation)
end
- type_cast_calculated_value(value, column, operation)
- end
+ def execute_grouped_calculation(operation, column_name, distinct) #:nodoc:
+ group_attrs = group_values
- def execute_grouped_calculation(operation, column_name, distinct) #:nodoc:
- group_attrs = group_values
-
- if group_attrs.first.respond_to?(:to_sym)
- association = @klass._reflect_on_association(group_attrs.first)
- associated = group_attrs.size == 1 && association && association.belongs_to? # only count belongs_to associations
- group_fields = Array(associated ? association.foreign_key : group_attrs)
- else
- group_fields = group_attrs
- end
- group_fields = arel_columns(group_fields)
+ if group_attrs.first.respond_to?(:to_sym)
+ association = @klass._reflect_on_association(group_attrs.first)
+ associated = group_attrs.size == 1 && association && association.belongs_to? # only count belongs_to associations
+ group_fields = Array(associated ? association.foreign_key : group_attrs)
+ else
+ group_fields = group_attrs
+ end
+ group_fields = arel_columns(group_fields)
- group_aliases = group_fields.map { |field| column_alias_for(field) }
- group_columns = group_aliases.zip(group_fields)
+ group_aliases = group_fields.map { |field| column_alias_for(field) }
+ group_columns = group_aliases.zip(group_fields)
- if operation == "count" && column_name == :all
- aggregate_alias = "count_all"
- else
- aggregate_alias = column_alias_for([operation, column_name].join(" "))
- end
-
- select_values = [
- operation_over_aggregate_column(
- aggregate_column(column_name),
- operation,
- distinct).as(aggregate_alias)
- ]
- select_values += select_values unless having_clause.empty?
-
- select_values.concat group_columns.map { |aliaz, field|
- if field.respond_to?(:as)
- field.as(aliaz)
+ if operation == "count" && column_name == :all
+ aggregate_alias = "count_all"
else
- "#{field} AS #{aliaz}"
+ aggregate_alias = column_alias_for([operation, column_name].join(" "))
end
- }
- relation = except(:group)
- relation.group_values = group_fields
- relation.select_values = select_values
+ select_values = [
+ operation_over_aggregate_column(
+ aggregate_column(column_name),
+ operation,
+ distinct).as(aggregate_alias)
+ ]
+ select_values += select_values unless having_clause.empty?
+
+ select_values.concat group_columns.map { |aliaz, field|
+ if field.respond_to?(:as)
+ field.as(aliaz)
+ else
+ "#{field} AS #{aliaz}"
+ end
+ }
- calculated_data = @klass.connection.select_all(relation, nil, relation.bound_attributes)
+ relation = except(:group)
+ relation.group_values = group_fields
+ relation.select_values = select_values
- if association
- key_ids = calculated_data.collect { |row| row[group_aliases.first] }
- key_records = association.klass.base_class.where(association.klass.base_class.primary_key => key_ids)
- key_records = Hash[key_records.map { |r| [r.id, r] }]
- end
+ calculated_data = @klass.connection.select_all(relation, nil, relation.bound_attributes)
- Hash[calculated_data.map do |row|
- key = group_columns.map { |aliaz, col_name|
- column = type_for(col_name) do
- calculated_data.column_types.fetch(aliaz) do
- Type::Value.new
- end
- end
- type_cast_calculated_value(row[aliaz], column)
- }
- key = key.first if key.size == 1
- key = key_records[key] if associated
+ if association
+ key_ids = calculated_data.collect { |row| row[group_aliases.first] }
+ key_records = association.klass.base_class.where(association.klass.base_class.primary_key => key_ids)
+ key_records = Hash[key_records.map { |r| [r.id, r] }]
+ end
- column_type = calculated_data.column_types.fetch(aggregate_alias) { type_for(column_name) }
- [key, type_cast_calculated_value(row[aggregate_alias], column_type, operation)]
- end]
- end
+ Hash[calculated_data.map do |row|
+ key = group_columns.map { |aliaz, col_name|
+ column = type_for(col_name) do
+ calculated_data.column_types.fetch(aliaz) do
+ Type::Value.new
+ end
+ end
+ type_cast_calculated_value(row[aliaz], column)
+ }
+ key = key.first if key.size == 1
+ key = key_records[key] if associated
+
+ column_type = calculated_data.column_types.fetch(aggregate_alias) { type_for(column_name) }
+ [key, type_cast_calculated_value(row[aggregate_alias], column_type, operation)]
+ end]
+ end
# Converts the given keys to the value that the database adapter returns as
# a usable column name:
@@ -334,54 +334,54 @@ module ActiveRecord
# column_alias_for("sum(id)") # => "sum_id"
# column_alias_for("count(distinct users.id)") # => "count_distinct_users_id"
# column_alias_for("count(*)") # => "count_all"
- def column_alias_for(keys)
- if keys.respond_to? :name
- keys = "#{keys.relation.name}.#{keys.name}"
- end
+ def column_alias_for(keys)
+ if keys.respond_to? :name
+ keys = "#{keys.relation.name}.#{keys.name}"
+ end
- table_name = keys.to_s.downcase
- table_name.gsub!(/\*/, "all")
- table_name.gsub!(/\W+/, " ")
- table_name.strip!
- table_name.gsub!(/ +/, "_")
+ table_name = keys.to_s.downcase
+ table_name.gsub!(/\*/, "all")
+ table_name.gsub!(/\W+/, " ")
+ table_name.strip!
+ table_name.gsub!(/ +/, "_")
- @klass.connection.table_alias_for(table_name)
- end
+ @klass.connection.table_alias_for(table_name)
+ end
- def type_for(field, &block)
- field_name = field.respond_to?(:name) ? field.name.to_s : field.to_s.split(".").last
- @klass.type_for_attribute(field_name, &block)
- end
+ def type_for(field, &block)
+ field_name = field.respond_to?(:name) ? field.name.to_s : field.to_s.split(".").last
+ @klass.type_for_attribute(field_name, &block)
+ end
- def type_cast_calculated_value(value, type, operation = nil)
- case operation
- when "count" then value.to_i
- when "sum" then type.deserialize(value || 0)
- when "average" then value.respond_to?(:to_d) ? value.to_d : value
- else type.deserialize(value)
+ def type_cast_calculated_value(value, type, operation = nil)
+ case operation
+ when "count" then value.to_i
+ when "sum" then type.deserialize(value || 0)
+ when "average" then value.respond_to?(:to_d) ? value.to_d : value
+ else type.deserialize(value)
+ end
end
- end
- def select_for_count
- if select_values.present?
- return select_values.first if select_values.one?
- select_values.join(", ")
- else
- :all
+ def select_for_count
+ if select_values.present?
+ return select_values.first if select_values.one?
+ select_values.join(", ")
+ else
+ :all
+ end
end
- end
- def build_count_subquery(relation, column_name, distinct)
- column_alias = Arel.sql("count_column")
- subquery_alias = Arel.sql("subquery_for_count")
+ def build_count_subquery(relation, column_name, distinct)
+ column_alias = Arel.sql("count_column")
+ subquery_alias = Arel.sql("subquery_for_count")
- aliased_column = aggregate_column(column_name == :all ? 1 : column_name).as(column_alias)
- relation.select_values = [aliased_column]
- subquery = relation.arel.as(subquery_alias)
+ aliased_column = aggregate_column(column_name == :all ? 1 : column_name).as(column_alias)
+ relation.select_values = [aliased_column]
+ subquery = relation.arel.as(subquery_alias)
- sm = Arel::SelectManager.new relation.engine
- select_value = operation_over_aggregate_column(column_alias, "count", distinct)
- sm.project(select_value).from(subquery)
- end
+ sm = Arel::SelectManager.new relation.engine
+ select_value = operation_over_aggregate_column(column_alias, "count", distinct)
+ sm.project(select_value).from(subquery)
+ end
end
end
diff --git a/activerecord/lib/active_record/relation/delegation.rb b/activerecord/lib/active_record/relation/delegation.rb
index 6b28d85a49..b4147ce434 100644
--- a/activerecord/lib/active_record/relation/delegation.rb
+++ b/activerecord/lib/active_record/relation/delegation.rb
@@ -83,17 +83,17 @@ module ActiveRecord
protected
- def method_missing(method, *args, &block)
- if @klass.respond_to?(method)
- self.class.delegate_to_scoped_klass(method)
- scoping { @klass.public_send(method, *args, &block) }
- elsif arel.respond_to?(method)
- self.class.delegate method, to: :arel
- arel.public_send(method, *args, &block)
- else
- super
+ def method_missing(method, *args, &block)
+ if @klass.respond_to?(method)
+ self.class.delegate_to_scoped_klass(method)
+ scoping { @klass.public_send(method, *args, &block) }
+ elsif arel.respond_to?(method)
+ self.class.delegate method, to: :arel
+ arel.public_send(method, *args, &block)
+ else
+ super
+ end
end
- end
end
module ClassMethods # :nodoc:
@@ -103,9 +103,9 @@ module ActiveRecord
private
- def relation_class_for(klass)
- klass.relation_delegate_class(self)
- end
+ def relation_class_for(klass)
+ klass.relation_delegate_class(self)
+ end
end
def respond_to?(method, include_private = false)
@@ -115,14 +115,14 @@ module ActiveRecord
protected
- def method_missing(method, *args, &block)
- if @klass.respond_to?(method)
- scoping { @klass.public_send(method, *args, &block) }
- elsif arel.respond_to?(method)
- arel.public_send(method, *args, &block)
- else
- super
+ def method_missing(method, *args, &block)
+ if @klass.respond_to?(method)
+ scoping { @klass.public_send(method, *args, &block) }
+ elsif arel.respond_to?(method)
+ arel.public_send(method, *args, &block)
+ else
+ super
+ end
end
- end
end
end
diff --git a/activerecord/lib/active_record/relation/finder_methods.rb b/activerecord/lib/active_record/relation/finder_methods.rb
index 6241e0dbdb..6349701dba 100644
--- a/activerecord/lib/active_record/relation/finder_methods.rb
+++ b/activerecord/lib/active_record/relation/finder_methods.rb
@@ -361,232 +361,232 @@ module ActiveRecord
private
- def offset_index
- offset_value || 0
- end
+ def offset_index
+ offset_value || 0
+ end
- def find_with_associations
- # NOTE: the JoinDependency constructed here needs to know about
- # any joins already present in `self`, so pass them in
- #
- # failing to do so means that in cases like activerecord/test/cases/associations/inner_join_association_test.rb:136
- # incorrect SQL is generated. In that case, the join dependency for
- # SpecialCategorizations is constructed without knowledge of the
- # preexisting join in joins_values to categorizations (by way of
- # the `has_many :through` for categories).
- #
- join_dependency = construct_join_dependency(joins_values)
-
- aliases = join_dependency.aliases
- relation = select aliases.columns
- relation = apply_join_dependency(relation, join_dependency)
-
- if block_given?
- yield relation
- else
- if ActiveRecord::NullRelation === relation
- []
+ def find_with_associations
+ # NOTE: the JoinDependency constructed here needs to know about
+ # any joins already present in `self`, so pass them in
+ #
+ # failing to do so means that in cases like activerecord/test/cases/associations/inner_join_association_test.rb:136
+ # incorrect SQL is generated. In that case, the join dependency for
+ # SpecialCategorizations is constructed without knowledge of the
+ # preexisting join in joins_values to categorizations (by way of
+ # the `has_many :through` for categories).
+ #
+ join_dependency = construct_join_dependency(joins_values)
+
+ aliases = join_dependency.aliases
+ relation = select aliases.columns
+ relation = apply_join_dependency(relation, join_dependency)
+
+ if block_given?
+ yield relation
else
- arel = relation.arel
- rows = connection.select_all(arel, "SQL", relation.bound_attributes)
- join_dependency.instantiate(rows, aliases)
+ if ActiveRecord::NullRelation === relation
+ []
+ else
+ arel = relation.arel
+ rows = connection.select_all(arel, "SQL", relation.bound_attributes)
+ join_dependency.instantiate(rows, aliases)
+ end
end
end
- end
- def construct_join_dependency(joins = [], eager_loading: true)
- including = eager_load_values + includes_values
- ActiveRecord::Associations::JoinDependency.new(@klass, including, joins, eager_loading: eager_loading)
- end
+ def construct_join_dependency(joins = [], eager_loading: true)
+ including = eager_load_values + includes_values
+ ActiveRecord::Associations::JoinDependency.new(@klass, including, joins, eager_loading: eager_loading)
+ end
- def construct_relation_for_association_calculations
- apply_join_dependency(self, construct_join_dependency(joins_values))
- end
+ def construct_relation_for_association_calculations
+ apply_join_dependency(self, construct_join_dependency(joins_values))
+ end
- def apply_join_dependency(relation, join_dependency)
- relation = relation.except(:includes, :eager_load, :preload)
- relation = relation.joins join_dependency
+ def apply_join_dependency(relation, join_dependency)
+ relation = relation.except(:includes, :eager_load, :preload)
+ relation = relation.joins join_dependency
- if using_limitable_reflections?(join_dependency.reflections)
- relation
- else
- if relation.limit_value
- limited_ids = limited_ids_for(relation)
- limited_ids.empty? ? relation.none! : relation.where!(primary_key => limited_ids)
+ if using_limitable_reflections?(join_dependency.reflections)
+ relation
+ else
+ if relation.limit_value
+ limited_ids = limited_ids_for(relation)
+ limited_ids.empty? ? relation.none! : relation.where!(primary_key => limited_ids)
+ end
+ relation.except(:limit, :offset)
end
- relation.except(:limit, :offset)
end
- end
- def limited_ids_for(relation)
- values = @klass.connection.columns_for_distinct(
- "#{quoted_table_name}.#{quoted_primary_key}", relation.order_values)
+ def limited_ids_for(relation)
+ values = @klass.connection.columns_for_distinct(
+ "#{quoted_table_name}.#{quoted_primary_key}", relation.order_values)
- relation = relation.except(:select).select(values).distinct!
- arel = relation.arel
+ relation = relation.except(:select).select(values).distinct!
+ arel = relation.arel
- id_rows = @klass.connection.select_all(arel, "SQL", relation.bound_attributes)
- id_rows.map {|row| row[primary_key]}
- end
+ id_rows = @klass.connection.select_all(arel, "SQL", relation.bound_attributes)
+ id_rows.map {|row| row[primary_key]}
+ end
- def using_limitable_reflections?(reflections)
- reflections.none?(&:collection?)
- end
+ def using_limitable_reflections?(reflections)
+ reflections.none?(&:collection?)
+ end
protected
- def find_with_ids(*ids)
- raise UnknownPrimaryKey.new(@klass) if primary_key.nil?
+ def find_with_ids(*ids)
+ raise UnknownPrimaryKey.new(@klass) if primary_key.nil?
- expects_array = ids.first.kind_of?(Array)
- return ids.first if expects_array && ids.first.empty?
+ expects_array = ids.first.kind_of?(Array)
+ return ids.first if expects_array && ids.first.empty?
- ids = ids.flatten.compact.uniq
+ ids = ids.flatten.compact.uniq
- case ids.size
- when 0
- raise RecordNotFound, "Couldn't find #{@klass.name} without an ID"
- when 1
- result = find_one(ids.first)
- expects_array ? [ result ] : result
- else
- find_some(ids)
+ case ids.size
+ when 0
+ raise RecordNotFound, "Couldn't find #{@klass.name} without an ID"
+ when 1
+ result = find_one(ids.first)
+ expects_array ? [ result ] : result
+ else
+ find_some(ids)
+ end
+ rescue RangeError
+ raise RecordNotFound, "Couldn't find #{@klass.name} with an out of range ID"
end
- rescue RangeError
- raise RecordNotFound, "Couldn't find #{@klass.name} with an out of range ID"
- end
- def find_one(id)
- if ActiveRecord::Base === id
- id = id.id
- ActiveSupport::Deprecation.warn(<<-MSG.squish)
+ def find_one(id)
+ if ActiveRecord::Base === id
+ id = id.id
+ ActiveSupport::Deprecation.warn(<<-MSG.squish)
You are passing an instance of ActiveRecord::Base to `find`.
Please pass the id of the object by calling `.id`.
MSG
- end
+ end
- relation = where(primary_key => id)
- record = relation.take
+ relation = where(primary_key => id)
+ record = relation.take
- raise_record_not_found_exception!(id, 0, 1) unless record
+ raise_record_not_found_exception!(id, 0, 1) unless record
- record
- end
+ record
+ end
- def find_some(ids)
- return find_some_ordered(ids) unless order_values.present?
+ def find_some(ids)
+ return find_some_ordered(ids) unless order_values.present?
- result = where(primary_key => ids).to_a
+ result = where(primary_key => ids).to_a
- expected_size =
- if limit_value && ids.size > limit_value
- limit_value
- else
- ids.size
- end
+ expected_size =
+ if limit_value && ids.size > limit_value
+ limit_value
+ else
+ ids.size
+ end
- # 11 ids with limit 3, offset 9 should give 2 results.
- if offset_value && (ids.size - offset_value < expected_size)
- expected_size = ids.size - offset_value
- end
+ # 11 ids with limit 3, offset 9 should give 2 results.
+ if offset_value && (ids.size - offset_value < expected_size)
+ expected_size = ids.size - offset_value
+ end
- if result.size == expected_size
- result
- else
- raise_record_not_found_exception!(ids, result.size, expected_size)
+ if result.size == expected_size
+ result
+ else
+ raise_record_not_found_exception!(ids, result.size, expected_size)
+ end
end
- end
- def find_some_ordered(ids)
- ids = ids.slice(offset_value || 0, limit_value || ids.size) || []
+ def find_some_ordered(ids)
+ ids = ids.slice(offset_value || 0, limit_value || ids.size) || []
- result = except(:limit, :offset).where(primary_key => ids).records
+ result = except(:limit, :offset).where(primary_key => ids).records
- if result.size == ids.size
- pk_type = @klass.type_for_attribute(primary_key)
+ if result.size == ids.size
+ pk_type = @klass.type_for_attribute(primary_key)
- records_by_id = result.index_by(&:id)
- ids.map { |id| records_by_id.fetch(pk_type.cast(id)) }
- else
- raise_record_not_found_exception!(ids, result.size, ids.size)
+ records_by_id = result.index_by(&:id)
+ ids.map { |id| records_by_id.fetch(pk_type.cast(id)) }
+ else
+ raise_record_not_found_exception!(ids, result.size, ids.size)
+ end
end
- end
- def find_take
- if loaded?
- records.first
- else
- @take ||= limit(1).records.first
+ def find_take
+ if loaded?
+ records.first
+ else
+ @take ||= limit(1).records.first
+ end
end
- end
- def find_nth(index, offset = nil)
- # TODO: once the offset argument is removed we rely on offset_index
- # within find_nth_with_limit, rather than pass it in via
- # find_nth_with_limit_and_offset
- if offset
- ActiveSupport::Deprecation.warn(<<-MSG.squish)
+ def find_nth(index, offset = nil)
+ # TODO: once the offset argument is removed we rely on offset_index
+ # within find_nth_with_limit, rather than pass it in via
+ # find_nth_with_limit_and_offset
+ if offset
+ ActiveSupport::Deprecation.warn(<<-MSG.squish)
Passing an offset argument to find_nth is deprecated,
please use Relation#offset instead.
MSG
+ end
+ if loaded?
+ records[index]
+ else
+ offset ||= offset_index
+ @offsets[offset + index] ||= find_nth_with_limit_and_offset(index, 1, offset: offset).first
+ end
end
- if loaded?
- records[index]
- else
- offset ||= offset_index
- @offsets[offset + index] ||= find_nth_with_limit_and_offset(index, 1, offset: offset).first
- end
- end
- def find_nth!(index)
- find_nth(index) or raise RecordNotFound.new("Couldn't find #{@klass.name} with [#{arel.where_sql(@klass.arel_engine)}]")
- end
-
- def find_nth_with_limit(index, limit)
- # TODO: once the offset argument is removed from find_nth,
- # find_nth_with_limit_and_offset can be merged into this method
- relation = if order_values.empty? && primary_key
- order(arel_attribute(primary_key).asc)
- else
- self
- end
-
- relation = relation.offset(index) unless index.zero?
- relation.limit(limit).to_a
- end
+ def find_nth!(index)
+ find_nth(index) or raise RecordNotFound.new("Couldn't find #{@klass.name} with [#{arel.where_sql(@klass.arel_engine)}]")
+ end
- def find_nth_from_last(index)
- if loaded?
- records[-index]
- else
+ def find_nth_with_limit(index, limit)
+ # TODO: once the offset argument is removed from find_nth,
+ # find_nth_with_limit_and_offset can be merged into this method
relation = if order_values.empty? && primary_key
- order(arel_attribute(primary_key).asc)
+ order(arel_attribute(primary_key).asc)
else
self
end
- relation.to_a[-index]
- # TODO: can be made more performant on large result sets by
- # for instance, last(index)[-index] (which would require
- # refactoring the last(n) finder method to make test suite pass),
- # or by using a combination of reverse_order, limit, and offset,
- # e.g., reverse_order.offset(index-1).first
+ relation = relation.offset(index) unless index.zero?
+ relation.limit(limit).to_a
+ end
+
+ def find_nth_from_last(index)
+ if loaded?
+ records[-index]
+ else
+ relation = if order_values.empty? && primary_key
+ order(arel_attribute(primary_key).asc)
+ else
+ self
+ end
+
+ relation.to_a[-index]
+ # TODO: can be made more performant on large result sets by
+ # for instance, last(index)[-index] (which would require
+ # refactoring the last(n) finder method to make test suite pass),
+ # or by using a combination of reverse_order, limit, and offset,
+ # e.g., reverse_order.offset(index-1).first
+ end
end
- end
private
- def find_nth_with_limit_and_offset(index, limit, offset:) # :nodoc:
- if loaded?
- records[index, limit]
- else
- index += offset
- find_nth_with_limit(index, limit)
+ def find_nth_with_limit_and_offset(index, limit, offset:) # :nodoc:
+ if loaded?
+ records[index, limit]
+ else
+ index += offset
+ find_nth_with_limit(index, limit)
+ end
end
- end
- def find_last(limit)
- limit ? records.last(limit) : records.last
- end
+ def find_last(limit)
+ limit ? records.last(limit) : records.last
+ end
end
end
diff --git a/activerecord/lib/active_record/relation/merger.rb b/activerecord/lib/active_record/relation/merger.rb
index 87a97803d5..df43b5c64b 100644
--- a/activerecord/lib/active_record/relation/merger.rb
+++ b/activerecord/lib/active_record/relation/merger.rb
@@ -83,85 +83,85 @@ module ActiveRecord
private
- def merge_preloads
- return if other.preload_values.empty? && other.includes_values.empty?
-
- if other.klass == relation.klass
- relation.preload!(*other.preload_values) unless other.preload_values.empty?
- relation.includes!(other.includes_values) unless other.includes_values.empty?
- else
- reflection = relation.klass.reflect_on_all_associations.find do |r|
- r.class_name == other.klass.name
- end || return
-
- unless other.preload_values.empty?
- relation.preload! reflection.name => other.preload_values
- end
+ def merge_preloads
+ return if other.preload_values.empty? && other.includes_values.empty?
+
+ if other.klass == relation.klass
+ relation.preload!(*other.preload_values) unless other.preload_values.empty?
+ relation.includes!(other.includes_values) unless other.includes_values.empty?
+ else
+ reflection = relation.klass.reflect_on_all_associations.find do |r|
+ r.class_name == other.klass.name
+ end || return
- unless other.includes_values.empty?
- relation.includes! reflection.name => other.includes_values
+ unless other.preload_values.empty?
+ relation.preload! reflection.name => other.preload_values
+ end
+
+ unless other.includes_values.empty?
+ relation.includes! reflection.name => other.includes_values
+ end
end
end
- end
- def merge_joins
- return if other.joins_values.blank?
+ def merge_joins
+ return if other.joins_values.blank?
- if other.klass == relation.klass
- relation.joins!(*other.joins_values)
- else
- joins_dependency, rest = other.joins_values.partition do |join|
- case join
- when Hash, Symbol, Array
- true
- else
- false
+ if other.klass == relation.klass
+ relation.joins!(*other.joins_values)
+ else
+ joins_dependency, rest = other.joins_values.partition do |join|
+ case join
+ when Hash, Symbol, Array
+ true
+ else
+ false
+ end
end
- end
- join_dependency = ActiveRecord::Associations::JoinDependency.new(other.klass,
- joins_dependency,
- [])
- relation.joins! rest
+ join_dependency = ActiveRecord::Associations::JoinDependency.new(other.klass,
+ joins_dependency,
+ [])
+ relation.joins! rest
- @relation = relation.joins join_dependency
+ @relation = relation.joins join_dependency
+ end
end
- end
- def merge_multi_values
- if other.reordering_value
- # override any order specified in the original relation
- relation.reorder! other.order_values
- elsif other.order_values
- # merge in order_values from relation
- relation.order! other.order_values
+ def merge_multi_values
+ if other.reordering_value
+ # override any order specified in the original relation
+ relation.reorder! other.order_values
+ elsif other.order_values
+ # merge in order_values from relation
+ relation.order! other.order_values
+ end
+
+ relation.extend(*other.extending_values) unless other.extending_values.blank?
end
- relation.extend(*other.extending_values) unless other.extending_values.blank?
- end
+ def merge_single_values
+ if relation.from_clause.empty?
+ relation.from_clause = other.from_clause
+ end
+ relation.lock_value ||= other.lock_value
- def merge_single_values
- if relation.from_clause.empty?
- relation.from_clause = other.from_clause
+ unless other.create_with_value.blank?
+ relation.create_with_value = (relation.create_with_value || {}).merge(other.create_with_value)
+ end
end
- relation.lock_value ||= other.lock_value
- unless other.create_with_value.blank?
- relation.create_with_value = (relation.create_with_value || {}).merge(other.create_with_value)
+ CLAUSE_METHOD_NAMES = CLAUSE_METHODS.map do |name|
+ ["#{name}_clause", "#{name}_clause="]
end
- end
-
- CLAUSE_METHOD_NAMES = CLAUSE_METHODS.map do |name|
- ["#{name}_clause", "#{name}_clause="]
- end
- def merge_clauses
- CLAUSE_METHOD_NAMES.each do |(reader, writer)|
- clause = relation.send(reader)
- other_clause = other.send(reader)
- relation.send(writer, clause.merge(other_clause))
+ def merge_clauses
+ CLAUSE_METHOD_NAMES.each do |(reader, writer)|
+ clause = relation.send(reader)
+ other_clause = other.send(reader)
+ relation.send(writer, clause.merge(other_clause))
+ end
end
- end
end
end
end
diff --git a/activerecord/lib/active_record/relation/predicate_builder.rb b/activerecord/lib/active_record/relation/predicate_builder.rb
index 8dbff84950..df663a84ed 100644
--- a/activerecord/lib/active_record/relation/predicate_builder.rb
+++ b/activerecord/lib/active_record/relation/predicate_builder.rb
@@ -78,91 +78,91 @@ module ActiveRecord
protected
- attr_reader :table
+ attr_reader :table
- def expand_from_hash(attributes)
- return ["1=0"] if attributes.empty?
+ def expand_from_hash(attributes)
+ return ["1=0"] if attributes.empty?
- attributes.flat_map do |key, value|
- if value.is_a?(Hash)
- associated_predicate_builder(key).expand_from_hash(value)
- else
- expand(key, value)
+ attributes.flat_map do |key, value|
+ if value.is_a?(Hash)
+ associated_predicate_builder(key).expand_from_hash(value)
+ else
+ expand(key, value)
+ end
end
end
- end
- def create_binds_for_hash(attributes)
- result = attributes.dup
- binds = []
-
- attributes.each do |column_name, value|
- case value
- when Hash
- attrs, bvs = associated_predicate_builder(column_name).create_binds_for_hash(value)
- result[column_name] = attrs
- binds += bvs
- when Relation
- binds += value.bound_attributes
- when Range
- first = value.begin
- last = value.end
- unless first.respond_to?(:infinite?) && first.infinite?
- binds << build_bind_param(column_name, first)
- first = Arel::Nodes::BindParam.new
- end
- unless last.respond_to?(:infinite?) && last.infinite?
- binds << build_bind_param(column_name, last)
- last = Arel::Nodes::BindParam.new
- end
-
- result[column_name] = RangeHandler::RangeWithBinds.new(first, last, value.exclude_end?)
- else
- if can_be_bound?(column_name, value)
- result[column_name] = Arel::Nodes::BindParam.new
- binds << build_bind_param(column_name, value)
+ def create_binds_for_hash(attributes)
+ result = attributes.dup
+ binds = []
+
+ attributes.each do |column_name, value|
+ case value
+ when Hash
+ attrs, bvs = associated_predicate_builder(column_name).create_binds_for_hash(value)
+ result[column_name] = attrs
+ binds += bvs
+ when Relation
+ binds += value.bound_attributes
+ when Range
+ first = value.begin
+ last = value.end
+ unless first.respond_to?(:infinite?) && first.infinite?
+ binds << build_bind_param(column_name, first)
+ first = Arel::Nodes::BindParam.new
+ end
+ unless last.respond_to?(:infinite?) && last.infinite?
+ binds << build_bind_param(column_name, last)
+ last = Arel::Nodes::BindParam.new
+ end
+
+ result[column_name] = RangeHandler::RangeWithBinds.new(first, last, value.exclude_end?)
+ else
+ if can_be_bound?(column_name, value)
+ result[column_name] = Arel::Nodes::BindParam.new
+ binds << build_bind_param(column_name, value)
+ end
end
end
- end
- [result, binds]
- end
+ [result, binds]
+ end
private
- def associated_predicate_builder(association_name)
- self.class.new(table.associated_table(association_name))
- end
-
- def convert_dot_notation_to_hash(attributes)
- dot_notation = attributes.select do |k, v|
- k.include?(".".freeze) && !v.is_a?(Hash)
+ def associated_predicate_builder(association_name)
+ self.class.new(table.associated_table(association_name))
end
- dot_notation.each_key do |key|
- table_name, column_name = key.split(".".freeze)
- value = attributes.delete(key)
- attributes[table_name] ||= {}
+ def convert_dot_notation_to_hash(attributes)
+ dot_notation = attributes.select do |k, v|
+ k.include?(".".freeze) && !v.is_a?(Hash)
+ end
- attributes[table_name] = attributes[table_name].merge(column_name => value)
- end
+ dot_notation.each_key do |key|
+ table_name, column_name = key.split(".".freeze)
+ value = attributes.delete(key)
+ attributes[table_name] ||= {}
- attributes
- end
+ attributes[table_name] = attributes[table_name].merge(column_name => value)
+ end
- def handler_for(object)
- @handlers.detect { |klass, _| klass === object }.last
- end
+ attributes
+ end
- def can_be_bound?(column_name, value)
- !value.nil? &&
- handler_for(value).is_a?(BasicObjectHandler) &&
- !table.associated_with?(column_name)
- end
+ def handler_for(object)
+ @handlers.detect { |klass, _| klass === object }.last
+ end
- def build_bind_param(column_name, value)
- Relation::QueryAttribute.new(column_name.to_s, value, table.type(column_name))
- end
+ def can_be_bound?(column_name, value)
+ !value.nil? &&
+ handler_for(value).is_a?(BasicObjectHandler) &&
+ !table.associated_with?(column_name)
+ end
+
+ def build_bind_param(column_name, value)
+ Relation::QueryAttribute.new(column_name.to_s, value, table.type(column_name))
+ end
end
end
diff --git a/activerecord/lib/active_record/relation/predicate_builder/array_handler.rb b/activerecord/lib/active_record/relation/predicate_builder/array_handler.rb
index 95dbd6a77f..6400caba06 100644
--- a/activerecord/lib/active_record/relation/predicate_builder/array_handler.rb
+++ b/activerecord/lib/active_record/relation/predicate_builder/array_handler.rb
@@ -31,13 +31,13 @@ module ActiveRecord
protected
- attr_reader :predicate_builder
+ attr_reader :predicate_builder
- module NullPredicate # :nodoc:
- def self.or(other)
- other
+ module NullPredicate # :nodoc:
+ def self.or(other)
+ other
+ end
end
- end
end
end
end
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 413cb9fd84..7e20cb2c63 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
@@ -30,7 +30,7 @@ module ActiveRecord
protected
- attr_reader :predicate_builder
+ attr_reader :predicate_builder
end
class AssociationQueryValue # :nodoc:
@@ -60,30 +60,30 @@ module ActiveRecord
private
- def primary_key
- associated_table.association_primary_key(base_class)
- end
+ def primary_key
+ associated_table.association_primary_key(base_class)
+ end
- def polymorphic_base_class_from_value
- case value
- when Relation
- value.klass.base_class
- when Array
- val = value.compact.first
- val.class.base_class if val.is_a?(Base)
- when Base
- value.class.base_class
+ def polymorphic_base_class_from_value
+ case value
+ when Relation
+ value.klass.base_class
+ when Array
+ val = value.compact.first
+ val.class.base_class if val.is_a?(Base)
+ when Base
+ value.class.base_class
+ end
end
- end
- def convert_to_id(value)
- case value
- when Base
- value._read_attribute(primary_key)
- else
- value
+ def convert_to_id(value)
+ case value
+ when Base
+ value._read_attribute(primary_key)
+ else
+ value
+ end
end
- end
end
end
end
diff --git a/activerecord/lib/active_record/relation/predicate_builder/base_handler.rb b/activerecord/lib/active_record/relation/predicate_builder/base_handler.rb
index 6fa5b16f73..65c5159704 100644
--- a/activerecord/lib/active_record/relation/predicate_builder/base_handler.rb
+++ b/activerecord/lib/active_record/relation/predicate_builder/base_handler.rb
@@ -11,7 +11,7 @@ module ActiveRecord
protected
- attr_reader :predicate_builder
+ attr_reader :predicate_builder
end
end
end
diff --git a/activerecord/lib/active_record/relation/predicate_builder/class_handler.rb b/activerecord/lib/active_record/relation/predicate_builder/class_handler.rb
index ed313fc9d4..73ad864765 100644
--- a/activerecord/lib/active_record/relation/predicate_builder/class_handler.rb
+++ b/activerecord/lib/active_record/relation/predicate_builder/class_handler.rb
@@ -12,16 +12,16 @@ module ActiveRecord
protected
- attr_reader :predicate_builder
+ attr_reader :predicate_builder
private
- def print_deprecation_warning
- ActiveSupport::Deprecation.warn(<<-MSG.squish)
+ def print_deprecation_warning
+ ActiveSupport::Deprecation.warn(<<-MSG.squish)
Passing a class as a value in an Active Record query is deprecated and
will be removed. Pass a string instead.
MSG
- end
+ end
end
end
end
diff --git a/activerecord/lib/active_record/relation/predicate_builder/polymorphic_array_handler.rb b/activerecord/lib/active_record/relation/predicate_builder/polymorphic_array_handler.rb
index b6c6240343..0c7f92b3d0 100644
--- a/activerecord/lib/active_record/relation/predicate_builder/polymorphic_array_handler.rb
+++ b/activerecord/lib/active_record/relation/predicate_builder/polymorphic_array_handler.rb
@@ -23,7 +23,7 @@ module ActiveRecord
protected
- attr_reader :predicate_builder
+ attr_reader :predicate_builder
end
class PolymorphicArrayValue # :nodoc:
@@ -41,17 +41,17 @@ module ActiveRecord
private
- def primary_key(value)
- associated_table.association_primary_key(base_class(value))
- end
+ def primary_key(value)
+ associated_table.association_primary_key(base_class(value))
+ end
- def base_class(value)
- value.class.base_class
- end
+ def base_class(value)
+ value.class.base_class
+ end
- def convert_to_id(value)
- value._read_attribute(primary_key(value))
- end
+ def convert_to_id(value)
+ value._read_attribute(primary_key(value))
+ end
end
end
end
diff --git a/activerecord/lib/active_record/relation/query_methods.rb b/activerecord/lib/active_record/relation/query_methods.rb
index 3b86f1c605..619b947f57 100644
--- a/activerecord/lib/active_record/relation/query_methods.rb
+++ b/activerecord/lib/active_record/relation/query_methods.rb
@@ -952,241 +952,241 @@ module ActiveRecord
private
- def assert_mutability!
- raise ImmutableRelation if @loaded
- raise ImmutableRelation if defined?(@arel) && @arel
- end
+ def assert_mutability!
+ raise ImmutableRelation if @loaded
+ raise ImmutableRelation if defined?(@arel) && @arel
+ end
- def build_arel
- arel = Arel::SelectManager.new(table)
+ def build_arel
+ arel = Arel::SelectManager.new(table)
- build_joins(arel, joins_values.flatten) unless joins_values.empty?
- build_left_outer_joins(arel, left_outer_joins_values.flatten) unless left_outer_joins_values.empty?
+ build_joins(arel, joins_values.flatten) unless joins_values.empty?
+ build_left_outer_joins(arel, left_outer_joins_values.flatten) unless left_outer_joins_values.empty?
- arel.where(where_clause.ast) unless where_clause.empty?
- arel.having(having_clause.ast) unless having_clause.empty?
- if limit_value
- if string_containing_comma?(limit_value)
- arel.take(connection.sanitize_limit(limit_value))
- else
- arel.take(Arel::Nodes::BindParam.new)
+ arel.where(where_clause.ast) unless where_clause.empty?
+ arel.having(having_clause.ast) unless having_clause.empty?
+ if limit_value
+ if string_containing_comma?(limit_value)
+ arel.take(connection.sanitize_limit(limit_value))
+ else
+ arel.take(Arel::Nodes::BindParam.new)
+ end
end
- end
- arel.skip(Arel::Nodes::BindParam.new) if offset_value
- arel.group(*arel_columns(group_values.uniq.reject(&:blank?))) unless group_values.empty?
+ arel.skip(Arel::Nodes::BindParam.new) if offset_value
+ arel.group(*arel_columns(group_values.uniq.reject(&:blank?))) unless group_values.empty?
- build_order(arel)
+ build_order(arel)
- build_select(arel)
+ build_select(arel)
- arel.distinct(distinct_value)
- arel.from(build_from) unless from_clause.empty?
- arel.lock(lock_value) if lock_value
+ arel.distinct(distinct_value)
+ arel.from(build_from) unless from_clause.empty?
+ arel.lock(lock_value) if lock_value
- arel
- end
-
- def symbol_unscoping(scope)
- if !VALID_UNSCOPING_VALUES.include?(scope)
- raise ArgumentError, "Called unscope() with invalid unscoping argument ':#{scope}'. Valid arguments are :#{VALID_UNSCOPING_VALUES.to_a.join(", :")}."
+ arel
end
- clause_method = Relation::CLAUSE_METHODS.include?(scope)
- multi_val_method = Relation::MULTI_VALUE_METHODS.include?(scope)
- if clause_method
- unscope_code = "#{scope}_clause="
- else
- unscope_code = "#{scope}_value#{'s' if multi_val_method}="
- end
+ def symbol_unscoping(scope)
+ if !VALID_UNSCOPING_VALUES.include?(scope)
+ raise ArgumentError, "Called unscope() with invalid unscoping argument ':#{scope}'. Valid arguments are :#{VALID_UNSCOPING_VALUES.to_a.join(", :")}."
+ end
- case scope
- when :order
- result = []
- else
- result = [] if multi_val_method
- end
+ clause_method = Relation::CLAUSE_METHODS.include?(scope)
+ multi_val_method = Relation::MULTI_VALUE_METHODS.include?(scope)
+ if clause_method
+ unscope_code = "#{scope}_clause="
+ else
+ unscope_code = "#{scope}_value#{'s' if multi_val_method}="
+ end
- self.send(unscope_code, result)
- end
+ case scope
+ when :order
+ result = []
+ else
+ result = [] if multi_val_method
+ end
- def build_from
- opts = from_clause.value
- name = from_clause.name
- case opts
- when Relation
- name ||= "subquery"
- opts.arel.as(name.to_s)
- else
- opts
+ self.send(unscope_code, result)
end
- end
- def build_left_outer_joins(manager, outer_joins)
- buckets = outer_joins.group_by do |join|
- case join
- when Hash, Symbol, Array
- :association_join
+ def build_from
+ opts = from_clause.value
+ name = from_clause.name
+ case opts
+ when Relation
+ name ||= "subquery"
+ opts.arel.as(name.to_s)
else
- raise ArgumentError, "only Hash, Symbol and Array are allowed"
+ opts
end
end
- build_join_query(manager, buckets, Arel::Nodes::OuterJoin)
- end
-
- def build_joins(manager, joins)
- buckets = joins.group_by do |join|
- case join
- when String
- :string_join
- when Hash, Symbol, Array
- :association_join
- when ActiveRecord::Associations::JoinDependency
- :stashed_join
- when Arel::Nodes::Join
- :join_node
- else
- raise "unknown class: %s" % join.class.name
+ def build_left_outer_joins(manager, outer_joins)
+ buckets = outer_joins.group_by do |join|
+ case join
+ when Hash, Symbol, Array
+ :association_join
+ else
+ raise ArgumentError, "only Hash, Symbol and Array are allowed"
+ end
end
+
+ build_join_query(manager, buckets, Arel::Nodes::OuterJoin)
end
- build_join_query(manager, buckets, Arel::Nodes::InnerJoin)
- end
+ def build_joins(manager, joins)
+ buckets = joins.group_by do |join|
+ case join
+ when String
+ :string_join
+ when Hash, Symbol, Array
+ :association_join
+ when ActiveRecord::Associations::JoinDependency
+ :stashed_join
+ when Arel::Nodes::Join
+ :join_node
+ else
+ raise "unknown class: %s" % join.class.name
+ end
+ end
- def build_join_query(manager, buckets, join_type)
- buckets.default = []
+ build_join_query(manager, buckets, Arel::Nodes::InnerJoin)
+ end
- association_joins = buckets[:association_join]
- stashed_association_joins = buckets[:stashed_join]
- join_nodes = buckets[:join_node].uniq
- string_joins = buckets[:string_join].map(&:strip).uniq
+ def build_join_query(manager, buckets, join_type)
+ buckets.default = []
- join_list = join_nodes + convert_join_strings_to_ast(manager, string_joins)
+ association_joins = buckets[:association_join]
+ stashed_association_joins = buckets[:stashed_join]
+ join_nodes = buckets[:join_node].uniq
+ string_joins = buckets[:string_join].map(&:strip).uniq
- join_dependency = ActiveRecord::Associations::JoinDependency.new(
- @klass,
- association_joins,
- join_list
- )
+ join_list = join_nodes + convert_join_strings_to_ast(manager, string_joins)
- join_infos = join_dependency.join_constraints stashed_association_joins, join_type
+ join_dependency = ActiveRecord::Associations::JoinDependency.new(
+ @klass,
+ association_joins,
+ join_list
+ )
- join_infos.each do |info|
- info.joins.each { |join| manager.from(join) }
- manager.bind_values.concat info.binds
- end
+ join_infos = join_dependency.join_constraints stashed_association_joins, join_type
- manager.join_sources.concat(join_list)
+ join_infos.each do |info|
+ info.joins.each { |join| manager.from(join) }
+ manager.bind_values.concat info.binds
+ end
- manager
- end
+ manager.join_sources.concat(join_list)
- def convert_join_strings_to_ast(table, joins)
- joins
- .flatten
- .reject(&:blank?)
- .map { |join| table.create_string_join(Arel.sql(join)) }
- end
+ manager
+ end
- def build_select(arel)
- if select_values.any?
- arel.project(*arel_columns(select_values.uniq))
- else
- arel.project(@klass.arel_table[Arel.star])
+ def convert_join_strings_to_ast(table, joins)
+ joins
+ .flatten
+ .reject(&:blank?)
+ .map { |join| table.create_string_join(Arel.sql(join)) }
end
- end
- def arel_columns(columns)
- columns.map do |field|
- if (Symbol === field || String === field) && (klass.has_attribute?(field) || klass.attribute_alias?(field)) && !from_clause.value
- arel_attribute(field)
- elsif Symbol === field
- connection.quote_table_name(field.to_s)
+ def build_select(arel)
+ if select_values.any?
+ arel.project(*arel_columns(select_values.uniq))
else
- field
+ arel.project(@klass.arel_table[Arel.star])
end
end
- end
- def reverse_sql_order(order_query)
- if order_query.empty?
- return [arel_attribute(primary_key).desc] if primary_key
- raise IrreversibleOrderError,
- "Relation has no current order and table has no primary key to be used as default order"
+ def arel_columns(columns)
+ columns.map do |field|
+ if (Symbol === field || String === field) && (klass.has_attribute?(field) || klass.attribute_alias?(field)) && !from_clause.value
+ arel_attribute(field)
+ elsif Symbol === field
+ connection.quote_table_name(field.to_s)
+ else
+ field
+ end
+ end
end
- order_query.flat_map do |o|
- case o
- when Arel::Attribute
- o.desc
- when Arel::Nodes::Ordering
- o.reverse
- when String
- if does_not_support_reverse?(o)
- raise IrreversibleOrderError, "Order #{o.inspect} can not be reversed automatically"
- end
- o.split(",").map! do |s|
- s.strip!
- s.gsub!(/\sasc\Z/i, " DESC") || s.gsub!(/\sdesc\Z/i, " ASC") || s.concat(" DESC")
+ def reverse_sql_order(order_query)
+ if order_query.empty?
+ return [arel_attribute(primary_key).desc] if primary_key
+ raise IrreversibleOrderError,
+ "Relation has no current order and table has no primary key to be used as default order"
+ end
+
+ order_query.flat_map do |o|
+ case o
+ when Arel::Attribute
+ o.desc
+ when Arel::Nodes::Ordering
+ o.reverse
+ when String
+ if does_not_support_reverse?(o)
+ raise IrreversibleOrderError, "Order #{o.inspect} can not be reversed automatically"
+ end
+ o.split(",").map! do |s|
+ s.strip!
+ s.gsub!(/\sasc\Z/i, " DESC") || s.gsub!(/\sdesc\Z/i, " ASC") || s.concat(" DESC")
+ end
+ else
+ o
end
- else
- o
end
end
- end
- def does_not_support_reverse?(order)
- # Uses SQL function with multiple arguments.
- /\([^()]*,[^()]*\)/.match?(order) ||
- # Uses "nulls first" like construction.
- /nulls (first|last)\Z/i.match?(order)
- end
+ def does_not_support_reverse?(order)
+ # Uses SQL function with multiple arguments.
+ /\([^()]*,[^()]*\)/.match?(order) ||
+ # Uses "nulls first" like construction.
+ /nulls (first|last)\Z/i.match?(order)
+ end
- def build_order(arel)
- orders = order_values.uniq
- orders.reject!(&:blank?)
+ def build_order(arel)
+ orders = order_values.uniq
+ orders.reject!(&:blank?)
- arel.order(*orders) unless orders.empty?
- end
+ arel.order(*orders) unless orders.empty?
+ end
- VALID_DIRECTIONS = [:asc, :desc, :ASC, :DESC,
- "asc", "desc", "ASC", "DESC"] # :nodoc:
+ VALID_DIRECTIONS = [:asc, :desc, :ASC, :DESC,
+ "asc", "desc", "ASC", "DESC"] # :nodoc:
- def validate_order_args(args)
- args.each do |arg|
- next unless arg.is_a?(Hash)
- arg.each do |_key, value|
- raise ArgumentError, "Direction \"#{value}\" is invalid. Valid " \
- "directions are: #{VALID_DIRECTIONS.inspect}" unless VALID_DIRECTIONS.include?(value)
+ def validate_order_args(args)
+ args.each do |arg|
+ next unless arg.is_a?(Hash)
+ arg.each do |_key, value|
+ raise ArgumentError, "Direction \"#{value}\" is invalid. Valid " \
+ "directions are: #{VALID_DIRECTIONS.inspect}" unless VALID_DIRECTIONS.include?(value)
+ end
end
end
- end
-
- def preprocess_order_args(order_args)
- order_args.map! do |arg|
- klass.send(:sanitize_sql_for_order, arg)
- end
- order_args.flatten!
- validate_order_args(order_args)
- references = order_args.grep(String)
- references.map! { |arg| arg =~ /^([a-zA-Z]\w*)\.(\w+)/ && $1 }.compact!
- references!(references) if references.any?
-
- # if a symbol is given we prepend the quoted table name
- order_args.map! do |arg|
- case arg
- when Symbol
- arel_attribute(arg).asc
- when Hash
- arg.map { |field, dir|
- arel_attribute(field).send(dir.downcase)
- }
- else
- arg
+ def preprocess_order_args(order_args)
+ order_args.map! do |arg|
+ klass.send(:sanitize_sql_for_order, arg)
end
- end.flatten!
- end
+ order_args.flatten!
+ validate_order_args(order_args)
+
+ references = order_args.grep(String)
+ references.map! { |arg| arg =~ /^([a-zA-Z]\w*)\.(\w+)/ && $1 }.compact!
+ references!(references) if references.any?
+
+ # if a symbol is given we prepend the quoted table name
+ order_args.map! do |arg|
+ case arg
+ when Symbol
+ arel_attribute(arg).asc
+ when Hash
+ arg.map { |field, dir|
+ arel_attribute(field).send(dir.downcase)
+ }
+ else
+ arg
+ end
+ end.flatten!
+ end
# Checks to make sure that the arguments are not blank. Note that if some
# blank-like object were initially passed into the query method, then this
@@ -1204,34 +1204,34 @@ module ActiveRecord
# check_if_method_has_arguments!("references", args)
# ...
# end
- def check_if_method_has_arguments!(method_name, args)
- if args.blank?
- raise ArgumentError, "The method .#{method_name}() must contain arguments."
+ def check_if_method_has_arguments!(method_name, args)
+ if args.blank?
+ raise ArgumentError, "The method .#{method_name}() must contain arguments."
+ end
end
- end
- def structurally_incompatible_values_for_or(other)
- Relation::SINGLE_VALUE_METHODS.reject { |m| send("#{m}_value") == other.send("#{m}_value") } +
- (Relation::MULTI_VALUE_METHODS - [:extending]).reject { |m| send("#{m}_values") == other.send("#{m}_values") } +
- (Relation::CLAUSE_METHODS - [:having, :where]).reject { |m| send("#{m}_clause") == other.send("#{m}_clause") }
- end
+ def structurally_incompatible_values_for_or(other)
+ Relation::SINGLE_VALUE_METHODS.reject { |m| send("#{m}_value") == other.send("#{m}_value") } +
+ (Relation::MULTI_VALUE_METHODS - [:extending]).reject { |m| send("#{m}_values") == other.send("#{m}_values") } +
+ (Relation::CLAUSE_METHODS - [:having, :where]).reject { |m| send("#{m}_clause") == other.send("#{m}_clause") }
+ end
- def new_where_clause
- Relation::WhereClause.empty
- end
- alias new_having_clause new_where_clause
+ def new_where_clause
+ Relation::WhereClause.empty
+ end
+ alias new_having_clause new_where_clause
- def where_clause_factory
- @where_clause_factory ||= Relation::WhereClauseFactory.new(klass, predicate_builder)
- end
- alias having_clause_factory where_clause_factory
+ def where_clause_factory
+ @where_clause_factory ||= Relation::WhereClauseFactory.new(klass, predicate_builder)
+ end
+ alias having_clause_factory where_clause_factory
- def new_from_clause
- Relation::FromClause.empty
- end
+ def new_from_clause
+ Relation::FromClause.empty
+ end
- def string_containing_comma?(value)
- ::String === value && value.include?(",")
- end
+ def string_containing_comma?(value)
+ ::String === value && value.include?(",")
+ end
end
end
diff --git a/activerecord/lib/active_record/relation/where_clause.rb b/activerecord/lib/active_record/relation/where_clause.rb
index e1376ce00a..402f8acfd1 100644
--- a/activerecord/lib/active_record/relation/where_clause.rb
+++ b/activerecord/lib/active_record/relation/where_clause.rb
@@ -86,89 +86,89 @@ module ActiveRecord
protected
- attr_reader :predicates
+ attr_reader :predicates
- def referenced_columns
- @referenced_columns ||= begin
- equality_nodes = predicates.select { |n| equality_node?(n) }
- Set.new(equality_nodes, &:left)
+ def referenced_columns
+ @referenced_columns ||= begin
+ equality_nodes = predicates.select { |n| equality_node?(n) }
+ Set.new(equality_nodes, &:left)
+ end
end
- end
private
- def predicates_unreferenced_by(other)
- predicates.reject do |n|
- equality_node?(n) && other.referenced_columns.include?(n.left)
+ def predicates_unreferenced_by(other)
+ predicates.reject do |n|
+ equality_node?(n) && other.referenced_columns.include?(n.left)
+ end
end
- end
- def equality_node?(node)
- node.respond_to?(:operator) && node.operator == :==
- end
-
- def non_conflicting_binds(other)
- conflicts = referenced_columns & other.referenced_columns
- conflicts.map! { |node| node.name.to_s }
- binds.reject { |attr| conflicts.include?(attr.name) }
- end
+ def equality_node?(node)
+ node.respond_to?(:operator) && node.operator == :==
+ end
- def inverted_predicates
- predicates.map { |node| invert_predicate(node) }
- end
+ def non_conflicting_binds(other)
+ conflicts = referenced_columns & other.referenced_columns
+ conflicts.map! { |node| node.name.to_s }
+ binds.reject { |attr| conflicts.include?(attr.name) }
+ end
- def invert_predicate(node)
- case node
- when NilClass
- raise ArgumentError, "Invalid argument for .where.not(), got nil."
- when Arel::Nodes::In
- Arel::Nodes::NotIn.new(node.left, node.right)
- when Arel::Nodes::Equality
- Arel::Nodes::NotEqual.new(node.left, node.right)
- when String
- Arel::Nodes::Not.new(Arel::Nodes::SqlLiteral.new(node))
- else
- Arel::Nodes::Not.new(node)
+ def inverted_predicates
+ predicates.map { |node| invert_predicate(node) }
end
- end
- def predicates_except(columns)
- predicates.reject do |node|
+ def invert_predicate(node)
case node
- when Arel::Nodes::Between, Arel::Nodes::In, Arel::Nodes::NotIn, Arel::Nodes::Equality, Arel::Nodes::NotEqual, Arel::Nodes::LessThan, Arel::Nodes::LessThanOrEqual, Arel::Nodes::GreaterThan, Arel::Nodes::GreaterThanOrEqual
- subrelation = (node.left.kind_of?(Arel::Attributes::Attribute) ? node.left : node.right)
- columns.include?(subrelation.name.to_s)
+ when NilClass
+ raise ArgumentError, "Invalid argument for .where.not(), got nil."
+ when Arel::Nodes::In
+ Arel::Nodes::NotIn.new(node.left, node.right)
+ when Arel::Nodes::Equality
+ Arel::Nodes::NotEqual.new(node.left, node.right)
+ when String
+ Arel::Nodes::Not.new(Arel::Nodes::SqlLiteral.new(node))
+ else
+ Arel::Nodes::Not.new(node)
end
end
- end
- def binds_except(columns)
- binds.reject do |attr|
- columns.include?(attr.name)
+ def predicates_except(columns)
+ predicates.reject do |node|
+ case node
+ when Arel::Nodes::Between, Arel::Nodes::In, Arel::Nodes::NotIn, Arel::Nodes::Equality, Arel::Nodes::NotEqual, Arel::Nodes::LessThan, Arel::Nodes::LessThanOrEqual, Arel::Nodes::GreaterThan, Arel::Nodes::GreaterThanOrEqual
+ subrelation = (node.left.kind_of?(Arel::Attributes::Attribute) ? node.left : node.right)
+ columns.include?(subrelation.name.to_s)
+ end
+ end
end
- end
- def predicates_with_wrapped_sql_literals
- non_empty_predicates.map do |node|
- if Arel::Nodes::Equality === node
- node
- else
- wrap_sql_literal(node)
+ def binds_except(columns)
+ binds.reject do |attr|
+ columns.include?(attr.name)
end
end
- end
- ARRAY_WITH_EMPTY_STRING = [""]
- def non_empty_predicates
- predicates - ARRAY_WITH_EMPTY_STRING
- end
+ def predicates_with_wrapped_sql_literals
+ non_empty_predicates.map do |node|
+ if Arel::Nodes::Equality === node
+ node
+ else
+ wrap_sql_literal(node)
+ end
+ end
+ end
- def wrap_sql_literal(node)
- if ::String === node
- node = Arel.sql(node)
+ ARRAY_WITH_EMPTY_STRING = [""]
+ def non_empty_predicates
+ predicates - ARRAY_WITH_EMPTY_STRING
+ end
+
+ def wrap_sql_literal(node)
+ if ::String === node
+ node = Arel.sql(node)
+ end
+ Arel::Nodes::Grouping.new(node)
end
- Arel::Nodes::Grouping.new(node)
- end
end
end
end
diff --git a/activerecord/lib/active_record/relation/where_clause_factory.rb b/activerecord/lib/active_record/relation/where_clause_factory.rb
index dbf172a577..038ebbfe21 100644
--- a/activerecord/lib/active_record/relation/where_clause_factory.rb
+++ b/activerecord/lib/active_record/relation/where_clause_factory.rb
@@ -32,7 +32,7 @@ module ActiveRecord
protected
- attr_reader :klass, :predicate_builder
+ attr_reader :klass, :predicate_builder
end
end
end
diff --git a/activerecord/lib/active_record/result.rb b/activerecord/lib/active_record/result.rb
index b9fd0f5326..f5383f4c14 100644
--- a/activerecord/lib/active_record/result.rb
+++ b/activerecord/lib/active_record/result.rb
@@ -103,36 +103,36 @@ module ActiveRecord
private
- def column_type(name, type_overrides = {})
- type_overrides.fetch(name) do
- column_types.fetch(name, IDENTITY_TYPE)
+ def column_type(name, type_overrides = {})
+ type_overrides.fetch(name) do
+ column_types.fetch(name, IDENTITY_TYPE)
+ end
end
- end
- def hash_rows
- @hash_rows ||=
- begin
- # We freeze the strings to prevent them getting duped when
- # used as keys in ActiveRecord::Base's @attributes hash
- columns = @columns.map { |c| c.dup.freeze }
- @rows.map { |row|
- # In the past we used Hash[columns.zip(row)]
- # though elegant, the verbose way is much more efficient
- # both time and memory wise cause it avoids a big array allocation
- # this method is called a lot and needs to be micro optimised
- hash = {}
-
- index = 0
- length = columns.length
-
- while index < length
- hash[columns[index]] = row[index]
- index += 1
- end
-
- hash
- }
- end
- end
+ def hash_rows
+ @hash_rows ||=
+ begin
+ # We freeze the strings to prevent them getting duped when
+ # used as keys in ActiveRecord::Base's @attributes hash
+ columns = @columns.map { |c| c.dup.freeze }
+ @rows.map { |row|
+ # In the past we used Hash[columns.zip(row)]
+ # though elegant, the verbose way is much more efficient
+ # both time and memory wise cause it avoids a big array allocation
+ # this method is called a lot and needs to be micro optimised
+ hash = {}
+
+ index = 0
+ length = columns.length
+
+ while index < length
+ hash[columns[index]] = row[index]
+ index += 1
+ end
+
+ hash
+ }
+ end
+ end
end
end
diff --git a/activerecord/lib/active_record/sanitization.rb b/activerecord/lib/active_record/sanitization.rb
index 26679bb1c3..6617008344 100644
--- a/activerecord/lib/active_record/sanitization.rb
+++ b/activerecord/lib/active_record/sanitization.rb
@@ -28,16 +28,16 @@ module ActiveRecord
#
# sanitize_sql_for_conditions("name='foo''bar' and group_id='4'")
# # => "name='foo''bar' and group_id='4'"
- def sanitize_sql_for_conditions(condition)
- return nil if condition.blank?
+ def sanitize_sql_for_conditions(condition)
+ return nil if condition.blank?
- case condition
- when Array; sanitize_sql_array(condition)
- else condition
+ case condition
+ when Array; sanitize_sql_array(condition)
+ else condition
+ end
end
- end
- alias_method :sanitize_sql, :sanitize_sql_for_conditions
- alias_method :sanitize_conditions, :sanitize_sql
+ alias_method :sanitize_sql, :sanitize_sql_for_conditions
+ alias_method :sanitize_conditions, :sanitize_sql
# Accepts an array, hash, or string of SQL conditions and sanitizes
# them into a valid SQL fragment for a SET clause.
@@ -53,13 +53,13 @@ module ActiveRecord
#
# sanitize_sql_for_assignment("name=NULL and group_id='4'")
# # => "name=NULL and group_id='4'"
- def sanitize_sql_for_assignment(assignments, default_table_name = self.table_name)
- case assignments
- when Array; sanitize_sql_array(assignments)
- when Hash; sanitize_sql_hash_for_assignment(assignments, default_table_name)
- else assignments
+ def sanitize_sql_for_assignment(assignments, default_table_name = self.table_name)
+ case assignments
+ when Array; sanitize_sql_array(assignments)
+ when Hash; sanitize_sql_hash_for_assignment(assignments, default_table_name)
+ else assignments
+ end
end
- end
# Accepts an array, or string of SQL conditions and sanitizes
# them into a valid SQL fragment for an ORDER clause.
@@ -69,13 +69,13 @@ module ActiveRecord
#
# sanitize_sql_for_order("id ASC")
# # => "id ASC"
- def sanitize_sql_for_order(condition)
- if condition.is_a?(Array) && condition.first.to_s.include?("?")
- sanitize_sql_array(condition)
- else
- condition
+ def sanitize_sql_for_order(condition)
+ if condition.is_a?(Array) && condition.first.to_s.include?("?")
+ sanitize_sql_array(condition)
+ else
+ condition
+ end
end
- end
# Accepts a hash of SQL conditions and replaces those attributes
# that correspond to a {#composed_of}[rdoc-ref:Aggregations::ClassMethods#composed_of]
@@ -92,36 +92,36 @@ module ActiveRecord
#
# { address: Address.new("813 abc st.", "chicago") }
# # => { address_street: "813 abc st.", address_city: "chicago" }
- def expand_hash_conditions_for_aggregates(attrs)
- expanded_attrs = {}
- attrs.each do |attr, value|
- if aggregation = reflect_on_aggregation(attr.to_sym)
- mapping = aggregation.mapping
- mapping.each do |field_attr, aggregate_attr|
- if mapping.size == 1 && !value.respond_to?(aggregate_attr)
- expanded_attrs[field_attr] = value
- else
- expanded_attrs[field_attr] = value.send(aggregate_attr)
+ def expand_hash_conditions_for_aggregates(attrs)
+ expanded_attrs = {}
+ attrs.each do |attr, value|
+ if aggregation = reflect_on_aggregation(attr.to_sym)
+ mapping = aggregation.mapping
+ mapping.each do |field_attr, aggregate_attr|
+ if mapping.size == 1 && !value.respond_to?(aggregate_attr)
+ expanded_attrs[field_attr] = value
+ else
+ expanded_attrs[field_attr] = value.send(aggregate_attr)
+ end
end
+ else
+ expanded_attrs[attr] = value
end
- else
- expanded_attrs[attr] = value
end
+ expanded_attrs
end
- expanded_attrs
- end
# Sanitizes a hash of attribute/value pairs into SQL conditions for a SET clause.
#
# sanitize_sql_hash_for_assignment({ status: nil, group_id: 1 }, "posts")
# # => "`posts`.`status` = NULL, `posts`.`group_id` = 1"
- def sanitize_sql_hash_for_assignment(attrs, table)
- c = connection
- attrs.map do |attr, value|
- value = type_for_attribute(attr.to_s).serialize(value)
- "#{c.quote_table_name_for_assignment(table, attr)} = #{c.quote(value)}"
- end.join(", ")
- end
+ def sanitize_sql_hash_for_assignment(attrs, table)
+ c = connection
+ attrs.map do |attr, value|
+ value = type_for_attribute(attr.to_s).serialize(value)
+ "#{c.quote_table_name_for_assignment(table, attr)} = #{c.quote(value)}"
+ end.join(", ")
+ end
# Sanitizes a +string+ so that it is safe to use within an SQL
# LIKE statement. This method uses +escape_character+ to escape all occurrences of "\", "_" and "%".
@@ -137,10 +137,10 @@ module ActiveRecord
#
# sanitize_sql_like("snake_cased_string", "!")
# # => "snake!_cased!_string"
- def sanitize_sql_like(string, escape_character = "\\")
- pattern = Regexp.union(escape_character, "%", "_")
- string.gsub(pattern) { |x| [escape_character, x].join }
- end
+ def sanitize_sql_like(string, escape_character = "\\")
+ pattern = Regexp.union(escape_character, "%", "_")
+ string.gsub(pattern) { |x| [escape_character, x].join }
+ end
# Accepts an array of conditions. The array has each value
# sanitized and interpolated into the SQL statement.
@@ -153,65 +153,65 @@ module ActiveRecord
#
# sanitize_sql_array(["name='%s' and group_id='%s'", "foo'bar", 4])
# # => "name='foo''bar' and group_id='4'"
- def sanitize_sql_array(ary)
- statement, *values = ary
- if values.first.is_a?(Hash) && /:\w+/.match?(statement)
- replace_named_bind_variables(statement, values.first)
- elsif statement.include?("?")
- replace_bind_variables(statement, values)
- elsif statement.blank?
- statement
- else
- statement % values.collect { |value| connection.quote_string(value.to_s) }
+ def sanitize_sql_array(ary)
+ statement, *values = ary
+ if values.first.is_a?(Hash) && /:\w+/.match?(statement)
+ replace_named_bind_variables(statement, values.first)
+ elsif statement.include?("?")
+ replace_bind_variables(statement, values)
+ elsif statement.blank?
+ statement
+ else
+ statement % values.collect { |value| connection.quote_string(value.to_s) }
+ end
end
- end
- def replace_bind_variables(statement, values) # :nodoc:
- raise_if_bind_arity_mismatch(statement, statement.count("?"), values.size)
- bound = values.dup
- c = connection
- statement.gsub(/\?/) do
- replace_bind_variable(bound.shift, c)
+ def replace_bind_variables(statement, values) # :nodoc:
+ raise_if_bind_arity_mismatch(statement, statement.count("?"), values.size)
+ bound = values.dup
+ c = connection
+ statement.gsub(/\?/) do
+ replace_bind_variable(bound.shift, c)
+ end
end
- end
- def replace_bind_variable(value, c = connection) # :nodoc:
- if ActiveRecord::Relation === value
- value.to_sql
- else
- quote_bound_value(value, c)
+ def replace_bind_variable(value, c = connection) # :nodoc:
+ if ActiveRecord::Relation === value
+ value.to_sql
+ else
+ quote_bound_value(value, c)
+ end
end
- end
- def replace_named_bind_variables(statement, bind_vars) # :nodoc:
- statement.gsub(/(:?):([a-zA-Z]\w*)/) do |match|
- if $1 == ":" # skip postgresql casts
- match # return the whole match
- elsif bind_vars.include?(match = $2.to_sym)
- replace_bind_variable(bind_vars[match])
- else
- raise PreparedStatementInvalid, "missing value for :#{match} in #{statement}"
+ def replace_named_bind_variables(statement, bind_vars) # :nodoc:
+ statement.gsub(/(:?):([a-zA-Z]\w*)/) do |match|
+ if $1 == ":" # skip postgresql casts
+ match # return the whole match
+ elsif bind_vars.include?(match = $2.to_sym)
+ replace_bind_variable(bind_vars[match])
+ else
+ raise PreparedStatementInvalid, "missing value for :#{match} in #{statement}"
+ end
end
end
- end
- def quote_bound_value(value, c = connection) # :nodoc:
- if value.respond_to?(:map) && !value.acts_like?(:string)
- if value.respond_to?(:empty?) && value.empty?
- c.quote(nil)
+ def quote_bound_value(value, c = connection) # :nodoc:
+ if value.respond_to?(:map) && !value.acts_like?(:string)
+ if value.respond_to?(:empty?) && value.empty?
+ c.quote(nil)
+ else
+ value.map { |v| c.quote(v) }.join(",")
+ end
else
- value.map { |v| c.quote(v) }.join(",")
+ c.quote(value)
end
- else
- c.quote(value)
end
- end
- def raise_if_bind_arity_mismatch(statement, expected, provided) # :nodoc:
- unless expected == provided
- raise PreparedStatementInvalid, "wrong number of bind variables (#{provided} for #{expected}) in: #{statement}"
+ def raise_if_bind_arity_mismatch(statement, expected, provided) # :nodoc:
+ unless expected == provided
+ raise PreparedStatementInvalid, "wrong number of bind variables (#{provided} for #{expected}) in: #{statement}"
+ end
end
- end
end
# TODO: Deprecate this
diff --git a/activerecord/lib/active_record/scoping.rb b/activerecord/lib/active_record/scoping.rb
index 78231594d4..d1bd1cd89a 100644
--- a/activerecord/lib/active_record/scoping.rb
+++ b/activerecord/lib/active_record/scoping.rb
@@ -94,11 +94,11 @@ module ActiveRecord
private
- def raise_invalid_scope_type!(scope_type)
- if !VALID_SCOPE_TYPES.include?(scope_type)
- raise ArgumentError, "Invalid scope type '#{scope_type}' sent to the registry. Scope types must be included in VALID_SCOPE_TYPES"
+ def raise_invalid_scope_type!(scope_type)
+ if !VALID_SCOPE_TYPES.include?(scope_type)
+ raise ArgumentError, "Invalid scope type '#{scope_type}' sent to the registry. Scope types must be included in VALID_SCOPE_TYPES"
+ end
end
- end
end
end
end
diff --git a/activerecord/lib/active_record/scoping/default.rb b/activerecord/lib/active_record/scoping/default.rb
index 9eab59ac78..572a45aac9 100644
--- a/activerecord/lib/active_record/scoping/default.rb
+++ b/activerecord/lib/active_record/scoping/default.rb
@@ -87,62 +87,62 @@ module ActiveRecord
# # Should return a scope, you can call 'super' here etc.
# end
# end
- def default_scope(scope = nil)
- scope = Proc.new if block_given?
-
- if scope.is_a?(Relation) || !scope.respond_to?(:call)
- raise ArgumentError,
- "Support for calling #default_scope without a block is removed. For example instead " \
- "of `default_scope where(color: 'red')`, please use " \
- "`default_scope { where(color: 'red') }`. (Alternatively you can just redefine " \
- "self.default_scope.)"
- end
+ def default_scope(scope = nil)
+ scope = Proc.new if block_given?
+
+ if scope.is_a?(Relation) || !scope.respond_to?(:call)
+ raise ArgumentError,
+ "Support for calling #default_scope without a block is removed. For example instead " \
+ "of `default_scope where(color: 'red')`, please use " \
+ "`default_scope { where(color: 'red') }`. (Alternatively you can just redefine " \
+ "self.default_scope.)"
+ end
- self.default_scopes += [scope]
- end
+ self.default_scopes += [scope]
+ end
- def build_default_scope(base_rel = nil) # :nodoc:
- return if abstract_class?
+ def build_default_scope(base_rel = nil) # :nodoc:
+ return if abstract_class?
- if self.default_scope_override.nil?
- self.default_scope_override = !Base.is_a?(method(:default_scope).owner)
- end
+ if self.default_scope_override.nil?
+ self.default_scope_override = !Base.is_a?(method(:default_scope).owner)
+ end
- if self.default_scope_override
- # The user has defined their own default scope method, so call that
- evaluate_default_scope { default_scope }
- elsif default_scopes.any?
- base_rel ||= relation
- evaluate_default_scope do
- default_scopes.inject(base_rel) do |default_scope, scope|
- scope = scope.respond_to?(:to_proc) ? scope : scope.method(:call)
- default_scope.merge(base_rel.instance_exec(&scope))
+ if self.default_scope_override
+ # The user has defined their own default scope method, so call that
+ evaluate_default_scope { default_scope }
+ elsif default_scopes.any?
+ base_rel ||= relation
+ evaluate_default_scope do
+ default_scopes.inject(base_rel) do |default_scope, scope|
+ scope = scope.respond_to?(:to_proc) ? scope : scope.method(:call)
+ default_scope.merge(base_rel.instance_exec(&scope))
+ end
end
end
end
- end
- def ignore_default_scope? # :nodoc:
- ScopeRegistry.value_for(:ignore_default_scope, base_class)
- end
+ def ignore_default_scope? # :nodoc:
+ ScopeRegistry.value_for(:ignore_default_scope, base_class)
+ end
- def ignore_default_scope=(ignore) # :nodoc:
- ScopeRegistry.set_value_for(:ignore_default_scope, base_class, ignore)
- end
+ def ignore_default_scope=(ignore) # :nodoc:
+ ScopeRegistry.set_value_for(:ignore_default_scope, base_class, ignore)
+ end
# The ignore_default_scope flag is used to prevent an infinite recursion
# situation where a default scope references a scope which has a default
# scope which references a scope...
- def evaluate_default_scope # :nodoc:
- return if ignore_default_scope?
-
- begin
- self.ignore_default_scope = true
- yield
- ensure
- self.ignore_default_scope = false
+ def evaluate_default_scope # :nodoc:
+ return if ignore_default_scope?
+
+ begin
+ self.ignore_default_scope = true
+ yield
+ ensure
+ self.ignore_default_scope = false
+ end
end
- end
end
end
end
diff --git a/activerecord/lib/active_record/store.rb b/activerecord/lib/active_record/store.rb
index 2169d64137..f6bf2c7e48 100644
--- a/activerecord/lib/active_record/store.rb
+++ b/activerecord/lib/active_record/store.rb
@@ -177,34 +177,34 @@ module ActiveRecord
end
end
- class IndifferentCoder # :nodoc:
- def initialize(coder_or_class_name)
- @coder =
- if coder_or_class_name.respond_to?(:load) && coder_or_class_name.respond_to?(:dump)
- coder_or_class_name
- else
- ActiveRecord::Coders::YAMLColumn.new(coder_or_class_name || Object)
- end
- end
+ class IndifferentCoder # :nodoc:
+ def initialize(coder_or_class_name)
+ @coder =
+ if coder_or_class_name.respond_to?(:load) && coder_or_class_name.respond_to?(:dump)
+ coder_or_class_name
+ else
+ ActiveRecord::Coders::YAMLColumn.new(coder_or_class_name || Object)
+ end
+ end
- def dump(obj)
- @coder.dump self.class.as_indifferent_hash(obj)
- end
+ def dump(obj)
+ @coder.dump self.class.as_indifferent_hash(obj)
+ end
- def load(yaml)
- self.class.as_indifferent_hash(@coder.load(yaml || ""))
- end
+ def load(yaml)
+ self.class.as_indifferent_hash(@coder.load(yaml || ""))
+ end
- def self.as_indifferent_hash(obj)
- case obj
- when ActiveSupport::HashWithIndifferentAccess
- obj
- when Hash
- obj.with_indifferent_access
- else
- ActiveSupport::HashWithIndifferentAccess.new
+ def self.as_indifferent_hash(obj)
+ case obj
+ when ActiveSupport::HashWithIndifferentAccess
+ obj
+ when Hash
+ obj.with_indifferent_access
+ else
+ ActiveSupport::HashWithIndifferentAccess.new
+ end
end
end
- end
end
end
diff --git a/activerecord/lib/active_record/table_metadata.rb b/activerecord/lib/active_record/table_metadata.rb
index 5fe0d8b5e4..e8d6a144f9 100644
--- a/activerecord/lib/active_record/table_metadata.rb
+++ b/activerecord/lib/active_record/table_metadata.rb
@@ -64,6 +64,6 @@ module ActiveRecord
protected
- attr_reader :klass, :arel_table, :association
+ attr_reader :klass, :arel_table, :association
end
end
diff --git a/activerecord/lib/active_record/tasks/database_tasks.rb b/activerecord/lib/active_record/tasks/database_tasks.rb
index 269a1488f5..c0764fc4ab 100644
--- a/activerecord/lib/active_record/tasks/database_tasks.rb
+++ b/activerecord/lib/active_record/tasks/database_tasks.rb
@@ -77,7 +77,7 @@ module ActiveRecord
def fixtures_path
@fixtures_path ||= if ENV["FIXTURES_PATH"]
- File.join(root, ENV["FIXTURES_PATH"])
+ File.join(root, ENV["FIXTURES_PATH"])
else
File.join(root, "test", "fixtures")
end
@@ -275,39 +275,39 @@ module ActiveRecord
private
- def class_for_adapter(adapter)
- key = @tasks.keys.detect { |pattern| adapter[pattern] }
- unless key
- raise DatabaseNotSupported, "Rake tasks not supported by '#{adapter}' adapter"
+ def class_for_adapter(adapter)
+ key = @tasks.keys.detect { |pattern| adapter[pattern] }
+ unless key
+ raise DatabaseNotSupported, "Rake tasks not supported by '#{adapter}' adapter"
+ end
+ @tasks[key]
end
- @tasks[key]
- end
- def each_current_configuration(environment)
- environments = [environment]
- environments << "test" if environment == "development"
+ def each_current_configuration(environment)
+ environments = [environment]
+ environments << "test" if environment == "development"
- configurations = ActiveRecord::Base.configurations.values_at(*environments)
- configurations.compact.each do |configuration|
- yield configuration unless configuration["database"].blank?
+ configurations = ActiveRecord::Base.configurations.values_at(*environments)
+ configurations.compact.each do |configuration|
+ yield configuration unless configuration["database"].blank?
+ end
end
- end
- def each_local_configuration
- ActiveRecord::Base.configurations.each_value do |configuration|
- next unless configuration["database"]
+ def each_local_configuration
+ ActiveRecord::Base.configurations.each_value do |configuration|
+ next unless configuration["database"]
- if local_database?(configuration)
- yield configuration
- else
- $stderr.puts "This task only modifies local databases. #{configuration['database']} is on a remote host."
+ if local_database?(configuration)
+ yield configuration
+ else
+ $stderr.puts "This task only modifies local databases. #{configuration['database']} is on a remote host."
+ end
end
end
- end
- def local_database?(configuration)
- configuration["host"].blank? || LOCAL_HOSTS.include?(configuration["host"])
- end
+ def local_database?(configuration)
+ configuration["host"].blank? || LOCAL_HOSTS.include?(configuration["host"])
+ end
end
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 d10c1b05cd..c8b89f1fdf 100644
--- a/activerecord/lib/active_record/tasks/mysql_database_tasks.rb
+++ b/activerecord/lib/active_record/tasks/mysql_database_tasks.rb
@@ -74,79 +74,79 @@ module ActiveRecord
private
- def configuration
- @configuration
- end
+ def configuration
+ @configuration
+ end
- def configuration_without_database
- configuration.merge("database" => nil)
- end
+ def configuration_without_database
+ configuration.merge("database" => nil)
+ end
- def creation_options
- Hash.new.tap do |options|
- options[:charset] = configuration["encoding"] if configuration.include? "encoding"
- options[:collation] = configuration["collation"] if configuration.include? "collation"
+ def creation_options
+ Hash.new.tap do |options|
+ options[:charset] = configuration["encoding"] if configuration.include? "encoding"
+ options[:collation] = configuration["collation"] if configuration.include? "collation"
+ end
end
- end
- def error_class
- if configuration["adapter"].include?("jdbc")
- require "active_record/railties/jdbcmysql_error"
- ArJdbcMySQL::Error
- elsif defined?(Mysql2)
- Mysql2::Error
- else
- StandardError
+ def error_class
+ if configuration["adapter"].include?("jdbc")
+ require "active_record/railties/jdbcmysql_error"
+ ArJdbcMySQL::Error
+ elsif defined?(Mysql2)
+ Mysql2::Error
+ else
+ StandardError
+ end
end
- end
- def grant_statement
- <<-SQL
+ def grant_statement
+ <<-SQL
GRANT ALL PRIVILEGES ON #{configuration['database']}.*
TO '#{configuration['username']}'@'localhost'
IDENTIFIED BY '#{configuration['password']}' WITH GRANT OPTION;
SQL
- end
+ end
- def root_configuration_without_database
- configuration_without_database.merge(
- "username" => "root",
- "password" => root_password
- )
- end
+ def root_configuration_without_database
+ configuration_without_database.merge(
+ "username" => "root",
+ "password" => root_password
+ )
+ end
- def root_password
- $stdout.print "Please provide the root password for your MySQL installation\n>"
- $stdin.gets.strip
- end
+ def root_password
+ $stdout.print "Please provide the root password for your MySQL installation\n>"
+ $stdin.gets.strip
+ end
- def prepare_command_options
- args = {
- "host" => "--host",
- "port" => "--port",
- "socket" => "--socket",
- "username" => "--user",
- "password" => "--password",
- "encoding" => "--default-character-set",
- "sslca" => "--ssl-ca",
- "sslcert" => "--ssl-cert",
- "sslcapath" => "--ssl-capath",
- "sslcipher" => "--ssl-cipher",
- "sslkey" => "--ssl-key"
- }.map { |opt, arg| "#{arg}=#{configuration[opt]}" if configuration[opt] }.compact
-
- args
- end
+ def prepare_command_options
+ args = {
+ "host" => "--host",
+ "port" => "--port",
+ "socket" => "--socket",
+ "username" => "--user",
+ "password" => "--password",
+ "encoding" => "--default-character-set",
+ "sslca" => "--ssl-ca",
+ "sslcert" => "--ssl-cert",
+ "sslcapath" => "--ssl-capath",
+ "sslcipher" => "--ssl-cipher",
+ "sslkey" => "--ssl-key"
+ }.map { |opt, arg| "#{arg}=#{configuration[opt]}" if configuration[opt] }.compact
+
+ args
+ end
- def run_cmd(cmd, args, action)
- fail run_cmd_error(cmd, args, action) unless Kernel.system(cmd, *args)
- end
+ def run_cmd(cmd, args, action)
+ fail run_cmd_error(cmd, args, action) unless Kernel.system(cmd, *args)
+ end
- def run_cmd_error(cmd, args, action)
- msg = "failed to execute: `#{cmd}`\n"
- msg << "Please check the output above for any errors and make sure that `#{cmd}` is installed in your PATH and has proper permissions.\n\n"
- msg
- end
+ def run_cmd_error(cmd, args, action)
+ msg = "failed to execute: `#{cmd}`\n"
+ msg << "Please check the output above for any errors and make sure that `#{cmd}` is installed in your PATH and has proper permissions.\n\n"
+ msg
+ end
end
end
end
diff --git a/activerecord/lib/active_record/tasks/postgresql_database_tasks.rb b/activerecord/lib/active_record/tasks/postgresql_database_tasks.rb
index d290b12b73..c9e7262709 100644
--- a/activerecord/lib/active_record/tasks/postgresql_database_tasks.rb
+++ b/activerecord/lib/active_record/tasks/postgresql_database_tasks.rb
@@ -74,38 +74,38 @@ module ActiveRecord
private
- def configuration
- @configuration
- end
+ def configuration
+ @configuration
+ end
- def encoding
- configuration["encoding"] || DEFAULT_ENCODING
- end
+ def encoding
+ configuration["encoding"] || DEFAULT_ENCODING
+ end
- def establish_master_connection
- establish_connection configuration.merge(
- "database" => "postgres",
- "schema_search_path" => "public"
- )
- end
+ def establish_master_connection
+ establish_connection configuration.merge(
+ "database" => "postgres",
+ "schema_search_path" => "public"
+ )
+ end
- def set_psql_env
- ENV["PGHOST"] = configuration["host"] if configuration["host"]
- ENV["PGPORT"] = configuration["port"].to_s if configuration["port"]
- ENV["PGPASSWORD"] = configuration["password"].to_s if configuration["password"]
- ENV["PGUSER"] = configuration["username"].to_s if configuration["username"]
- end
+ def set_psql_env
+ ENV["PGHOST"] = configuration["host"] if configuration["host"]
+ ENV["PGPORT"] = configuration["port"].to_s if configuration["port"]
+ ENV["PGPASSWORD"] = configuration["password"].to_s if configuration["password"]
+ ENV["PGUSER"] = configuration["username"].to_s if configuration["username"]
+ end
- def run_cmd(cmd, args, action)
- fail run_cmd_error(cmd, args, action) unless Kernel.system(cmd, *args)
- end
+ def run_cmd(cmd, args, action)
+ fail run_cmd_error(cmd, args, action) unless Kernel.system(cmd, *args)
+ end
- def run_cmd_error(cmd, args, action)
- msg = "failed to execute:\n"
- msg << "#{cmd} #{args.join(' ')}\n\n"
- msg << "Please check the output above for any errors and make sure that `#{cmd}` is installed in your PATH and has proper permissions.\n\n"
- msg
- end
+ def run_cmd_error(cmd, args, action)
+ msg = "failed to execute:\n"
+ msg << "#{cmd} #{args.join(' ')}\n\n"
+ msg << "Please check the output above for any errors and make sure that `#{cmd}` is installed in your PATH and has proper permissions.\n\n"
+ msg
+ end
end
end
end
diff --git a/activerecord/lib/active_record/tasks/sqlite_database_tasks.rb b/activerecord/lib/active_record/tasks/sqlite_database_tasks.rb
index 8533fb6aa5..31f1b7efd4 100644
--- a/activerecord/lib/active_record/tasks/sqlite_database_tasks.rb
+++ b/activerecord/lib/active_record/tasks/sqlite_database_tasks.rb
@@ -47,13 +47,13 @@ module ActiveRecord
private
- def configuration
- @configuration
- end
+ def configuration
+ @configuration
+ end
- def root
- @root
- end
+ def root
+ @root
+ end
end
end
end
diff --git a/activerecord/lib/active_record/transactions.rb b/activerecord/lib/active_record/transactions.rb
index a140dd236f..b19ae5c46e 100644
--- a/activerecord/lib/active_record/transactions.rb
+++ b/activerecord/lib/active_record/transactions.rb
@@ -286,23 +286,23 @@ module ActiveRecord
private
- def set_options_for_callbacks!(args, enforced_options = {})
- options = args.extract_options!.merge!(enforced_options)
- args << options
-
- if options[:on]
- fire_on = Array(options[:on])
- assert_valid_transaction_action(fire_on)
- options[:if] = Array(options[:if])
- options[:if] << "transaction_include_any_action?(#{fire_on})"
+ def set_options_for_callbacks!(args, enforced_options = {})
+ options = args.extract_options!.merge!(enforced_options)
+ args << options
+
+ if options[:on]
+ fire_on = Array(options[:on])
+ assert_valid_transaction_action(fire_on)
+ options[:if] = Array(options[:if])
+ options[:if] << "transaction_include_any_action?(#{fire_on})"
+ end
end
- end
- def assert_valid_transaction_action(actions)
- if (actions - ACTIONS).any?
- raise ArgumentError, ":on conditions for after_commit and after_rollback callbacks have to be one of #{ACTIONS}"
+ def assert_valid_transaction_action(actions)
+ if (actions - ACTIONS).any?
+ raise ArgumentError, ":on conditions for after_commit and after_rollback callbacks have to be one of #{ACTIONS}"
+ end
end
- end
end
# See ActiveRecord::Transactions::ClassMethods for detailed documentation.
@@ -410,73 +410,73 @@ module ActiveRecord
protected
# Save the new record state and id of a record so it can be restored later if a transaction fails.
- def remember_transaction_record_state #:nodoc:
- @_start_transaction_state[:id] = id
- @_start_transaction_state.reverse_merge!(
- new_record: @new_record,
- destroyed: @destroyed,
- frozen?: frozen?,
- )
- @_start_transaction_state[:level] = (@_start_transaction_state[:level] || 0) + 1
- end
+ def remember_transaction_record_state #:nodoc:
+ @_start_transaction_state[:id] = id
+ @_start_transaction_state.reverse_merge!(
+ new_record: @new_record,
+ destroyed: @destroyed,
+ frozen?: frozen?,
+ )
+ @_start_transaction_state[:level] = (@_start_transaction_state[:level] || 0) + 1
+ end
# Clear the new record state and id of a record.
- def clear_transaction_record_state #:nodoc:
- @_start_transaction_state[:level] = (@_start_transaction_state[:level] || 0) - 1
- force_clear_transaction_record_state if @_start_transaction_state[:level] < 1
- end
+ def clear_transaction_record_state #:nodoc:
+ @_start_transaction_state[:level] = (@_start_transaction_state[:level] || 0) - 1
+ force_clear_transaction_record_state if @_start_transaction_state[:level] < 1
+ end
# Force to clear the transaction record state.
- def force_clear_transaction_record_state #:nodoc:
- @_start_transaction_state.clear
- end
+ def force_clear_transaction_record_state #:nodoc:
+ @_start_transaction_state.clear
+ end
# Restore the new record state and id of a record that was previously saved by a call to save_record_state.
- def restore_transaction_record_state(force = false) #:nodoc:
- unless @_start_transaction_state.empty?
- transaction_level = (@_start_transaction_state[:level] || 0) - 1
- if transaction_level < 1 || force
- restore_state = @_start_transaction_state
- thaw
- @new_record = restore_state[:new_record]
- @destroyed = restore_state[:destroyed]
- pk = self.class.primary_key
- if pk && read_attribute(pk) != restore_state[:id]
- write_attribute(pk, restore_state[:id])
+ def restore_transaction_record_state(force = false) #:nodoc:
+ unless @_start_transaction_state.empty?
+ transaction_level = (@_start_transaction_state[:level] || 0) - 1
+ if transaction_level < 1 || force
+ restore_state = @_start_transaction_state
+ thaw
+ @new_record = restore_state[:new_record]
+ @destroyed = restore_state[:destroyed]
+ pk = self.class.primary_key
+ if pk && read_attribute(pk) != restore_state[:id]
+ write_attribute(pk, restore_state[:id])
+ end
+ freeze if restore_state[:frozen?]
end
- freeze if restore_state[:frozen?]
end
end
- end
# Determine if a record was created or destroyed in a transaction. State should be one of :new_record or :destroyed.
- def transaction_record_state(state) #:nodoc:
- @_start_transaction_state[state]
- end
+ def transaction_record_state(state) #:nodoc:
+ @_start_transaction_state[state]
+ end
# Determine if a transaction included an action for :create, :update, or :destroy. Used in filtering callbacks.
- def transaction_include_any_action?(actions) #:nodoc:
- actions.any? do |action|
- case action
- when :create
- transaction_record_state(:new_record)
- when :destroy
- destroyed?
- when :update
- !(transaction_record_state(:new_record) || destroyed?)
+ def transaction_include_any_action?(actions) #:nodoc:
+ actions.any? do |action|
+ case action
+ when :create
+ transaction_record_state(:new_record)
+ when :destroy
+ destroyed?
+ when :update
+ !(transaction_record_state(:new_record) || destroyed?)
+ end
end
end
- end
private
- def set_transaction_state(state) # :nodoc:
- @transaction_state = state
- end
+ def set_transaction_state(state) # :nodoc:
+ @transaction_state = state
+ end
- def has_transactional_callbacks? # :nodoc:
- !_rollback_callbacks.empty? || !_commit_callbacks.empty? || !_before_commit_callbacks.empty?
- end
+ def has_transactional_callbacks? # :nodoc:
+ !_rollback_callbacks.empty? || !_commit_callbacks.empty? || !_before_commit_callbacks.empty?
+ end
# 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
@@ -495,15 +495,15 @@ module ActiveRecord
# Since Active Record objects can be inside multiple transactions, this
# method recursively goes through the parent of the TransactionState and
# checks if the Active Record object reflects the state of the object.
- def sync_with_transaction_state
- update_attributes_from_transaction_state(@transaction_state)
- end
+ def sync_with_transaction_state
+ update_attributes_from_transaction_state(@transaction_state)
+ end
- def update_attributes_from_transaction_state(transaction_state)
- if transaction_state && transaction_state.finalized?
- restore_transaction_record_state if transaction_state.rolledback?
- clear_transaction_record_state
+ def update_attributes_from_transaction_state(transaction_state)
+ if transaction_state && transaction_state.finalized?
+ restore_transaction_record_state if transaction_state.rolledback?
+ clear_transaction_record_state
+ end
end
- end
end
end
diff --git a/activerecord/lib/active_record/type/adapter_specific_registry.rb b/activerecord/lib/active_record/type/adapter_specific_registry.rb
index 208bc8def5..d0f9581576 100644
--- a/activerecord/lib/active_record/type/adapter_specific_registry.rb
+++ b/activerecord/lib/active_record/type/adapter_specific_registry.rb
@@ -10,15 +10,15 @@ module ActiveRecord
private
- def registration_klass
- Registration
- end
+ def registration_klass
+ Registration
+ end
- def find_registration(symbol, *args)
- registrations
- .select { |registration| registration.matches?(symbol, *args) }
- .max
- end
+ def find_registration(symbol, *args)
+ registrations
+ .select { |registration| registration.matches?(symbol, *args) }
+ .max
+ end
end
class Registration
@@ -52,42 +52,42 @@ module ActiveRecord
protected
- attr_reader :name, :block, :adapter, :override
-
- def priority
- result = 0
- if adapter
- result |= 1
- end
- if override
- result |= 2
+ attr_reader :name, :block, :adapter, :override
+
+ def priority
+ result = 0
+ if adapter
+ result |= 1
+ end
+ if override
+ result |= 2
+ end
+ result
end
- result
- end
- def priority_except_adapter
- priority & 0b111111100
- end
+ def priority_except_adapter
+ priority & 0b111111100
+ end
private
- def matches_adapter?(adapter: nil, **)
- (self.adapter.nil? || adapter == self.adapter)
- end
+ def matches_adapter?(adapter: nil, **)
+ (self.adapter.nil? || adapter == self.adapter)
+ end
- def conflicts_with?(other)
- same_priority_except_adapter?(other) &&
- has_adapter_conflict?(other)
- end
+ def conflicts_with?(other)
+ same_priority_except_adapter?(other) &&
+ has_adapter_conflict?(other)
+ end
- def same_priority_except_adapter?(other)
- priority_except_adapter == other.priority_except_adapter
- end
+ def same_priority_except_adapter?(other)
+ priority_except_adapter == other.priority_except_adapter
+ end
- def has_adapter_conflict?(other)
- (override.nil? && other.adapter) ||
- (adapter && other.override.nil?)
- end
+ def has_adapter_conflict?(other)
+ (override.nil? && other.adapter) ||
+ (adapter && other.override.nil?)
+ end
end
class DecorationRegistration < Registration
@@ -112,15 +112,15 @@ module ActiveRecord
protected
- attr_reader :options, :klass
+ attr_reader :options, :klass
private
- def matches_options?(**kwargs)
- options.all? do |key, value|
- kwargs[key] == value
+ def matches_options?(**kwargs)
+ options.all? do |key, value|
+ kwargs[key] == value
+ end
end
- end
end
end
diff --git a/activerecord/lib/active_record/type/hash_lookup_type_map.rb b/activerecord/lib/active_record/type/hash_lookup_type_map.rb
index 3b01e3f8ca..0145d5d6c1 100644
--- a/activerecord/lib/active_record/type/hash_lookup_type_map.rb
+++ b/activerecord/lib/active_record/type/hash_lookup_type_map.rb
@@ -15,9 +15,9 @@ module ActiveRecord
private
- def perform_fetch(type, *args, &block)
- @mapping.fetch(type, block).call(type, *args)
- end
+ def perform_fetch(type, *args, &block)
+ @mapping.fetch(type, block).call(type, *args)
+ end
end
end
end
diff --git a/activerecord/lib/active_record/type/serialized.rb b/activerecord/lib/active_record/type/serialized.rb
index a3a5241780..ac9134bfcb 100644
--- a/activerecord/lib/active_record/type/serialized.rb
+++ b/activerecord/lib/active_record/type/serialized.rb
@@ -49,15 +49,15 @@ module ActiveRecord
private
- def default_value?(value)
- value == coder.load(nil)
- end
+ def default_value?(value)
+ value == coder.load(nil)
+ end
- def encoded(value)
- unless default_value?(value)
- coder.dump(value)
+ def encoded(value)
+ unless default_value?(value)
+ coder.dump(value)
+ end
end
- end
end
end
end
diff --git a/activerecord/lib/active_record/type/time.rb b/activerecord/lib/active_record/type/time.rb
index 7da49e43c7..b9bac87c67 100644
--- a/activerecord/lib/active_record/type/time.rb
+++ b/activerecord/lib/active_record/type/time.rb
@@ -17,4 +17,3 @@ module ActiveRecord
end
end
end
-
diff --git a/activerecord/lib/active_record/type/type_map.rb b/activerecord/lib/active_record/type/type_map.rb
index 1f744ef115..9618ff8787 100644
--- a/activerecord/lib/active_record/type/type_map.rb
+++ b/activerecord/lib/active_record/type/type_map.rb
@@ -44,21 +44,21 @@ module ActiveRecord
private
- def perform_fetch(lookup_key, *args)
- matching_pair = @mapping.reverse_each.detect do |key, _|
- key === lookup_key
- end
+ def perform_fetch(lookup_key, *args)
+ matching_pair = @mapping.reverse_each.detect do |key, _|
+ key === lookup_key
+ end
- if matching_pair
- matching_pair.last.call(lookup_key, *args)
- else
- yield lookup_key, *args
+ if matching_pair
+ matching_pair.last.call(lookup_key, *args)
+ else
+ yield lookup_key, *args
+ end
end
- end
- def default_value
- @default_value ||= ActiveModel::Type::Value.new
- end
+ def default_value
+ @default_value ||= ActiveModel::Type::Value.new
+ end
end
end
end
diff --git a/activerecord/lib/active_record/type_caster/connection.rb b/activerecord/lib/active_record/type_caster/connection.rb
index 7ed8dcc313..6c54792e26 100644
--- a/activerecord/lib/active_record/type_caster/connection.rb
+++ b/activerecord/lib/active_record/type_caster/connection.rb
@@ -14,16 +14,16 @@ module ActiveRecord
protected
- attr_reader :table_name
- delegate :connection, to: :@klass
+ attr_reader :table_name
+ delegate :connection, to: :@klass
private
- def column_for(attribute_name)
- if connection.schema_cache.data_source_exists?(table_name)
- connection.schema_cache.columns_hash(table_name)[attribute_name.to_s]
+ def column_for(attribute_name)
+ if connection.schema_cache.data_source_exists?(table_name)
+ connection.schema_cache.columns_hash(table_name)[attribute_name.to_s]
+ end
end
- end
end
end
end
diff --git a/activerecord/lib/active_record/type_caster/map.rb b/activerecord/lib/active_record/type_caster/map.rb
index 3a367b3999..52529a6b42 100644
--- a/activerecord/lib/active_record/type_caster/map.rb
+++ b/activerecord/lib/active_record/type_caster/map.rb
@@ -13,7 +13,7 @@ module ActiveRecord
protected
- attr_reader :types
+ attr_reader :types
end
end
end
diff --git a/activerecord/lib/rails/generators/active_record/migration/migration_generator.rb b/activerecord/lib/rails/generators/active_record/migration/migration_generator.rb
index 66ef62a76c..76182a3c24 100644
--- a/activerecord/lib/rails/generators/active_record/migration/migration_generator.rb
+++ b/activerecord/lib/rails/generators/active_record/migration/migration_generator.rb
@@ -15,43 +15,43 @@ module ActiveRecord
end
protected
- attr_reader :migration_action, :join_tables
+ attr_reader :migration_action, :join_tables
# Sets the default migration template that is being used for the generation of the migration.
# Depending on command line arguments, the migration template and the table name instance
# variables are set up.
- def set_local_assigns!
- @migration_template = "migration.rb"
- case file_name
- when /^(add|remove)_.*_(?:to|from)_(.*)/
- @migration_action = $1
- @table_name = normalize_table_name($2)
- when /join_table/
- if attributes.length == 2
- @migration_action = "join"
- @join_tables = pluralize_table_names? ? attributes.map(&:plural_name) : attributes.map(&:singular_name)
+ def set_local_assigns!
+ @migration_template = "migration.rb"
+ case file_name
+ when /^(add|remove)_.*_(?:to|from)_(.*)/
+ @migration_action = $1
+ @table_name = normalize_table_name($2)
+ when /join_table/
+ if attributes.length == 2
+ @migration_action = "join"
+ @join_tables = pluralize_table_names? ? attributes.map(&:plural_name) : attributes.map(&:singular_name)
- set_index_names
+ set_index_names
+ end
+ when /^create_(.+)/
+ @table_name = normalize_table_name($1)
+ @migration_template = "create_table_migration.rb"
end
- when /^create_(.+)/
- @table_name = normalize_table_name($1)
- @migration_template = "create_table_migration.rb"
end
- end
- def set_index_names
- attributes.each_with_index do |attr, i|
- attr.index_name = [attr, attributes[i - 1]].map{ |a| index_name_for(a) }
+ def set_index_names
+ attributes.each_with_index do |attr, i|
+ attr.index_name = [attr, attributes[i - 1]].map{ |a| index_name_for(a) }
+ end
end
- end
- def index_name_for(attribute)
- if attribute.foreign_key?
- attribute.name
- else
- attribute.name.singularize.foreign_key
- end.to_sym
- end
+ def index_name_for(attribute)
+ if attribute.foreign_key?
+ attribute.name
+ else
+ attribute.name.singularize.foreign_key
+ end.to_sym
+ end
private
def attributes_with_index