aboutsummaryrefslogtreecommitdiffstats
path: root/activerecord
diff options
context:
space:
mode:
Diffstat (limited to 'activerecord')
-rw-r--r--activerecord/CHANGELOG.md8
-rw-r--r--activerecord/lib/active_record/associations/collection_association.rb2
-rw-r--r--activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb2
-rw-r--r--activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb4
-rw-r--r--activerecord/lib/active_record/connection_adapters/connection_specification.rb2
-rw-r--r--activerecord/lib/active_record/connection_adapters/postgresql/schema_statements.rb4
-rw-r--r--activerecord/lib/active_record/database_configurations.rb54
-rw-r--r--activerecord/lib/active_record/enum.rb9
-rw-r--r--activerecord/lib/active_record/relation/query_methods.rb12
-rw-r--r--activerecord/lib/active_record/tasks/database_tasks.rb2
-rw-r--r--activerecord/lib/active_record/tasks/mysql_database_tasks.rb2
-rw-r--r--activerecord/test/cases/adapters/postgresql/postgresql_adapter_test.rb6
-rw-r--r--activerecord/test/cases/connection_adapters/merge_and_resolve_default_url_config_test.rb16
-rw-r--r--activerecord/test/cases/database_configurations_test.rb13
-rw-r--r--activerecord/test/cases/enum_test.rb22
-rw-r--r--activerecord/test/cases/tasks/mysql_rake_test.rb11
16 files changed, 124 insertions, 45 deletions
diff --git a/activerecord/CHANGELOG.md b/activerecord/CHANGELOG.md
index 727ddd6bb7..2af48f99db 100644
--- a/activerecord/CHANGELOG.md
+++ b/activerecord/CHANGELOG.md
@@ -1,3 +1,11 @@
+* Add a warning for enum elements with 'not_' prefix.
+
+ class Foo
+ enum status: [:sent, :not_sent]
+ end
+
+ *Edu Depetris*
+
* Make currency symbols optional for money column type in PostgreSQL
*Joel Schneider*
diff --git a/activerecord/lib/active_record/associations/collection_association.rb b/activerecord/lib/active_record/associations/collection_association.rb
index c3d4eab562..891b50d160 100644
--- a/activerecord/lib/active_record/associations/collection_association.rb
+++ b/activerecord/lib/active_record/associations/collection_association.rb
@@ -56,7 +56,7 @@ module ActiveRecord
def ids_writer(ids)
primary_key = reflection.association_primary_key
pk_type = klass.type_for_attribute(primary_key)
- ids = Array(ids).reject(&:blank?)
+ ids = Array(ids).compact_blank
ids.map! { |i| pk_type.cast(i) }
records = klass.where(primary_key => ids).index_by do |r|
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 13f94a4722..88367c79a1 100644
--- a/activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb
+++ b/activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb
@@ -100,7 +100,7 @@ module ActiveRecord
def index_exists?(table_name, column_name, options = {})
column_names = Array(column_name).map(&:to_s)
checks = []
- checks << lambda { |i| i.columns == column_names }
+ checks << lambda { |i| Array(i.columns) == column_names }
checks << lambda { |i| i.unique } if options[:unique]
checks << lambda { |i| i.name == options[:name].to_s } if options[:name]
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 405fecb603..ef1eef6b69 100644
--- a/activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb
+++ b/activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb
@@ -476,12 +476,12 @@ module ActiveRecord
# distinct queries, and requires that the ORDER BY include the distinct column.
# See https://dev.mysql.com/doc/refman/5.7/en/group-by-handling.html
def columns_for_distinct(columns, orders) # :nodoc:
- order_columns = orders.reject(&:blank?).map { |s|
+ order_columns = orders.compact_blank.map { |s|
# Convert Arel node to string
s = s.to_sql unless s.is_a?(String)
# Remove any ASC/DESC modifiers
s.gsub(/\s+(?:ASC|DESC)\b/i, "")
- }.reject(&:blank?).map.with_index { |column, i| "#{column} AS alias_#{i}" }
+ }.compact_blank.map.with_index { |column, i| "#{column} AS alias_#{i}" }
(order_columns << super).join(", ")
end
diff --git a/activerecord/lib/active_record/connection_adapters/connection_specification.rb b/activerecord/lib/active_record/connection_adapters/connection_specification.rb
index df26f67c6e..0732b69f81 100644
--- a/activerecord/lib/active_record/connection_adapters/connection_specification.rb
+++ b/activerecord/lib/active_record/connection_adapters/connection_specification.rb
@@ -50,7 +50,7 @@ module ActiveRecord
# Converts the given URL to a full connection hash.
def to_hash
- config = raw_config.reject { |_, value| value.blank? }
+ config = raw_config.compact_blank
config.map { |key, value| config[key] = uri_parser.unescape(value) if value.is_a? String }
config
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 0062952667..628a609521 100644
--- a/activerecord/lib/active_record/connection_adapters/postgresql/schema_statements.rb
+++ b/activerecord/lib/active_record/connection_adapters/postgresql/schema_statements.rb
@@ -555,13 +555,13 @@ module ActiveRecord
# PostgreSQL requires the ORDER BY columns in the select list for distinct queries, and
# requires that the ORDER BY include the distinct column.
def columns_for_distinct(columns, orders) #:nodoc:
- order_columns = orders.reject(&:blank?).map { |s|
+ order_columns = orders.compact_blank.map { |s|
# Convert Arel node to string
s = s.to_sql unless s.is_a?(String)
# Remove any ASC/DESC modifiers
s.gsub(/\s+(?:ASC|DESC)\b/i, "")
.gsub(/\s+NULLS\s+(?:FIRST|LAST)\b/i, "")
- }.reject(&:blank?).map.with_index { |column, i| "#{column} AS alias_#{i}" }
+ }.compact_blank.map.with_index { |column, i| "#{column} AS alias_#{i}" }
(order_columns << super).join(", ")
end
diff --git a/activerecord/lib/active_record/database_configurations.rb b/activerecord/lib/active_record/database_configurations.rb
index e122628b05..3e387782f6 100644
--- a/activerecord/lib/active_record/database_configurations.rb
+++ b/activerecord/lib/active_record/database_configurations.rb
@@ -91,6 +91,19 @@ module ActiveRecord
end
alias :blank? :empty?
+ def each
+ throw_getter_deprecation(:each)
+ configurations.each { |config|
+ yield [config.env_name, config.config]
+ }
+ end
+
+ def first
+ throw_getter_deprecation(:first)
+ config = configurations.first
+ [config.env_name, config.config]
+ end
+
private
def env_with_configs(env = nil)
if env
@@ -105,18 +118,20 @@ module ActiveRecord
return configs if configs.is_a?(Array)
db_configs = configs.flat_map do |env_name, config|
- if config.is_a?(Hash) && config.all? { |k, v| v.is_a?(Hash) }
+ if config.is_a?(Hash) && config.all? { |_, v| v.is_a?(Hash) }
walk_configs(env_name.to_s, config)
else
build_db_config_from_raw_config(env_name.to_s, "primary", config)
end
- end.compact
+ end
- if url = ENV["DATABASE_URL"]
- merge_url_with_configs(url, db_configs)
- else
- db_configs
+ current_env = ActiveRecord::ConnectionHandling::DEFAULT_ENV.call.to_s
+
+ unless db_configs.find(&:for_current_env?)
+ db_configs << environment_url_config(current_env, "primary", {})
end
+
+ merge_db_environment_variables(current_env, db_configs.compact)
end
def walk_configs(env_name, config)
@@ -156,27 +171,24 @@ module ActiveRecord
end
end
- def merge_url_with_configs(url, configs)
- env = ActiveRecord::ConnectionHandling::DEFAULT_ENV.call.to_s
+ def merge_db_environment_variables(current_env, configs)
+ configs.map do |config|
+ next config if config.url_config? || config.env_name != current_env
- if configs.find(&:for_current_env?)
- configs.map do |config|
- if config.url_config?
- config
- else
- ActiveRecord::DatabaseConfigurations::UrlConfig.new(config.env_name, config.spec_name, url, config.config)
- end
- end
- else
- configs + [ActiveRecord::DatabaseConfigurations::UrlConfig.new(env, "primary", url)]
+ url_config = environment_url_config(current_env, config.spec_name, config.config)
+ url_config || config
end
end
+ def environment_url_config(env, spec_name, config)
+ url = ENV["DATABASE_URL"]
+ return unless url
+
+ ActiveRecord::DatabaseConfigurations::UrlConfig.new(env, spec_name, url, config)
+ end
+
def method_missing(method, *args, &blk)
case method
- when :each, :first
- throw_getter_deprecation(method)
- configurations.send(method, *args, &blk)
when :fetch
throw_getter_deprecation(method)
configs_for(env_name: args.first)
diff --git a/activerecord/lib/active_record/enum.rb b/activerecord/lib/active_record/enum.rb
index 8077630aeb..fc49f752aa 100644
--- a/activerecord/lib/active_record/enum.rb
+++ b/activerecord/lib/active_record/enum.rb
@@ -200,6 +200,8 @@ module ActiveRecord
# scope :active, -> { where(status: 0) }
# scope :not_active, -> { where.not(status: 0) }
if enum_scopes != false
+ klass.send(:detect_negative_condition!, value_method_name)
+
klass.send(:detect_enum_conflict!, name, value_method_name, true)
klass.scope value_method_name, -> { where(attr => value) }
@@ -261,5 +263,12 @@ module ActiveRecord
source: source
}
end
+
+ def detect_negative_condition!(method_name)
+ if method_name.start_with?("not_") && logger
+ logger.warn "An enum element in #{self.name} uses the prefix 'not_'." \
+ " This will cause a conflict with auto generated negative scopes."
+ 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 6a181882ae..6957ba052b 100644
--- a/activerecord/lib/active_record/relation/query_methods.rb
+++ b/activerecord/lib/active_record/relation/query_methods.rb
@@ -138,7 +138,7 @@ module ActiveRecord
end
def includes!(*args) # :nodoc:
- args.reject!(&:blank?)
+ args.compact_blank!
args.flatten!
self.includes_values |= args
@@ -265,7 +265,7 @@ module ActiveRecord
end
def _select!(*fields) # :nodoc:
- fields.reject!(&:blank?)
+ fields.compact_blank!
fields.flatten!
self.select_values += fields
self
@@ -965,7 +965,7 @@ module ActiveRecord
def reverse_order! # :nodoc:
orders = order_values.uniq
- orders.reject!(&:blank?)
+ orders.compact_blank!
self.order_values = reverse_sql_order(orders)
self
end
@@ -1053,7 +1053,7 @@ module ActiveRecord
)
arel.skip(Arel::Nodes::BindParam.new(offset_attribute))
end
- arel.group(*arel_columns(group_values.uniq.reject(&:blank?))) unless group_values.empty?
+ arel.group(*arel_columns(group_values.uniq.compact_blank)) unless group_values.empty?
build_order(arel)
@@ -1129,7 +1129,7 @@ module ActiveRecord
association_joins = buckets[:association_join]
stashed_joins = buckets[:stashed_join]
join_nodes = buckets[:join_node].tap(&:uniq!)
- string_joins = buckets[:string_join].delete_if(&:blank?).map!(&:strip).tap(&:uniq!)
+ string_joins = buckets[:string_join].compact_blank!.map!(&:strip).tap(&:uniq!)
string_joins.map! { |join| table.create_string_join(Arel.sql(join)) }
@@ -1227,7 +1227,7 @@ module ActiveRecord
def build_order(arel)
orders = order_values.uniq
- orders.reject!(&:blank?)
+ orders.compact_blank!
arel.order(*orders) unless orders.empty?
end
diff --git a/activerecord/lib/active_record/tasks/database_tasks.rb b/activerecord/lib/active_record/tasks/database_tasks.rb
index a78bebf764..5d1ce19829 100644
--- a/activerecord/lib/active_record/tasks/database_tasks.rb
+++ b/activerecord/lib/active_record/tasks/database_tasks.rb
@@ -154,6 +154,8 @@ module ActiveRecord
end
def for_each(databases)
+ return {} unless defined?(Rails)
+
database_configs = ActiveRecord::DatabaseConfigurations.new(databases).configs_for(env_name: Rails.env)
# if this is a single database application we don't want tasks for each primary database
diff --git a/activerecord/lib/active_record/tasks/mysql_database_tasks.rb b/activerecord/lib/active_record/tasks/mysql_database_tasks.rb
index a7e04007a9..e3efeb75b5 100644
--- a/activerecord/lib/active_record/tasks/mysql_database_tasks.rb
+++ b/activerecord/lib/active_record/tasks/mysql_database_tasks.rb
@@ -16,7 +16,7 @@ module ActiveRecord
connection.create_database configuration["database"], creation_options
establish_connection configuration
rescue ActiveRecord::StatementInvalid => error
- if error.cause.error_number == ER_DB_CREATE_EXISTS
+ if connection.error_number(error.cause) == ER_DB_CREATE_EXISTS
raise DatabaseAlreadyExists
else
raise
diff --git a/activerecord/test/cases/adapters/postgresql/postgresql_adapter_test.rb b/activerecord/test/cases/adapters/postgresql/postgresql_adapter_test.rb
index d99593817a..830c0892d3 100644
--- a/activerecord/test/cases/adapters/postgresql/postgresql_adapter_test.rb
+++ b/activerecord/test/cases/adapters/postgresql/postgresql_adapter_test.rb
@@ -253,9 +253,11 @@ module ActiveRecord
def test_expression_index
with_example_table do
- @connection.add_index "ex", "mod(id, 10), abs(number)", name: "expression"
+ expr = "mod(id, 10), abs(number)"
+ @connection.add_index "ex", expr, name: "expression"
index = @connection.indexes("ex").find { |idx| idx.name == "expression" }
- assert_equal "mod(id, 10), abs(number)", index.columns
+ assert_equal expr, index.columns
+ assert_equal true, @connection.index_exists?("ex", expr, name: "expression")
end
end
diff --git a/activerecord/test/cases/connection_adapters/merge_and_resolve_default_url_config_test.rb b/activerecord/test/cases/connection_adapters/merge_and_resolve_default_url_config_test.rb
index 15a045ed23..95e57f42e3 100644
--- a/activerecord/test/cases/connection_adapters/merge_and_resolve_default_url_config_test.rb
+++ b/activerecord/test/cases/connection_adapters/merge_and_resolve_default_url_config_test.rb
@@ -347,6 +347,22 @@ module ActiveRecord
assert_equal expected, actual
end
end
+
+ def test_does_not_change_other_environments
+ ENV["DATABASE_URL"] = "postgres://localhost/foo"
+ config = { "production" => { "adapter" => "not_postgres", "database" => "not_foo", "host" => "localhost" }, "default_env" => {} }
+
+ actual = resolve_spec(:production, config)
+ assert_equal config["production"].merge("name" => "production"), actual
+
+ actual = resolve_spec(:default_env, config)
+ assert_equal({
+ "host" => "localhost",
+ "database" => "foo",
+ "adapter" => "postgresql",
+ "name" => "default_env"
+ }, actual)
+ end
end
end
end
diff --git a/activerecord/test/cases/database_configurations_test.rb b/activerecord/test/cases/database_configurations_test.rb
index ed8151f01a..725d1b5d1b 100644
--- a/activerecord/test/cases/database_configurations_test.rb
+++ b/activerecord/test/cases/database_configurations_test.rb
@@ -80,17 +80,20 @@ class LegacyDatabaseConfigurationsTest < ActiveRecord::TestCase
def test_each_is_deprecated
assert_deprecated do
- ActiveRecord::Base.configurations.each do |db_config|
- assert_equal "primary", db_config.spec_name
+ all_configs = ActiveRecord::Base.configurations.values
+ ActiveRecord::Base.configurations.each do |env_name, config|
+ assert_includes ["arunit", "arunit2", "arunit_without_prepared_statements"], env_name
+ assert_includes all_configs, config
end
end
end
def test_first_is_deprecated
+ first_config = ActiveRecord::Base.configurations.values.first
assert_deprecated do
- db_config = ActiveRecord::Base.configurations.first
- assert_equal "arunit", db_config.env_name
- assert_equal "primary", db_config.spec_name
+ env_name, config = ActiveRecord::Base.configurations.first
+ assert_equal "arunit", env_name
+ assert_equal first_config, config
end
end
diff --git a/activerecord/test/cases/enum_test.rb b/activerecord/test/cases/enum_test.rb
index ae0ce195b3..8673a99c45 100644
--- a/activerecord/test/cases/enum_test.rb
+++ b/activerecord/test/cases/enum_test.rb
@@ -3,6 +3,7 @@
require "cases/helper"
require "models/author"
require "models/book"
+require "active_support/log_subscriber/test_helper"
class EnumTest < ActiveRecord::TestCase
fixtures :books, :authors, :author_addresses
@@ -565,4 +566,25 @@ class EnumTest < ActiveRecord::TestCase
assert_raises(NoMethodError) { klass.proposed }
end
+
+ test "enums with a negative condition log a warning" do
+ old_logger = ActiveRecord::Base.logger
+ logger = ActiveSupport::LogSubscriber::TestHelper::MockLogger.new
+
+ ActiveRecord::Base.logger = logger
+
+ expected_message = "An enum element in Book uses the prefix 'not_'."\
+ " This will cause a conflict with auto generated negative scopes."
+
+ Class.new(ActiveRecord::Base) do
+ def self.name
+ "Book"
+ end
+ enum status: [:sent, :not_sent]
+ end
+
+ assert_match(expected_message, logger.logged(:warn).first)
+ ensure
+ ActiveRecord::Base.logger = old_logger
+ end
end
diff --git a/activerecord/test/cases/tasks/mysql_rake_test.rb b/activerecord/test/cases/tasks/mysql_rake_test.rb
index 258132835f..ac3c5bc26e 100644
--- a/activerecord/test/cases/tasks/mysql_rake_test.rb
+++ b/activerecord/test/cases/tasks/mysql_rake_test.rb
@@ -7,7 +7,10 @@ if current_adapter?(:Mysql2Adapter)
module ActiveRecord
class MysqlDBCreateTest < ActiveRecord::TestCase
def setup
- @connection = Class.new { def create_database(*); end }.new
+ @connection = Class.new do
+ def create_database(*); end
+ def error_number(_); end
+ end.new
@configuration = {
"adapter" => "mysql2",
"database" => "my-app-db"
@@ -90,9 +93,11 @@ if current_adapter?(:Mysql2Adapter)
with_stubbed_connection_establish_connection do
ActiveRecord::Base.connection.stub(
:create_database,
- proc { raise ActiveRecord::Tasks::DatabaseAlreadyExists }
+ proc { raise ActiveRecord::StatementInvalid }
) do
- ActiveRecord::Tasks::DatabaseTasks.create @configuration
+ ActiveRecord::Base.connection.stub(:error_number, 1007) do
+ ActiveRecord::Tasks::DatabaseTasks.create @configuration
+ end
assert_equal "Database 'my-app-db' already exists\n", $stderr.string
end