aboutsummaryrefslogtreecommitdiffstats
path: root/activerecord
diff options
context:
space:
mode:
Diffstat (limited to 'activerecord')
-rw-r--r--activerecord/CHANGELOG.md40
-rw-r--r--activerecord/lib/active_record/associations/collection_association.rb12
-rw-r--r--activerecord/lib/active_record/attribute_methods.rb12
-rw-r--r--activerecord/lib/active_record/connection_adapters/abstract/connection_pool.rb2
-rw-r--r--activerecord/lib/active_record/connection_adapters/abstract_adapter.rb5
-rw-r--r--activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb3
-rw-r--r--activerecord/lib/active_record/connection_adapters/mysql2_adapter.rb3
-rw-r--r--activerecord/lib/active_record/connection_adapters/mysql_adapter.rb1
-rw-r--r--activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb4
-rw-r--r--activerecord/lib/active_record/connection_adapters/sqlite3_adapter.rb3
-rw-r--r--activerecord/lib/active_record/inheritance.rb20
-rw-r--r--activerecord/lib/active_record/persistence.rb1
-rw-r--r--activerecord/lib/active_record/relation.rb5
-rw-r--r--activerecord/lib/active_record/relation/delegation.rb2
-rw-r--r--activerecord/lib/active_record/tasks/postgresql_database_tasks.rb4
-rw-r--r--activerecord/test/cases/adapters/postgresql/geometric_test.rb4
-rw-r--r--activerecord/test/cases/associations/has_many_associations_test.rb6
-rw-r--r--activerecord/test/cases/base_test.rb13
-rw-r--r--activerecord/test/cases/finder_test.rb91
-rw-r--r--activerecord/test/cases/inheritance_test.rb45
-rw-r--r--activerecord/test/cases/relation/delegation_test.rb2
-rw-r--r--activerecord/test/cases/sanitize_test.rb94
-rw-r--r--activerecord/test/cases/tasks/postgresql_rake_test.rb4
-rw-r--r--activerecord/test/models/bulb.rb6
-rw-r--r--activerecord/test/schema/schema.rb2
25 files changed, 248 insertions, 136 deletions
diff --git a/activerecord/CHANGELOG.md b/activerecord/CHANGELOG.md
index 3724b1a387..fdc95f718a 100644
--- a/activerecord/CHANGELOG.md
+++ b/activerecord/CHANGELOG.md
@@ -1,3 +1,22 @@
+* Respect the column default values for `inheritance_column` when
+ instantiating records through the base class.
+
+ Fixes #17121.
+
+ Example:
+
+ # The schema of BaseModel has `t.string :type, default: 'SubType'`
+ subtype = BaseModel.new
+ assert_equals SubType, subtype.class
+
+ *Kuldeep Aggarwal*
+
+* Fix `rake db:structure:dump` on Postgres when multiple schemas are used.
+
+ Fixes #22346.
+
+ *Nick Muerdter*, *ckoenig*
+
* Add schema dumping support for PostgreSQL geometric data types.
*Ryuta Kamizono*
@@ -211,9 +230,9 @@
Example:
- config.generators do |g|
- g.orm :active_record, primary_key_type: :uuid
- end
+ config.generators do |g|
+ g.orm :active_record, primary_key_type: :uuid
+ end
*Jon McCartie*
@@ -289,10 +308,10 @@
To load the fixtures file `accounts.yml` as the `User` model, use:
- _fixture:
- model_class: User
- david:
- name: David
+ _fixture:
+ model_class: User
+ david:
+ name: David
Fixes #9516.
@@ -413,6 +432,13 @@
*Wojciech Wnętrzak*
+* Instantiating an AR model with `ActionController::Parameters` now raises
+ an `ActiveModel::ForbiddenAttributesError` if the parameters include a
+ `type` field that has not been explicitly permitted. Previously, the
+ `type` field was simply ignored in the same situation.
+
+ *Prem Sichanugrist*
+
* PostgreSQL, `create_schema`, `drop_schema` and `rename_table` now quote
schema names.
diff --git a/activerecord/lib/active_record/associations/collection_association.rb b/activerecord/lib/active_record/associations/collection_association.rb
index f32dddb8f0..473b80a658 100644
--- a/activerecord/lib/active_record/associations/collection_association.rb
+++ b/activerecord/lib/active_record/associations/collection_association.rb
@@ -414,12 +414,16 @@ module ActiveRecord
def replace_on_target(record, index, skip_callbacks)
callback(:before_add, record) unless skip_callbacks
+
+ was_loaded = loaded?
yield(record) if block_given?
- if index
- @target[index] = record
- else
- @target << record
+ unless !was_loaded && loaded?
+ if index
+ @target[index] = record
+ else
+ @target << record
+ end
end
callback(:after_add, record) unless skip_callbacks
diff --git a/activerecord/lib/active_record/attribute_methods.rb b/activerecord/lib/active_record/attribute_methods.rb
index 4ae585d3f5..423a93964e 100644
--- a/activerecord/lib/active_record/attribute_methods.rb
+++ b/activerecord/lib/active_record/attribute_methods.rb
@@ -191,6 +191,18 @@ module ActiveRecord
end
end
+ # Returns true if the given attribute exists, otherwise false.
+ #
+ # class Person < ActiveRecord::Base
+ # end
+ #
+ # Person.has_attribute?('name') # => true
+ # Person.has_attribute?(:age) # => true
+ # Person.has_attribute?(:nothing) # => false
+ def has_attribute?(attr_name)
+ attribute_types.key?(attr_name.to_s)
+ end
+
# Returns the column object for the named attribute.
# Returns a +ActiveRecord::ConnectionAdapters::NullColumn+ if the
# named attribute does not exist.
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 486b7b6d25..ccd2899489 100644
--- a/activerecord/lib/active_record/connection_adapters/abstract/connection_pool.rb
+++ b/activerecord/lib/active_record/connection_adapters/abstract/connection_pool.rb
@@ -197,7 +197,7 @@ module ActiveRecord
elapsed = Time.now - t0
if elapsed >= timeout
- msg = 'could not obtain a database connection within %0.3f seconds (waited %0.3f seconds)' %
+ 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
diff --git a/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb b/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb
index 4d4dc07b04..4b6912c616 100644
--- a/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb
+++ b/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb
@@ -95,14 +95,15 @@ module ActiveRecord
attr_reader :prepared_statements
- def initialize(connection, logger = nil, pool = nil) #:nodoc:
+ def initialize(connection, logger = nil, config = {}) # :nodoc:
super()
@connection = connection
@owner = nil
@instrumenter = ActiveSupport::Notifications.instrumenter
@logger = logger
- @pool = pool
+ @config = config
+ @pool = nil
@schema_cache = SchemaCache.new self
@visitor = nil
@prepared_statements = false
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 735bc0e67a..25ba42e5c9 100644
--- a/activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb
+++ b/activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb
@@ -143,8 +143,7 @@ module ActiveRecord
# FIXME: Make the first parameter more similar for the two adapters
def initialize(connection, logger, connection_options, config)
- super(connection, logger)
- @connection_options, @config = connection_options, config
+ super(connection, logger, config)
@quoted_column_names, @quoted_table_names = {}, {}
@visitor = Arel::Visitors::MySQL.new self
diff --git a/activerecord/lib/active_record/connection_adapters/mysql2_adapter.rb b/activerecord/lib/active_record/connection_adapters/mysql2_adapter.rb
index 3944698910..7ca597859d 100644
--- a/activerecord/lib/active_record/connection_adapters/mysql2_adapter.rb
+++ b/activerecord/lib/active_record/connection_adapters/mysql2_adapter.rb
@@ -16,8 +16,7 @@ module ActiveRecord
end
client = Mysql2::Client.new(config)
- options = [config[:host], config[:username], config[:password], config[:database], config[:port], config[:socket], 0]
- ConnectionAdapters::Mysql2Adapter.new(client, logger, options, config)
+ ConnectionAdapters::Mysql2Adapter.new(client, logger, nil, config)
rescue Mysql2::Error => error
if error.message.include?("Unknown database")
raise ActiveRecord::NoDatabaseError
diff --git a/activerecord/lib/active_record/connection_adapters/mysql_adapter.rb b/activerecord/lib/active_record/connection_adapters/mysql_adapter.rb
index f2d7b54105..76f1b91e6b 100644
--- a/activerecord/lib/active_record/connection_adapters/mysql_adapter.rb
+++ b/activerecord/lib/active_record/connection_adapters/mysql_adapter.rb
@@ -82,6 +82,7 @@ module ActiveRecord
super
@statements = StatementPool.new(self.class.type_cast_config_to_integer(config.fetch(:statement_limit) { 1000 }))
@client_encoding = nil
+ @connection_options = connection_options
connect
end
diff --git a/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb b/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb
index f731da9e18..aa43854d01 100644
--- a/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb
+++ b/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb
@@ -192,7 +192,7 @@ module ActiveRecord
# Initializes and connects a PostgreSQL adapter.
def initialize(connection, logger, connection_parameters, config)
- super(connection, logger)
+ super(connection, logger, config)
@visitor = Arel::Visitors::PostgreSQL.new self
if self.class.type_cast_config_to_boolean(config.fetch(:prepared_statements) { true })
@@ -202,7 +202,7 @@ module ActiveRecord
@prepared_statements = false
end
- @connection_parameters, @config = connection_parameters, config
+ @connection_parameters = connection_parameters
# @local_tz is initialized as nil to avoid warnings when connect tries to use it
@local_tz = nil
diff --git a/activerecord/lib/active_record/connection_adapters/sqlite3_adapter.rb b/activerecord/lib/active_record/connection_adapters/sqlite3_adapter.rb
index 90df9b8825..72ca909b02 100644
--- a/activerecord/lib/active_record/connection_adapters/sqlite3_adapter.rb
+++ b/activerecord/lib/active_record/connection_adapters/sqlite3_adapter.rb
@@ -78,11 +78,10 @@ module ActiveRecord
end
def initialize(connection, logger, connection_options, config)
- super(connection, logger)
+ super(connection, logger, config)
@active = nil
@statements = StatementPool.new(self.class.type_cast_config_to_integer(config.fetch(:statement_limit) { 1000 }))
- @config = config
@visitor = Arel::Visitors::SQLite.new self
@quoted_column_names = {}
diff --git a/activerecord/lib/active_record/inheritance.rb b/activerecord/lib/active_record/inheritance.rb
index 8b719e0bcb..6259c4cd33 100644
--- a/activerecord/lib/active_record/inheritance.rb
+++ b/activerecord/lib/active_record/inheritance.rb
@@ -51,8 +51,8 @@ module ActiveRecord
end
attrs = args.first
- if subclass_from_attributes?(attrs)
- subclass = subclass_from_attributes(attrs)
+ if has_attribute?(inheritance_column)
+ subclass = subclass_from_attributes(attrs) || subclass_from_attributes(column_defaults)
end
if subclass && subclass != self
@@ -163,7 +163,7 @@ module ActiveRecord
end
def using_single_table_inheritance?(record)
- record[inheritance_column].present? && columns_hash.include?(inheritance_column)
+ record[inheritance_column].present? && has_attribute?(inheritance_column)
end
def find_sti_class(type_name)
@@ -195,18 +195,14 @@ module ActiveRecord
# Detect the subclass from the inheritance column of attrs. If the inheritance column value
# is not self or a valid subclass, raises ActiveRecord::SubclassNotFound
- # If this is a StrongParameters hash, and access to inheritance_column is not permitted,
- # this will ignore the inheritance column and return nil
- def subclass_from_attributes?(attrs)
- attribute_names.include?(inheritance_column) && (attrs.is_a?(Hash) || attrs.respond_to?(:permitted?))
- end
-
def subclass_from_attributes(attrs)
attrs = attrs.to_h if attrs.respond_to?(:permitted?)
- subclass_name = attrs.with_indifferent_access[inheritance_column]
+ if attrs.is_a?(Hash)
+ subclass_name = attrs.with_indifferent_access[inheritance_column]
- if subclass_name.present?
- find_sti_class(subclass_name)
+ if subclass_name.present?
+ find_sti_class(subclass_name)
+ end
end
end
end
diff --git a/activerecord/lib/active_record/persistence.rb b/activerecord/lib/active_record/persistence.rb
index 46c6d8c293..1cb177483a 100644
--- a/activerecord/lib/active_record/persistence.rb
+++ b/activerecord/lib/active_record/persistence.rb
@@ -298,6 +298,7 @@ module ActiveRecord
# * \Validations are skipped.
# * \Callbacks are skipped.
# * +updated_at+/+updated_on+ are not updated.
+ # * However, attributes are serialized with the same rules as ActiveRecord::Relation#update_all
#
# This method raises an ActiveRecord::ActiveRecordError when called on new
# objects, or when at least one of the attributes is marked as readonly.
diff --git a/activerecord/lib/active_record/relation.rb b/activerecord/lib/active_record/relation.rb
index f100476374..2cf19c76c5 100644
--- a/activerecord/lib/active_record/relation.rb
+++ b/activerecord/lib/active_record/relation.rb
@@ -347,9 +347,8 @@ module ActiveRecord
# Updates all records in the current relation with details given. This method constructs a single SQL UPDATE
# statement and sends it straight to the database. It does not instantiate the involved models and it does not
- # trigger Active Record callbacks or validations. Values passed to #update_all will not go through
- # Active Record's type-casting behavior. It should receive only values that can be passed as-is to the SQL
- # database.
+ # trigger Active Record callbacks or validations. However, values passed to #update_all will still go through
+ # Active Record's normal type casting and serialization.
#
# ==== Parameters
#
diff --git a/activerecord/lib/active_record/relation/delegation.rb b/activerecord/lib/active_record/relation/delegation.rb
index b1333f110c..e4e5d63006 100644
--- a/activerecord/lib/active_record/relation/delegation.rb
+++ b/activerecord/lib/active_record/relation/delegation.rb
@@ -37,7 +37,7 @@ module ActiveRecord
# for each different klass, and the delegations are compiled into that subclass only.
delegate :to_xml, :to_yaml, :length, :collect, :map, :each, :all?, :include?, :to_ary, :join,
- :[], :&, :|, :+, :-, :sample, :reverse, :compact, to: :to_a
+ :[], :&, :|, :+, :-, :sample, :shuffle, :reverse, :compact, to: :to_a
delegate :table_name, :quoted_table_name, :primary_key, :quoted_primary_key,
:connection, :columns_hash, :to => :klass
diff --git a/activerecord/lib/active_record/tasks/postgresql_database_tasks.rb b/activerecord/lib/active_record/tasks/postgresql_database_tasks.rb
index cd7d949239..8b4874044c 100644
--- a/activerecord/lib/active_record/tasks/postgresql_database_tasks.rb
+++ b/activerecord/lib/active_record/tasks/postgresql_database_tasks.rb
@@ -56,9 +56,9 @@ module ActiveRecord
args = ['-s', '-x', '-O', '-f', filename]
unless search_path.blank?
- args << search_path.split(',').map do |part|
+ args += search_path.split(',').map do |part|
"--schema=#{part.strip}"
- end.join(' ')
+ end
end
args << configuration['database']
run_cmd('pg_dump', args, 'dumping')
diff --git a/activerecord/test/cases/adapters/postgresql/geometric_test.rb b/activerecord/test/cases/adapters/postgresql/geometric_test.rb
index 8d0c5bf23f..3b97cb4ad4 100644
--- a/activerecord/test/cases/adapters/postgresql/geometric_test.rb
+++ b/activerecord/test/cases/adapters/postgresql/geometric_test.rb
@@ -262,7 +262,9 @@ class PostgreSQLGeometricLineTest < ActiveRecord::PostgreSQLTestCase
end
teardown do
- @connection.drop_table 'postgresql_lines', if_exists: true
+ if defined?(@connection)
+ @connection.drop_table 'postgresql_lines', if_exists: true
+ end
end
def test_geometric_line_type
diff --git a/activerecord/test/cases/associations/has_many_associations_test.rb b/activerecord/test/cases/associations/has_many_associations_test.rb
index 50ca6537cc..ad157582a4 100644
--- a/activerecord/test/cases/associations/has_many_associations_test.rb
+++ b/activerecord/test/cases/associations/has_many_associations_test.rb
@@ -2348,6 +2348,12 @@ class HasManyAssociationsTest < ActiveRecord::TestCase
assert_equal [first_bulb, second_bulb], car.bulbs
end
+ test 'double insertion of new object to association when same association used in the after create callback of a new object' do
+ car = Car.create!
+ car.bulbs << TrickyBulb.new
+ assert_equal 1, car.bulbs.size
+ end
+
def test_association_force_reload_with_only_true_is_deprecated
company = Company.find(1)
diff --git a/activerecord/test/cases/base_test.rb b/activerecord/test/cases/base_test.rb
index d961f4710e..3a9d60a79f 100644
--- a/activerecord/test/cases/base_test.rb
+++ b/activerecord/test/cases/base_test.rb
@@ -1345,6 +1345,19 @@ class BasicsTest < ActiveRecord::TestCase
Company.attribute_names
end
+ def test_has_attribute
+ assert Company.has_attribute?('id')
+ assert Company.has_attribute?('type')
+ assert Company.has_attribute?('name')
+ assert_not Company.has_attribute?('lastname')
+ assert_not Company.has_attribute?('age')
+ end
+
+ def test_has_attribute_with_symbol
+ assert Company.has_attribute?(:id)
+ assert_not Company.has_attribute?(:age)
+ end
+
def test_attribute_names_on_table_not_exists
assert_equal [], NonExistentTable.attribute_names
end
diff --git a/activerecord/test/cases/finder_test.rb b/activerecord/test/cases/finder_test.rb
index 6686ce012d..91214da048 100644
--- a/activerecord/test/cases/finder_test.rb
+++ b/activerecord/test/cases/finder_test.rb
@@ -706,96 +706,13 @@ class FinderTest < ActiveRecord::TestCase
assert Company.where(["name = :name", {name: "37signals' go'es agains"}]).first
end
- def test_bind_arity
- assert_nothing_raised { bind '' }
- assert_raise(ActiveRecord::PreparedStatementInvalid) { bind '', 1 }
-
- assert_raise(ActiveRecord::PreparedStatementInvalid) { bind '?' }
- assert_nothing_raised { bind '?', 1 }
- assert_raise(ActiveRecord::PreparedStatementInvalid) { bind '?', 1, 1 }
- end
-
def test_named_bind_variables
- assert_equal '1', bind(':a', :a => 1) # ' ruby-mode
- assert_equal '1 1', bind(':a :a', :a => 1) # ' ruby-mode
-
- assert_nothing_raised { bind("'+00:00'", :foo => "bar") }
-
assert_kind_of Firm, Company.where(["name = :name", { name: "37signals" }]).first
assert_nil Company.where(["name = :name", { name: "37signals!" }]).first
assert_nil Company.where(["name = :name", { name: "37signals!' OR 1=1" }]).first
assert_kind_of Time, Topic.where(["id = :id", { id: 1 }]).first.written_on
end
- def test_named_bind_arity
- assert_nothing_raised { bind "name = :name", { name: "37signals" } }
- assert_nothing_raised { bind "name = :name", { name: "37signals", id: 1 } }
- assert_raise(ActiveRecord::PreparedStatementInvalid) { bind "name = :name", { id: 1 } }
- end
-
- class SimpleEnumerable
- include Enumerable
-
- def initialize(ary)
- @ary = ary
- end
-
- def each(&b)
- @ary.each(&b)
- end
- end
-
- def test_bind_enumerable
- quoted_abc = %(#{ActiveRecord::Base.connection.quote('a')},#{ActiveRecord::Base.connection.quote('b')},#{ActiveRecord::Base.connection.quote('c')})
-
- assert_equal '1,2,3', bind('?', [1, 2, 3])
- assert_equal quoted_abc, bind('?', %w(a b c))
-
- assert_equal '1,2,3', bind(':a', :a => [1, 2, 3])
- assert_equal quoted_abc, bind(':a', :a => %w(a b c)) # '
-
- assert_equal '1,2,3', bind('?', SimpleEnumerable.new([1, 2, 3]))
- assert_equal quoted_abc, bind('?', SimpleEnumerable.new(%w(a b c)))
-
- assert_equal '1,2,3', bind(':a', :a => SimpleEnumerable.new([1, 2, 3]))
- assert_equal quoted_abc, bind(':a', :a => SimpleEnumerable.new(%w(a b c))) # '
- end
-
- def test_bind_empty_enumerable
- quoted_nil = ActiveRecord::Base.connection.quote(nil)
- assert_equal quoted_nil, bind('?', [])
- assert_equal " in (#{quoted_nil})", bind(' in (?)', [])
- assert_equal "foo in (#{quoted_nil})", bind('foo in (?)', [])
- end
-
- def test_bind_empty_string
- quoted_empty = ActiveRecord::Base.connection.quote('')
- assert_equal quoted_empty, bind('?', '')
- end
-
- def test_bind_chars
- quoted_bambi = ActiveRecord::Base.connection.quote("Bambi")
- quoted_bambi_and_thumper = ActiveRecord::Base.connection.quote("Bambi\nand\nThumper")
- assert_equal "name=#{quoted_bambi}", bind('name=?', "Bambi")
- assert_equal "name=#{quoted_bambi_and_thumper}", bind('name=?', "Bambi\nand\nThumper")
- assert_equal "name=#{quoted_bambi}", bind('name=?', "Bambi".mb_chars)
- assert_equal "name=#{quoted_bambi_and_thumper}", bind('name=?', "Bambi\nand\nThumper".mb_chars)
- end
-
- def test_bind_record
- o = Struct.new(:quoted_id).new(1)
- assert_equal '1', bind('?', o)
-
- os = [o] * 3
- assert_equal '1,1,1', bind('?', os)
- end
-
- def test_named_bind_with_postgresql_type_casts
- l = Proc.new { bind(":a::integer '2009-01-01'::date", :a => '10') }
- assert_nothing_raised(&l)
- assert_equal "#{ActiveRecord::Base.connection.quote('10')}::integer '2009-01-01'::date", l.call
- end
-
def test_string_sanitation
assert_not_equal "'something ' 1=1'", ActiveRecord::Base.sanitize("something ' 1=1")
assert_equal "'something; select table'", ActiveRecord::Base.sanitize("something; select table")
@@ -1136,14 +1053,6 @@ class FinderTest < ActiveRecord::TestCase
end
protected
- def bind(statement, *vars)
- if vars.first.is_a?(Hash)
- ActiveRecord::Base.send(:replace_named_bind_variables, statement, vars.first)
- else
- ActiveRecord::Base.send(:replace_bind_variables, statement, vars)
- end
- end
-
def table_with_custom_primary_key
yield(Class.new(Toy) do
def self.name
diff --git a/activerecord/test/cases/inheritance_test.rb b/activerecord/test/cases/inheritance_test.rb
index 52e3734dd0..03bce547da 100644
--- a/activerecord/test/cases/inheritance_test.rb
+++ b/activerecord/test/cases/inheritance_test.rb
@@ -478,4 +478,49 @@ class InheritanceComputeTypeTest < ActiveRecord::TestCase
product = Shop::Product.new(:type => phone)
assert product.save
end
+
+ def test_inheritance_new_with_subclass_as_default
+ original_type = Company.columns_hash["type"].default
+ ActiveRecord::Base.connection.change_column_default :companies, :type, 'Firm'
+ Company.reset_column_information
+
+ firm = Company.new # without arguments
+ assert_equal 'Firm', firm.type
+ assert_instance_of Firm, firm
+
+ firm = Company.new(firm_name: 'Shri Hans Plastic') # with arguments
+ assert_equal 'Firm', firm.type
+ assert_instance_of Firm, firm
+
+ firm = Company.new(type: 'Client') # overwrite the default type
+ assert_equal 'Client', firm.type
+ assert_instance_of Client, firm
+ ensure
+ ActiveRecord::Base.connection.change_column_default :companies, :type, original_type
+ Company.reset_column_information
+ end
+end
+
+class InheritanceAttributeTest < ActiveRecord::TestCase
+
+ class Company < ActiveRecord::Base
+ self.table_name = 'companies'
+ attribute :type, :string, default: "InheritanceAttributeTest::Startup"
+ end
+
+ class Startup < Company
+ end
+
+ class Empire < Company
+ end
+
+ def test_inheritance_new_with_subclass_as_default
+ startup = Company.new # without arguments
+ assert_equal 'InheritanceAttributeTest::Startup', startup.type
+ assert_instance_of Startup, startup
+
+ empire = Company.new(type: 'InheritanceAttributeTest::Empire') # without arguments
+ assert_equal 'InheritanceAttributeTest::Empire', empire.type
+ assert_instance_of Empire, empire
+ end
end
diff --git a/activerecord/test/cases/relation/delegation_test.rb b/activerecord/test/cases/relation/delegation_test.rb
index b4269bd56d..f0e07e0731 100644
--- a/activerecord/test/cases/relation/delegation_test.rb
+++ b/activerecord/test/cases/relation/delegation_test.rb
@@ -27,7 +27,7 @@ module ActiveRecord
module DelegationWhitelistBlacklistTests
ARRAY_DELEGATES = [
- :+, :-, :|, :&, :[],
+ :+, :-, :|, :&, :[], :shuffle,
:all?, :collect, :compact, :detect, :each, :each_cons, :each_with_index,
:exclude?, :find_all, :flat_map, :group_by, :include?, :length,
:map, :none?, :one?, :partition, :reject, :reverse,
diff --git a/activerecord/test/cases/sanitize_test.rb b/activerecord/test/cases/sanitize_test.rb
index 14e392ac30..07970fb1c1 100644
--- a/activerecord/test/cases/sanitize_test.rb
+++ b/activerecord/test/cases/sanitize_test.rb
@@ -69,4 +69,98 @@ class SanitizeTest < ActiveRecord::TestCase
searchable_post.search("20% _reduction_!").to_a
end
end
+
+ def test_bind_arity
+ assert_nothing_raised { bind '' }
+ assert_raise(ActiveRecord::PreparedStatementInvalid) { bind '', 1 }
+
+ assert_raise(ActiveRecord::PreparedStatementInvalid) { bind '?' }
+ assert_nothing_raised { bind '?', 1 }
+ assert_raise(ActiveRecord::PreparedStatementInvalid) { bind '?', 1, 1 }
+ end
+
+ def test_named_bind_variables
+ assert_equal '1', bind(':a', :a => 1) # ' ruby-mode
+ assert_equal '1 1', bind(':a :a', :a => 1) # ' ruby-mode
+
+ assert_nothing_raised { bind("'+00:00'", :foo => "bar") }
+ end
+
+ def test_named_bind_arity
+ assert_nothing_raised { bind "name = :name", { name: "37signals" } }
+ assert_nothing_raised { bind "name = :name", { name: "37signals", id: 1 } }
+ assert_raise(ActiveRecord::PreparedStatementInvalid) { bind "name = :name", { id: 1 } }
+ end
+
+ class SimpleEnumerable
+ include Enumerable
+
+ def initialize(ary)
+ @ary = ary
+ end
+
+ def each(&b)
+ @ary.each(&b)
+ end
+ end
+
+ def test_bind_enumerable
+ quoted_abc = %(#{ActiveRecord::Base.connection.quote('a')},#{ActiveRecord::Base.connection.quote('b')},#{ActiveRecord::Base.connection.quote('c')})
+
+ assert_equal '1,2,3', bind('?', [1, 2, 3])
+ assert_equal quoted_abc, bind('?', %w(a b c))
+
+ assert_equal '1,2,3', bind(':a', :a => [1, 2, 3])
+ assert_equal quoted_abc, bind(':a', :a => %w(a b c)) # '
+
+ assert_equal '1,2,3', bind('?', SimpleEnumerable.new([1, 2, 3]))
+ assert_equal quoted_abc, bind('?', SimpleEnumerable.new(%w(a b c)))
+
+ assert_equal '1,2,3', bind(':a', :a => SimpleEnumerable.new([1, 2, 3]))
+ assert_equal quoted_abc, bind(':a', :a => SimpleEnumerable.new(%w(a b c))) # '
+ end
+
+ def test_bind_empty_enumerable
+ quoted_nil = ActiveRecord::Base.connection.quote(nil)
+ assert_equal quoted_nil, bind('?', [])
+ assert_equal " in (#{quoted_nil})", bind(' in (?)', [])
+ assert_equal "foo in (#{quoted_nil})", bind('foo in (?)', [])
+ end
+
+ def test_bind_empty_string
+ quoted_empty = ActiveRecord::Base.connection.quote('')
+ assert_equal quoted_empty, bind('?', '')
+ end
+
+ def test_bind_chars
+ quoted_bambi = ActiveRecord::Base.connection.quote("Bambi")
+ quoted_bambi_and_thumper = ActiveRecord::Base.connection.quote("Bambi\nand\nThumper")
+ assert_equal "name=#{quoted_bambi}", bind('name=?', "Bambi")
+ assert_equal "name=#{quoted_bambi_and_thumper}", bind('name=?', "Bambi\nand\nThumper")
+ assert_equal "name=#{quoted_bambi}", bind('name=?', "Bambi".mb_chars)
+ assert_equal "name=#{quoted_bambi_and_thumper}", bind('name=?', "Bambi\nand\nThumper".mb_chars)
+ end
+
+ def test_bind_record
+ o = Struct.new(:quoted_id).new(1)
+ assert_equal '1', bind('?', o)
+
+ os = [o] * 3
+ assert_equal '1,1,1', bind('?', os)
+ end
+
+ def test_named_bind_with_postgresql_type_casts
+ l = Proc.new { bind(":a::integer '2009-01-01'::date", :a => '10') }
+ assert_nothing_raised(&l)
+ assert_equal "#{ActiveRecord::Base.connection.quote('10')}::integer '2009-01-01'::date", l.call
+ end
+
+ private
+ def bind(statement, *vars)
+ if vars.first.is_a?(Hash)
+ ActiveRecord::Base.send(:replace_named_bind_variables, statement, vars.first)
+ else
+ ActiveRecord::Base.send(:replace_bind_variables, statement, vars)
+ end
+ end
end
diff --git a/activerecord/test/cases/tasks/postgresql_rake_test.rb b/activerecord/test/cases/tasks/postgresql_rake_test.rb
index c31f94b2f2..ba53f340ae 100644
--- a/activerecord/test/cases/tasks/postgresql_rake_test.rb
+++ b/activerecord/test/cases/tasks/postgresql_rake_test.rb
@@ -212,7 +212,7 @@ module ActiveRecord
def test_structure_dump_with_schema_search_path
@configuration['schema_search_path'] = 'foo,bar'
- Kernel.expects(:system).with('pg_dump', '-s', '-x', '-O', '-f', @filename, '--schema=foo --schema=bar', 'my-app-db').returns(true)
+ Kernel.expects(:system).with('pg_dump', '-s', '-x', '-O', '-f', @filename, '--schema=foo', '--schema=bar', 'my-app-db').returns(true)
ActiveRecord::Tasks::DatabaseTasks.structure_dump(@configuration, @filename)
end
@@ -228,7 +228,7 @@ module ActiveRecord
end
def test_structure_dump_with_dump_schemas_string
- Kernel.expects(:system).with("pg_dump", '-s', '-x', '-O', '-f', @filename, '--schema=foo --schema=bar', "my-app-db").returns(true)
+ Kernel.expects(:system).with("pg_dump", '-s', '-x', '-O', '-f', @filename, '--schema=foo', '--schema=bar', "my-app-db").returns(true)
with_dump_schemas('foo,bar') do
ActiveRecord::Tasks::DatabaseTasks.structure_dump(@configuration, @filename)
diff --git a/activerecord/test/models/bulb.rb b/activerecord/test/models/bulb.rb
index c1e491e5c5..dc0296305a 100644
--- a/activerecord/test/models/bulb.rb
+++ b/activerecord/test/models/bulb.rb
@@ -50,3 +50,9 @@ class FailedBulb < Bulb
throw(:abort)
end
end
+
+class TrickyBulb < Bulb
+ after_create do |record|
+ record.car.bulbs.to_a
+ end
+end
diff --git a/activerecord/test/schema/schema.rb b/activerecord/test/schema/schema.rb
index 99098017d7..025184f63a 100644
--- a/activerecord/test/schema/schema.rb
+++ b/activerecord/test/schema/schema.rb
@@ -356,7 +356,7 @@ ActiveRecord::Schema.define do
t.column :key, :string
end
- create_table :guitar, force: true do |t|
+ create_table :guitars, force: true do |t|
t.string :color
end