diff options
author | Aaron Patterson <aaron.patterson@gmail.com> | 2013-10-15 14:45:00 -0700 |
---|---|---|
committer | Aaron Patterson <aaron.patterson@gmail.com> | 2013-10-15 14:45:00 -0700 |
commit | ee46f1d5d2a8825de2d4973fb0301f2d85986e73 (patch) | |
tree | 23bc39bf0a63c4436ce3aadedfab9dd7cde5b909 /activerecord/lib/active_record | |
parent | 704bf0ecc550552f1cc5e453771917e8782b64ad (diff) | |
parent | e3e3851ed662fc55ee88c16a3cd9bb87f24e6bd6 (diff) | |
download | rails-ee46f1d5d2a8825de2d4973fb0301f2d85986e73.tar.gz rails-ee46f1d5d2a8825de2d4973fb0301f2d85986e73.tar.bz2 rails-ee46f1d5d2a8825de2d4973fb0301f2d85986e73.zip |
Merge branch 'master' into joindep
* master: (44 commits)
grammar fix (reverted in e9a1ecd)
Revert "fixed a doc bug in the CHANGELOG.md s/does no longer depend on/no longer depends on/"
Add missed require making `enable_warnings` available
Prepare generated Gemfile for Capistrano 3
Added --model-name option scaffold_controller_generator.
read the association instead of sending
we should have unique sponsorable ids in the fixtures at least
simplify populating the ordering hash
the preloader for the RHS has all the preloaded records, so ask it
only calculate offset index once. #12537
Remove size alias for length validation
Fix `singleton_class?`
Minor Refactoring to `NumberHelper#number_to_human`
`$SAFE = 4;` has been removed with Ruby 2.1
scope_chain should not be mutated for other reflections
Remove `default_primary_key_type` and extract contains of `native_database_types` to a constant since they aren't conditional now in SQLite3Adapter. Makes it more like other adapters.
cleanup changelog entry format. [ci skip]
Extract a function to determine if the default value is a function
Push default_function to superclass to avoid method check
Dump the default function when the primary key is uuid
...
Conflicts:
activerecord/lib/active_record/relation/finder_methods.rb
Diffstat (limited to 'activerecord/lib/active_record')
15 files changed, 90 insertions, 81 deletions
diff --git a/activerecord/lib/active_record/associations/association.rb b/activerecord/lib/active_record/associations/association.rb index 04c36d5740..e6a45487d0 100644 --- a/activerecord/lib/active_record/associations/association.rb +++ b/activerecord/lib/active_record/associations/association.rb @@ -17,6 +17,7 @@ module ActiveRecord # HasManyThroughAssociation + ThroughAssociation class Association #:nodoc: attr_reader :owner, :target, :reflection + attr_accessor :inversed delegate :options, :to => :reflection @@ -42,6 +43,7 @@ module ActiveRecord @loaded = false @target = nil @stale_state = nil + @inversed = false end # Reloads the \target and returns +self+ on success. @@ -59,8 +61,9 @@ module ActiveRecord # Asserts the \target has been loaded setting the \loaded flag to +true+. def loaded! - @loaded = true + @loaded = true @stale_state = stale_state + @inversed = false end # The target is stale if the target no longer points to the record(s) that the @@ -70,7 +73,7 @@ module ActiveRecord # # Note that if the target has not been loaded, it is not considered stale. def stale_target? - loaded? && @stale_state != stale_state + !inversed && loaded? && @stale_state != stale_state end # Sets the target of this association to <tt>\target</tt>, and the \loaded flag to +true+. @@ -104,6 +107,7 @@ module ActiveRecord if record && invertible_for?(record) inverse = record.association(inverse_reflection_for(record).name) inverse.target = owner + inverse.inversed = true end end diff --git a/activerecord/lib/active_record/associations/collection_association.rb b/activerecord/lib/active_record/associations/collection_association.rb index 75f8990cf0..6b06a5f7fd 100644 --- a/activerecord/lib/active_record/associations/collection_association.rb +++ b/activerecord/lib/active_record/associations/collection_association.rb @@ -195,9 +195,7 @@ module ActiveRecord # Count all records using SQL. Construct options and pass them with # scope to the target class's +count+. - def count(column_name = nil, count_options = {}) - column_name, count_options = nil, column_name if column_name.is_a?(Hash) - + def count(column_name = nil) relation = scope if association_scope.distinct_value # This is needed because 'SELECT count(DISTINCT *)..' is not valid SQL. diff --git a/activerecord/lib/active_record/associations/collection_proxy.rb b/activerecord/lib/active_record/associations/collection_proxy.rb index ea7f768a68..0b6cdf5217 100644 --- a/activerecord/lib/active_record/associations/collection_proxy.rb +++ b/activerecord/lib/active_record/associations/collection_proxy.rb @@ -669,8 +669,8 @@ module ActiveRecord # # #<Pet id: 2, name: "Spook", person_id: 1>, # # #<Pet id: 3, name: "Choo-Choo", person_id: 1> # # ] - def count(column_name = nil, options = {}) - @association.count(column_name, options) + def count(column_name = nil) + @association.count(column_name) end # Returns the size of the collection. If the collection hasn't been loaded, diff --git a/activerecord/lib/active_record/associations/preloader.rb b/activerecord/lib/active_record/associations/preloader.rb index 713ff80d47..2393667ac8 100644 --- a/activerecord/lib/active_record/associations/preloader.rb +++ b/activerecord/lib/active_record/associations/preloader.rb @@ -153,13 +153,13 @@ module ActiveRecord records.group_by do |record| reflection = record.class.reflect_on_association(association) - reflection || raise_config_error(association) + reflection || raise_config_error(record, association) end end - def raise_config_error(association) + def raise_config_error(record, association) raise ActiveRecord::ConfigurationError, - "Association named '#{association}' was not found; " \ + "Association named '#{association}' was not found on #{record.class.name}; " \ "perhaps you misspelled it?" end diff --git a/activerecord/lib/active_record/associations/preloader/through_association.rb b/activerecord/lib/active_record/associations/preloader/through_association.rb index ea21836c65..2a8530af62 100644 --- a/activerecord/lib/active_record/associations/preloader/through_association.rb +++ b/activerecord/lib/active_record/associations/preloader/through_association.rb @@ -15,7 +15,7 @@ module ActiveRecord through_reflection.name, through_scope) - through_records = owners.map do |owner, h| + through_records = owners.map do |owner| association = owner.association through_reflection.name [owner, Array(association.reader)] @@ -29,29 +29,30 @@ module ActiveRecord source_reflection.name, reflection_scope) + @preloaded_records = preloaders.flat_map(&:preloaded_records) + middle_to_pl = preloaders.each_with_object({}) do |pl,h| pl.owners.each { |middle| h[middle] = pl } end + record_offset = {} + @preloaded_records.each_with_index do |record,i| + record_offset[record] = i + end + through_records.each_with_object({}) { |(lhs,center),records_by_owner| pl_to_middle = center.group_by { |record| middle_to_pl[record] } records_by_owner[lhs] = pl_to_middle.flat_map do |pl, middles| rhs_records = middles.flat_map { |r| - r.send(source_reflection.name) + association = r.association source_reflection.name + + association.reader }.compact - loaded_records = pl.preloaded_records - i = 0 - record_index = loaded_records.each_with_object({}) { |r,indexes| - indexes[r] = i - i += 1 - } - records = rhs_records.sort_by { |rhs| record_index[rhs] } - @preloaded_records.concat rhs_records - records + rhs_records.sort_by { |rhs| record_offset[rhs] } end } end diff --git a/activerecord/lib/active_record/connection_adapters/column.rb b/activerecord/lib/active_record/connection_adapters/column.rb index 2596c221bc..f2fbd5a8f2 100644 --- a/activerecord/lib/active_record/connection_adapters/column.rb +++ b/activerecord/lib/active_record/connection_adapters/column.rb @@ -13,7 +13,7 @@ module ActiveRecord ISO_DATETIME = /\A(\d{4})-(\d\d)-(\d\d) (\d\d):(\d\d):(\d\d)(\.\d+)?\z/ end - attr_reader :name, :default, :type, :limit, :null, :sql_type, :precision, :scale + attr_reader :name, :default, :type, :limit, :null, :sql_type, :precision, :scale, :default_function attr_accessor :primary, :coder alias :encoded? :coder @@ -27,16 +27,17 @@ module ActiveRecord # It will be mapped to one of the standard Rails SQL types in the <tt>type</tt> attribute. # +null+ determines if this column allows +NULL+ values. def initialize(name, default, sql_type = nil, null = true) - @name = name - @sql_type = sql_type - @null = null - @limit = extract_limit(sql_type) - @precision = extract_precision(sql_type) - @scale = extract_scale(sql_type) - @type = simplified_type(sql_type) - @default = extract_default(default) - @primary = nil - @coder = nil + @name = name + @sql_type = sql_type + @null = null + @limit = extract_limit(sql_type) + @precision = extract_precision(sql_type) + @scale = extract_scale(sql_type) + @type = simplified_type(sql_type) + @default = extract_default(default) + @default_function = nil + @primary = nil + @coder = nil end # Returns +true+ if the column is either of type string or text. diff --git a/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb b/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb index 0c4d005e63..771a150eae 100644 --- a/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb +++ b/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb @@ -45,12 +45,12 @@ module ActiveRecord module ConnectionAdapters # PostgreSQL-specific extensions to column definitions in a table. class PostgreSQLColumn < Column #:nodoc: - attr_accessor :array, :default_function + attr_accessor :array # Instantiates a new PostgreSQL column definition in a table. def initialize(name, default, oid_type, sql_type = nil, null = true) @oid_type = oid_type default_value = self.class.extract_value_from_default(default) - @default_function = default if !default_value && default && default =~ /.+\(.*\)/ + if sql_type =~ /\[\]$/ @array = true super(name, default_value, sql_type[0..sql_type.length - 3], null) @@ -58,6 +58,8 @@ module ActiveRecord @array = false super(name, default_value, sql_type, null) end + + @default_function = default if has_default_function?(default_value, default) end # :stopdoc: @@ -148,6 +150,10 @@ module ActiveRecord private + def has_default_function?(default_value, default) + !default_value && (%r{\w+(.*)} === default) + end + def extract_limit(sql_type) case sql_type when /^bigint/i; 8 @@ -442,7 +448,7 @@ module ActiveRecord def prepare_column_options(column, types) spec = super spec[:array] = 'true' if column.respond_to?(:array) && column.array - spec[:default] = "\"#{column.default_function}\"" if column.respond_to?(:default_function) && column.default_function + spec[:default] = "\"#{column.default_function}\"" if column.default_function spec end diff --git a/activerecord/lib/active_record/connection_adapters/sqlite3_adapter.rb b/activerecord/lib/active_record/connection_adapters/sqlite3_adapter.rb index 997384daea..e5ad08b6b0 100644 --- a/activerecord/lib/active_record/connection_adapters/sqlite3_adapter.rb +++ b/activerecord/lib/active_record/connection_adapters/sqlite3_adapter.rb @@ -55,6 +55,21 @@ module ActiveRecord class SQLite3Adapter < AbstractAdapter include Savepoints + NATIVE_DATABASE_TYPES = { + primary_key: 'INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL', + string: { name: "varchar", limit: 255 }, + text: { name: "text" }, + integer: { name: "integer" }, + float: { name: "float" }, + decimal: { name: "decimal" }, + datetime: { name: "datetime" }, + timestamp: { name: "datetime" }, + time: { name: "time" }, + date: { name: "date" }, + binary: { name: "blob" }, + boolean: { name: "boolean" } + } + class Version include Comparable @@ -183,11 +198,6 @@ module ActiveRecord true end - # Returns true - def supports_autoincrement? #:nodoc: - true - end - def supports_index_sort_order? true end @@ -200,20 +210,7 @@ module ActiveRecord end def native_database_types #:nodoc: - { - :primary_key => default_primary_key_type, - :string => { :name => "varchar", :limit => 255 }, - :text => { :name => "text" }, - :integer => { :name => "integer" }, - :float => { :name => "float" }, - :decimal => { :name => "decimal" }, - :datetime => { :name => "datetime" }, - :timestamp => { :name => "datetime" }, - :time => { :name => "time" }, - :date => { :name => "date" }, - :binary => { :name => "blob" }, - :boolean => { :name => "boolean" } - } + NATIVE_DATABASE_TYPES end # Returns the current database encoding format as a string, eg: 'UTF-8' @@ -596,14 +593,6 @@ module ActiveRecord @sqlite_version ||= SQLite3Adapter::Version.new(select_value('select sqlite_version(*)')) end - def default_primary_key_type - if supports_autoincrement? - 'INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL' - else - 'INTEGER PRIMARY KEY NOT NULL' - end - end - def translate_exception(exception, message) case exception.message when /column(s)? .* (is|are) not unique/ diff --git a/activerecord/lib/active_record/null_relation.rb b/activerecord/lib/active_record/null_relation.rb index 716020e7e7..1f3d377e53 100644 --- a/activerecord/lib/active_record/null_relation.rb +++ b/activerecord/lib/active_record/null_relation.rb @@ -50,7 +50,7 @@ module ActiveRecord 0 end - def calculate(_operation, _column_name, _options = {}) + def calculate(_operation, _column_name) if _operation == :count 0 else diff --git a/activerecord/lib/active_record/railties/databases.rake b/activerecord/lib/active_record/railties/databases.rake index daccab762f..ecadb95a5d 100644 --- a/activerecord/lib/active_record/railties/databases.rake +++ b/activerecord/lib/active_record/railties/databases.rake @@ -287,6 +287,7 @@ db_namespace = namespace :db do if ActiveRecord::Base.connection.supports_migrations? File.open(filename, "a") do |f| f.puts ActiveRecord::Base.connection.dump_schema_information + f.print "\n" end end db_namespace['structure:dump'].reenable diff --git a/activerecord/lib/active_record/reflection.rb b/activerecord/lib/active_record/reflection.rb index e88c5d17cb..bce7766501 100644 --- a/activerecord/lib/active_record/reflection.rb +++ b/activerecord/lib/active_record/reflection.rb @@ -574,7 +574,7 @@ module ActiveRecord # Add to it the scope from this reflection (if any) scope_chain.first << scope if scope - through_scope_chain = through_reflection.scope_chain + through_scope_chain = through_reflection.scope_chain.map(&:dup) if options[:source_type] through_scope_chain.first << diff --git a/activerecord/lib/active_record/relation/calculations.rb b/activerecord/lib/active_record/relation/calculations.rb index 27c04b0952..2d267183ce 100644 --- a/activerecord/lib/active_record/relation/calculations.rb +++ b/activerecord/lib/active_record/relation/calculations.rb @@ -19,17 +19,16 @@ module ActiveRecord # # Person.group(:city).count # # => { 'Rome' => 5, 'Paris' => 3 } - def count(column_name = nil, options = {}) - column_name, options = nil, column_name if column_name.is_a?(Hash) - calculate(:count, column_name, options) + def count(column_name = nil) + calculate(:count, column_name) end # Calculates the average value on a given column. Returns +nil+ if there's # no row. See +calculate+ for examples with options. # # Person.average(:age) # => 35.8 - def average(column_name, options = {}) - calculate(:average, column_name, options) + def average(column_name) + calculate(:average, column_name) end # Calculates the minimum value on a given column. The value is returned @@ -37,8 +36,8 @@ module ActiveRecord # +calculate+ for examples with options. # # Person.minimum(:age) # => 7 - def minimum(column_name, options = {}) - calculate(:minimum, column_name, options) + def minimum(column_name) + calculate(:minimum, column_name) end # Calculates the maximum value on a given column. The value is returned @@ -46,8 +45,8 @@ module ActiveRecord # +calculate+ for examples with options. # # Person.maximum(:age) # => 93 - def maximum(column_name, options = {}) - calculate(:maximum, column_name, options) + def maximum(column_name) + calculate(:maximum, column_name) end # Calculates the sum of values on a given column. The value is returned @@ -90,15 +89,15 @@ module ActiveRecord # Person.group(:last_name).having("min(age) > 17").minimum(:age) # # Person.sum("2 * age") - def calculate(operation, column_name, options = {}) + def calculate(operation, column_name) if column_name.is_a?(Symbol) && attribute_alias?(column_name) column_name = attribute_alias(column_name) end if has_include?(column_name) - construct_relation_for_association_calculations.calculate(operation, column_name, options) + construct_relation_for_association_calculations.calculate(operation, column_name) else - perform_calculation(operation, column_name, options) + perform_calculation(operation, column_name) end end @@ -181,7 +180,7 @@ module ActiveRecord eager_loading? || (includes_values.present? && (column_name || references_eager_loaded_tables?)) end - def perform_calculation(operation, column_name, options = {}) + def perform_calculation(operation, column_name) operation = operation.to_s.downcase # If #count is used with #distinct / #uniq it is considered distinct. (eg. relation.distinct.count) diff --git a/activerecord/lib/active_record/relation/finder_methods.rb b/activerecord/lib/active_record/relation/finder_methods.rb index f7f60635d3..a2c18c5226 100644 --- a/activerecord/lib/active_record/relation/finder_methods.rb +++ b/activerecord/lib/active_record/relation/finder_methods.rb @@ -242,10 +242,9 @@ module ActiveRecord def find_with_associations join_dependency = construct_join_dependency - relation = except :select aliases = join_dependency.aliases - relation = relation.select aliases.columns + relation = select aliases.columns relation = apply_join_dependency(relation, join_dependency) if block_given? diff --git a/activerecord/lib/active_record/sanitization.rb b/activerecord/lib/active_record/sanitization.rb index 0b87ab9926..cab8fd745a 100644 --- a/activerecord/lib/active_record/sanitization.rb +++ b/activerecord/lib/active_record/sanitization.rb @@ -127,7 +127,17 @@ module ActiveRecord raise_if_bind_arity_mismatch(statement, statement.count('?'), values.size) bound = values.dup c = connection - statement.gsub('?') { quote_bound_value(bound.shift, c) } + statement.gsub('?') do + replace_bind_variable(bound.shift, c) + end + end + + def replace_bind_variable(value, c = connection) #:nodoc: + if ActiveRecord::Relation === value + value.to_sql + else + quote_bound_value(value, c) + end end def replace_named_bind_variables(statement, bind_vars) #:nodoc: @@ -135,7 +145,7 @@ module ActiveRecord if $1 == ':' # skip postgresql casts $& # return the whole match elsif bind_vars.include?(match = $2.to_sym) - quote_bound_value(bind_vars[match]) + replace_bind_variable(bind_vars[match]) else raise PreparedStatementInvalid, "missing value for :#{match} in #{statement}" end diff --git a/activerecord/lib/active_record/schema_dumper.rb b/activerecord/lib/active_record/schema_dumper.rb index 8986d255cd..e055d571ab 100644 --- a/activerecord/lib/active_record/schema_dumper.rb +++ b/activerecord/lib/active_record/schema_dumper.rb @@ -123,6 +123,7 @@ HEADER tbl.print %Q(, primary_key: "#{pk}") elsif pkcol.sql_type == 'uuid' tbl.print ", id: :uuid" + tbl.print %Q(, default: "#{pkcol.default_function}") if pkcol.default_function end else tbl.print ", id: false" |