aboutsummaryrefslogtreecommitdiffstats
path: root/activerecord/lib
diff options
context:
space:
mode:
Diffstat (limited to 'activerecord/lib')
-rw-r--r--activerecord/lib/active_record/associations/has_many_through_association.rb2
-rw-r--r--activerecord/lib/active_record/associations/preloader/through_association.rb1
-rw-r--r--activerecord/lib/active_record/connection_adapters/abstract_adapter.rb11
-rw-r--r--activerecord/lib/active_record/connection_adapters/mysql_adapter.rb2
-rw-r--r--activerecord/lib/active_record/connection_adapters/postgresql/database_statements.rb2
-rw-r--r--activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb11
-rw-r--r--activerecord/lib/active_record/connection_adapters/sqlite3_adapter.rb2
-rw-r--r--activerecord/lib/active_record/fixtures.rb2
-rw-r--r--activerecord/lib/active_record/railties/databases.rake3
-rw-r--r--activerecord/lib/active_record/relation.rb19
-rw-r--r--activerecord/lib/active_record/relation/calculations.rb3
-rw-r--r--activerecord/lib/active_record/relation/finder_methods.rb11
-rw-r--r--activerecord/lib/active_record/relation/predicate_builder/relation_handler.rb2
-rw-r--r--activerecord/lib/active_record/relation/query_methods.rb37
-rw-r--r--activerecord/lib/active_record/sanitization.rb5
15 files changed, 78 insertions, 35 deletions
diff --git a/activerecord/lib/active_record/associations/has_many_through_association.rb b/activerecord/lib/active_record/associations/has_many_through_association.rb
index 04a69ba446..bde23fc116 100644
--- a/activerecord/lib/active_record/associations/has_many_through_association.rb
+++ b/activerecord/lib/active_record/associations/has_many_through_association.rb
@@ -161,7 +161,7 @@ module ActiveRecord
if scope.klass.primary_key
count = scope.destroy_all.length
else
- scope.to_a.each do |record|
+ scope.each do |record|
record._run_destroy_callbacks
end
diff --git a/activerecord/lib/active_record/associations/preloader/through_association.rb b/activerecord/lib/active_record/associations/preloader/through_association.rb
index d57da366bd..12bf3ef138 100644
--- a/activerecord/lib/active_record/associations/preloader/through_association.rb
+++ b/activerecord/lib/active_record/associations/preloader/through_association.rb
@@ -81,6 +81,7 @@ module ActiveRecord
unless reflection_scope.where_values.empty?
scope.includes_values = Array(reflection_scope.values[:includes] || options[:source])
scope.where_values = reflection_scope.values[:where]
+ scope.bind_values = reflection_scope.bind_values
end
scope.references! reflection_scope.values[:references]
diff --git a/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb b/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb
index a0d9086875..582dd360f0 100644
--- a/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb
+++ b/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb
@@ -14,10 +14,7 @@ module ActiveRecord
module ConnectionAdapters # :nodoc:
extend ActiveSupport::Autoload
- autoload_at 'active_record/connection_adapters/column' do
- autoload :Column
- autoload :NullColumn
- end
+ autoload :Column
autoload :ConnectionSpecification
autoload_at 'active_record/connection_adapters/abstract/schema_definitions' do
@@ -267,7 +264,7 @@ module ActiveRecord
# Returns a bind substitution value given a bind +index+ and +column+
# NOTE: The column param is currently being used by the sqlserver-adapter
- def substitute_at(column, index)
+ def substitute_at(column, index = 0)
Arel::Nodes::BindParam.new '?'
end
@@ -386,6 +383,10 @@ module ActiveRecord
type_map.lookup(sql_type)
end
+ def column_name_for_operation(operation, node) # :nodoc:
+ node.to_sql
+ end
+
protected
def initialize_type_map(m) # :nodoc:
diff --git a/activerecord/lib/active_record/connection_adapters/mysql_adapter.rb b/activerecord/lib/active_record/connection_adapters/mysql_adapter.rb
index cff6798eb3..3357ed52e5 100644
--- a/activerecord/lib/active_record/connection_adapters/mysql_adapter.rb
+++ b/activerecord/lib/active_record/connection_adapters/mysql_adapter.rb
@@ -88,7 +88,7 @@ module ActiveRecord
end
def clear
- cache.values.each do |hash|
+ cache.each_value do |hash|
hash[:stmt].close
end
cache.clear
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 89a7257d77..cf379ab210 100644
--- a/activerecord/lib/active_record/connection_adapters/postgresql/database_statements.rb
+++ b/activerecord/lib/active_record/connection_adapters/postgresql/database_statements.rb
@@ -156,7 +156,7 @@ module ActiveRecord
end
end
- def substitute_at(column, index)
+ def substitute_at(column, index = 0)
Arel::Nodes::BindParam.new "$#{index + 1}"
end
diff --git a/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb b/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb
index 8e209e1051..9941f74766 100644
--- a/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb
+++ b/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb
@@ -104,6 +104,7 @@ module ActiveRecord
macaddr: { name: "macaddr" },
uuid: { name: "uuid" },
json: { name: "json" },
+ jsonb: { name: "jsonb" },
ltree: { name: "ltree" },
citext: { name: "citext" },
point: { name: "point" },
@@ -393,6 +394,16 @@ module ActiveRecord
super(oid)
end
+ def column_name_for_operation(operation, node) # :nodoc:
+ OPERATION_ALIASES.fetch(operation) { operation.downcase }
+ end
+
+ OPERATION_ALIASES = { # :nodoc:
+ "maximum" => "max",
+ "minimum" => "min",
+ "average" => "avg",
+ }
+
protected
# Returns the version of the connected PostgreSQL server.
diff --git a/activerecord/lib/active_record/connection_adapters/sqlite3_adapter.rb b/activerecord/lib/active_record/connection_adapters/sqlite3_adapter.rb
index 4756896ac5..1b5e3bdbac 100644
--- a/activerecord/lib/active_record/connection_adapters/sqlite3_adapter.rb
+++ b/activerecord/lib/active_record/connection_adapters/sqlite3_adapter.rb
@@ -115,7 +115,7 @@ module ActiveRecord
end
def clear
- cache.values.each do |hash|
+ cache.each_value do |hash|
dealloc hash[:stmt]
end
cache.clear
diff --git a/activerecord/lib/active_record/fixtures.rb b/activerecord/lib/active_record/fixtures.rb
index 125a119b5f..db6421dacb 100644
--- a/activerecord/lib/active_record/fixtures.rb
+++ b/activerecord/lib/active_record/fixtures.rb
@@ -649,7 +649,7 @@ module ActiveRecord
model_class
end
- reflection_class._reflections.values.each do |association|
+ reflection_class._reflections.each_value do |association|
case association.macro
when :belongs_to
# Do not replace association name with association foreign key if they are named the same
diff --git a/activerecord/lib/active_record/railties/databases.rake b/activerecord/lib/active_record/railties/databases.rake
index 44765bd050..3ec25f9f17 100644
--- a/activerecord/lib/active_record/railties/databases.rake
+++ b/activerecord/lib/active_record/railties/databases.rake
@@ -196,7 +196,8 @@ db_namespace = namespace :db do
fixture_files = if ENV['FIXTURES']
ENV['FIXTURES'].split(',')
else
- Pathname.glob("#{fixtures_dir}/**/*.yml").map {|f| f.basename.sub_ext('').to_s }
+ # The use of String#[] here is to support namespaced fixtures
+ Dir["#{fixtures_dir}/**/*.yml"].map {|f| f[(fixtures_dir.size + 1)..-5] }
end
ActiveRecord::FixtureSet.create_fixtures(fixtures_dir, fixture_files)
diff --git a/activerecord/lib/active_record/relation.rb b/activerecord/lib/active_record/relation.rb
index 7f51e4134d..03bce4f5b7 100644
--- a/activerecord/lib/active_record/relation.rb
+++ b/activerecord/lib/active_record/relation.rb
@@ -79,22 +79,27 @@ module ActiveRecord
scope.unscope!(where: @klass.inheritance_column)
end
- um = scope.where(@klass.arel_table[@klass.primary_key].eq(id_was || id)).arel.compile_update(substitutes, @klass.primary_key)
+ relation = scope.where(@klass.primary_key => (id_was || id))
+ bvs = binds + relation.bind_values
+ um = relation
+ .arel
+ .compile_update(substitutes, @klass.primary_key)
+ reorder_bind_params(um.ast, bvs)
@klass.connection.update(
um,
'SQL',
- binds)
+ bvs,
+ )
end
def substitute_values(values) # :nodoc:
- substitutes = values.sort_by { |arel_attr,_| arel_attr.name }
- binds = substitutes.map do |arel_attr, value|
+ binds = values.map do |arel_attr, value|
[@klass.columns_hash[arel_attr.name], value]
end
- substitutes.each_with_index do |tuple, i|
- tuple[1] = @klass.connection.substitute_at(binds[i][0], i)
+ substitutes = values.each_with_index.map do |(arel_attr, _), i|
+ [arel_attr, @klass.connection.substitute_at(binds[i][0], i)]
end
[substitutes, binds]
@@ -337,7 +342,7 @@ module ActiveRecord
stmt.wheres = arel.constraints
end
- bvs = bind_values + arel.bind_values
+ bvs = arel.bind_values + bind_values
@klass.connection.update stmt, 'SQL', bvs
end
diff --git a/activerecord/lib/active_record/relation/calculations.rb b/activerecord/lib/active_record/relation/calculations.rb
index e20cc0e76d..c8ebb41131 100644
--- a/activerecord/lib/active_record/relation/calculations.rb
+++ b/activerecord/lib/active_record/relation/calculations.rb
@@ -253,7 +253,8 @@ module ActiveRecord
select_value = operation_over_aggregate_column(column, operation, distinct)
- column_alias = select_value.alias || select_value.to_sql
+ 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
diff --git a/activerecord/lib/active_record/relation/finder_methods.rb b/activerecord/lib/active_record/relation/finder_methods.rb
index 145b7378cf..eacae73ebb 100644
--- a/activerecord/lib/active_record/relation/finder_methods.rb
+++ b/activerecord/lib/active_record/relation/finder_methods.rb
@@ -82,12 +82,16 @@ module ActiveRecord
# Post.find_by "published_at < ?", 2.weeks.ago
def find_by(*args)
where(*args).take
+ rescue RangeError
+ nil
end
# Like <tt>find_by</tt>, except that if no record is found, raises
# an <tt>ActiveRecord::RecordNotFound</tt> error.
def find_by!(*args)
where(*args).take!
+ rescue RangeError
+ raise RecordNotFound, "Couldn't find #{@klass.name} with an out of range value"
end
# Gives a record (or N records if a parameter is supplied) without any implied
@@ -446,10 +450,7 @@ module ActiveRecord
MSG
end
- column = columns_hash[primary_key]
- substitute = connection.substitute_at(column, bind_values.length)
- relation = where(table[primary_key].eq(substitute))
- relation.bind_values += [[column, id]]
+ relation = where(primary_key => id)
record = relation.take
raise_record_not_found_exception!(id, 0, 1) unless record
@@ -458,7 +459,7 @@ module ActiveRecord
end
def find_some(ids)
- result = where(table[primary_key].in(ids)).to_a
+ result = where(primary_key => ids).to_a
expected_size =
if limit_value && ids.size > limit_value
diff --git a/activerecord/lib/active_record/relation/predicate_builder/relation_handler.rb b/activerecord/lib/active_record/relation/predicate_builder/relation_handler.rb
index 618fa3cdd9..063150958a 100644
--- a/activerecord/lib/active_record/relation/predicate_builder/relation_handler.rb
+++ b/activerecord/lib/active_record/relation/predicate_builder/relation_handler.rb
@@ -6,7 +6,7 @@ module ActiveRecord
value = value.select(value.klass.arel_table[value.klass.primary_key])
end
- attribute.in(value.arel.ast)
+ attribute.in(value.arel)
end
end
end
diff --git a/activerecord/lib/active_record/relation/query_methods.rb b/activerecord/lib/active_record/relation/query_methods.rb
index 2c3cfb7631..a686e3263b 100644
--- a/activerecord/lib/active_record/relation/query_methods.rb
+++ b/activerecord/lib/active_record/relation/query_methods.rb
@@ -439,7 +439,7 @@ module ActiveRecord
self
end
- def bind(value)
+ def bind(value) # :nodoc:
spawn.bind!(value)
end
@@ -883,12 +883,15 @@ module ActiveRecord
# Reorder bind indexes if joins produced bind values
bvs = arel.bind_values + bind_values
- arel.ast.grep(Arel::Nodes::BindParam).each_with_index do |bp, i|
+ reorder_bind_params(arel.ast, bvs)
+ arel
+ end
+
+ def reorder_bind_params(ast, bvs)
+ ast.grep(Arel::Nodes::BindParam).each_with_index do |bp, i|
column = bvs[i].first
bp.replace connection.substitute_at(column, i)
end
-
- arel
end
def symbol_unscoping(scope)
@@ -958,8 +961,7 @@ module ActiveRecord
when Hash
opts = PredicateBuilder.resolve_column_aliases(klass, opts)
- bv_len = bind_values.length
- tmp_opts, bind_values = create_binds(opts, bv_len)
+ tmp_opts, bind_values = create_binds(opts)
self.bind_values += bind_values
attributes = @klass.send(:expand_hash_conditions_for_aggregates, tmp_opts)
@@ -971,7 +973,7 @@ module ActiveRecord
end
end
- def create_binds(opts, idx)
+ def create_binds(opts)
bindable, non_binds = opts.partition do |column, value|
case value
when String, Integer, ActiveRecord::StatementCache::Substitute
@@ -981,12 +983,23 @@ module ActiveRecord
end
end
+ association_binds, non_binds = non_binds.partition do |column, value|
+ value.is_a?(Hash) && association_for_table(column)
+ end
+
new_opts = {}
binds = []
- bindable.each_with_index do |(column,value), index|
+ bindable.each do |(column,value)|
binds.push [@klass.columns_hash[column.to_s], value]
- new_opts[column] = connection.substitute_at(column, index + idx)
+ new_opts[column] = connection.substitute_at(column)
+ end
+
+ association_binds.each do |(column, value)|
+ association_relation = association_for_table(column).klass.send(:relation)
+ association_new_opts, association_bind = association_relation.send(:create_binds, value)
+ new_opts[column] = association_new_opts
+ binds += association_bind
end
non_binds.each { |column,value| new_opts[column] = value }
@@ -994,6 +1007,12 @@ module ActiveRecord
[new_opts, binds]
end
+ def association_for_table(table_name)
+ table_name = table_name.to_s
+ @klass._reflect_on_association(table_name) ||
+ @klass._reflect_on_association(table_name.singularize)
+ end
+
def build_from
opts, name = from_value
case opts
diff --git a/activerecord/lib/active_record/sanitization.rb b/activerecord/lib/active_record/sanitization.rb
index ff70cbed0f..6a130c145b 100644
--- a/activerecord/lib/active_record/sanitization.rb
+++ b/activerecord/lib/active_record/sanitization.rb
@@ -87,6 +87,9 @@ module ActiveRecord
# { address: Address.new("123 abc st.", "chicago") }
# # => "address_street='123 abc st.' and address_city='chicago'"
def sanitize_sql_hash_for_conditions(attrs, default_table_name = self.table_name)
+ ActiveSupport::Deprecation.warn(<<-EOWARN)
+sanitize_sql_hash_for_conditions is deprecated, and will be removed in Rails 5.0
+ EOWARN
attrs = PredicateBuilder.resolve_column_aliases self, attrs
attrs = expand_hash_conditions_for_aggregates(attrs)
@@ -134,7 +137,7 @@ module ActiveRecord
raise_if_bind_arity_mismatch(statement, statement.count('?'), values.size)
bound = values.dup
c = connection
- statement.gsub('?') do
+ statement.gsub(/\?/) do
replace_bind_variable(bound.shift, c)
end
end