aboutsummaryrefslogtreecommitdiffstats
path: root/activerecord
diff options
context:
space:
mode:
Diffstat (limited to 'activerecord')
-rw-r--r--activerecord/activerecord.gemspec2
-rw-r--r--activerecord/lib/active_record/connection_adapters/abstract/connection_pool.rb8
-rw-r--r--activerecord/lib/active_record/connection_adapters/abstract/database_limits.rb21
-rw-r--r--activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb24
-rw-r--r--activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb6
-rw-r--r--activerecord/lib/active_record/connection_adapters/mysql2_adapter.rb22
-rw-r--r--activerecord/lib/active_record/connection_adapters/mysql_adapter.rb101
-rw-r--r--activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb141
-rw-r--r--activerecord/lib/active_record/connection_adapters/sqlite_adapter.rb19
-rw-r--r--activerecord/lib/active_record/fixtures.rb6
-rw-r--r--activerecord/lib/active_record/persistence.rb10
-rw-r--r--activerecord/lib/active_record/railties/databases.rake170
-rw-r--r--activerecord/lib/active_record/relation.rb6
-rw-r--r--activerecord/lib/active_record/relation/predicate_builder.rb13
-rw-r--r--activerecord/lib/active_record/validations.rb6
-rw-r--r--activerecord/test/cases/associations/belongs_to_associations_test.rb2
-rw-r--r--activerecord/test/cases/associations/eager_test.rb4
-rw-r--r--activerecord/test/cases/associations/has_many_through_associations_test.rb2
-rw-r--r--activerecord/test/cases/finder_test.rb23
-rw-r--r--activerecord/test/cases/fixtures_test.rb5
-rw-r--r--activerecord/test/cases/identity_map_test.rb8
21 files changed, 352 insertions, 247 deletions
diff --git a/activerecord/activerecord.gemspec b/activerecord/activerecord.gemspec
index c3cd76a714..9d4cbbc150 100644
--- a/activerecord/activerecord.gemspec
+++ b/activerecord/activerecord.gemspec
@@ -22,6 +22,6 @@ Gem::Specification.new do |s|
s.add_dependency('activesupport', version)
s.add_dependency('activemodel', version)
- s.add_dependency('arel', '~> 2.0.2')
+ s.add_dependency('arel', '~> 2.1.0')
s.add_dependency('tzinfo', '~> 0.3.23')
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 b4db1eed18..6f21cea288 100644
--- a/activerecord/lib/active_record/connection_adapters/abstract/connection_pool.rb
+++ b/activerecord/lib/active_record/connection_adapters/abstract/connection_pool.rb
@@ -113,7 +113,7 @@ module ActiveRecord
end
end
- # A cached lookup for table existence
+ # A cached lookup for table existence.
def table_exists?(name)
return true if @tables.key? name
@@ -135,7 +135,7 @@ module ActiveRecord
@tables.clear
end
- # Clear out internal caches for table with +table_name+
+ # Clear out internal caches for table with +table_name+.
def clear_table_cache!(table_name)
@columns.delete table_name
@columns_hash.delete table_name
@@ -193,7 +193,7 @@ module ActiveRecord
@connections = []
end
- # Clears the cache which maps classes
+ # Clears the cache which maps classes.
def clear_reloadable_connections!
@reserved_connections.each do |name, conn|
checkin conn
@@ -365,7 +365,7 @@ module ActiveRecord
@connection_pools.each_value {|pool| pool.release_connection }
end
- # Clears the cache which maps classes
+ # Clears the cache which maps classes.
def clear_reloadable_connections!
@connection_pools.each_value {|pool| pool.clear_reloadable_connections! }
end
diff --git a/activerecord/lib/active_record/connection_adapters/abstract/database_limits.rb b/activerecord/lib/active_record/connection_adapters/abstract/database_limits.rb
index 29ac9341ec..30ccb8f0a4 100644
--- a/activerecord/lib/active_record/connection_adapters/abstract/database_limits.rb
+++ b/activerecord/lib/active_record/connection_adapters/abstract/database_limits.rb
@@ -2,52 +2,53 @@ module ActiveRecord
module ConnectionAdapters # :nodoc:
module DatabaseLimits
- # the maximum length of a table alias
+ # Returns the maximum length of a table alias.
def table_alias_length
255
end
- # the maximum length of a column name
+ # Returns the maximum length of a column name.
def column_name_length
64
end
- # the maximum length of a table name
+ # Returns the maximum length of a table name.
def table_name_length
64
end
- # the maximum length of an index name
+ # Returns the maximum length of an index name.
def index_name_length
64
end
- # the maximum number of columns per table
+ # Returns the maximum number of columns per table.
def columns_per_table
1024
end
- # the maximum number of indexes per table
+ # Returns the maximum number of indexes per table.
def indexes_per_table
16
end
- # the maximum number of columns in a multicolumn index
+ # Returns the maximum number of columns in a multicolumn index.
def columns_per_multicolumn_index
16
end
- # the maximum number of elements in an IN (x,y,z) clause. nil means no limit
+ # Returns the maximum number of elements in an IN (x,y,z) clause.
+ # nil means no limit.
def in_clause_length
nil
end
- # the maximum length of an SQL query
+ # Returns the maximum length of an SQL query.
def sql_query_length
1048575
end
- # maximum number of joins in a single query
+ # Returns maximum number of joins in a single query.
def joins_per_query
256
end
diff --git a/activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb b/activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb
index 70da9d5f1e..3045e30407 100644
--- a/activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb
+++ b/activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb
@@ -55,13 +55,27 @@ module ActiveRecord
def exec_query(sql, name = 'SQL', binds = [])
end
- # Executes insert +sql+ statement in the context of this connection using
+ # Executes insert +sql+ statement in the context of this connection using
# +binds+ as the bind substitutes. +name+ is the logged along with
# the executed +sql+ statement.
def exec_insert(sql, name, binds)
exec_query(sql, name, binds)
end
+ # Executes delete +sql+ statement in the context of this connection using
+ # +binds+ as the bind substitutes. +name+ is the logged along with
+ # the executed +sql+ statement.
+ def exec_delete(sql, name, binds)
+ exec_query(sql, name, binds)
+ end
+
+ # Executes update +sql+ statement in the context of this connection using
+ # +binds+ as the bind substitutes. +name+ is the logged along with
+ # the executed +sql+ statement.
+ def exec_update(sql, name, binds)
+ exec_query(sql, name, binds)
+ end
+
# Returns the last auto-generated ID from the affected table.
#
# +id_value+ will be returned unless the value is nil, in
@@ -77,13 +91,13 @@ module ActiveRecord
end
# Executes the update statement and returns the number of rows affected.
- def update(sql, name = nil)
- update_sql(sql, name)
+ def update(sql, name = nil, binds = [])
+ exec_update(sql, name, binds)
end
# Executes the delete statement and returns the number of rows affected.
- def delete(sql, name = nil)
- delete_sql(sql, name)
+ def delete(sql, name = nil, binds = [])
+ exec_delete(sql, name, binds)
end
# Checks whether there is currently no transaction active. This is done
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 8bae50885f..9f9c2c42cb 100644
--- a/activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb
+++ b/activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb
@@ -17,6 +17,10 @@ module ActiveRecord
# def tables(name = nil) end
+ # Checks to see if the table +table_name+ exists on the database.
+ #
+ # === Example
+ # table_exists?(:developers)
def table_exists?(table_name)
tables.include?(table_name.to_s)
end
@@ -24,7 +28,7 @@ module ActiveRecord
# Returns an array of indexes for the given table.
# def indexes(table_name, name = nil) end
- # Checks to see if an index exists on a table for a given index definition
+ # Checks to see if an index exists on a table for a given index definition.
#
# === Examples
# # Check an index exists
diff --git a/activerecord/lib/active_record/connection_adapters/mysql2_adapter.rb b/activerecord/lib/active_record/connection_adapters/mysql2_adapter.rb
index cf68ddc2da..d3a054c29b 100644
--- a/activerecord/lib/active_record/connection_adapters/mysql2_adapter.rb
+++ b/activerecord/lib/active_record/connection_adapters/mysql2_adapter.rb
@@ -132,6 +132,7 @@ module ActiveRecord
ADAPTER_NAME
end
+ # Returns true, since this connection adapter supports migrations.
def supports_migrations?
true
end
@@ -140,6 +141,7 @@ module ActiveRecord
true
end
+ # Returns true, since this connection adapter supports savepoints.
def supports_savepoints?
true
end
@@ -290,6 +292,15 @@ module ActiveRecord
execute sql.gsub('?') { quote(*binds.shift.reverse) }, name
end
+ def exec_delete(sql, name, binds)
+ binds = binds.dup
+
+ # Pretend to support bind parameters
+ execute sql.gsub('?') { quote(*binds.shift.reverse) }, name
+ @connection.affected_rows
+ end
+ alias :exec_update :exec_delete
+
def last_inserted_id(result)
@connection.last_id
end
@@ -377,6 +388,10 @@ module ActiveRecord
end
end
+ # Drops a MySQL database.
+ #
+ # Example:
+ # drop_database('sebastian_development')
def drop_database(name) #:nodoc:
execute "DROP DATABASE IF EXISTS `#{name}`"
end
@@ -407,6 +422,7 @@ module ActiveRecord
super(table_name, options)
end
+ # Returns an array of indexes for the given table.
def indexes(table_name, name = nil)
indexes = []
current_index = nil
@@ -424,6 +440,7 @@ module ActiveRecord
indexes
end
+ # Returns an array of +Mysql2Column+ objects for the table specified by +table_name+.
def columns(table_name, name = nil)
sql = "SHOW FIELDS FROM #{quote_table_name(table_name)}"
columns = []
@@ -438,6 +455,10 @@ module ActiveRecord
super(table_name, options.reverse_merge(:options => "ENGINE=InnoDB"))
end
+ # Renames a table.
+ #
+ # Example:
+ # rename_table('octopuses', 'octopi')
def rename_table(table_name, new_name)
execute "RENAME TABLE #{quote_table_name(table_name)} TO #{quote_table_name(new_name)}"
end
@@ -522,6 +543,7 @@ module ActiveRecord
variables.first['Value'] unless variables.empty?
end
+ # Returns a table's primary key and belonging sequence.
def pk_and_sequence_for(table)
keys = []
result = execute("describe #{quote_table_name(table)}")
diff --git a/activerecord/lib/active_record/connection_adapters/mysql_adapter.rb b/activerecord/lib/active_record/connection_adapters/mysql_adapter.rb
index 2c05ff21f9..862ce852e6 100644
--- a/activerecord/lib/active_record/connection_adapters/mysql_adapter.rb
+++ b/activerecord/lib/active_record/connection_adapters/mysql_adapter.rb
@@ -3,15 +3,8 @@ require 'active_support/core_ext/kernel/requires'
require 'active_support/core_ext/object/blank'
require 'set'
-begin
- require 'mysql'
-rescue LoadError
- raise "!!! Missing the mysql gem. Add it to your Gemfile: gem 'mysql'"
-end
-
-unless defined?(Mysql::Result) && Mysql::Result.method_defined?(:each_hash)
- raise "!!! Outdated mysql gem. Upgrade to 2.8.1 or later. In your Gemfile: gem 'mysql', '2.8.1'. Or use gem 'mysql2'"
-end
+gem 'mysql', '~> 2.8.1'
+require 'mysql'
class Mysql
class Time
@@ -208,13 +201,13 @@ module ActiveRecord
true
end
- # Returns +true+, since this connection adapter supports prepared statement
+ # Returns true, since this connection adapter supports prepared statement
# caching.
def supports_statement_cache?
true
end
- # Returns true.
+ # Returns true, since this connection adapter supports migrations.
def supports_migrations? #:nodoc:
true
end
@@ -224,6 +217,7 @@ module ActiveRecord
true
end
+ # Returns true, since this connection adapter supports savepoints.
def supports_savepoints? #:nodoc:
true
end
@@ -401,34 +395,9 @@ module ActiveRecord
def exec_query(sql, name = 'SQL', binds = [])
log(sql, name, binds) do
- result = nil
-
- cache = {}
- if binds.empty?
- stmt = @connection.prepare(sql)
- else
- cache = @statements[sql] ||= {
- :stmt => @connection.prepare(sql)
- }
- stmt = cache[:stmt]
- end
-
- stmt.execute(*binds.map { |col, val|
- type_cast(val, col)
- })
- if metadata = stmt.result_metadata
- cols = cache[:cols] ||= metadata.fetch_fields.map { |field|
- field.name
- }
-
- metadata.free
- result = ActiveRecord::Result.new(cols, stmt.to_a)
+ exec_stmt(sql, name, binds) do |cols, stmt|
+ ActiveRecord::Result.new(cols, stmt.to_a) if cols
end
-
- stmt.free_result
- stmt.close if binds.empty?
-
- result
end
end
@@ -480,6 +449,15 @@ module ActiveRecord
@connection.affected_rows
end
+ def exec_delete(sql, name, binds)
+ log(sql, name, binds) do
+ exec_stmt(sql, name, binds) do |cols, stmt|
+ stmt.affected_rows
+ end
+ end
+ end
+ alias :exec_update :exec_delete
+
def begin_db_transaction #:nodoc:
exec_without_stmt "BEGIN"
rescue Mysql::Error
@@ -607,6 +585,7 @@ module ActiveRecord
super(table_name, options)
end
+ # Returns an array of indexes for the given table.
def indexes(table_name, name = nil)#:nodoc:
indexes = []
current_index = nil
@@ -625,6 +604,7 @@ module ActiveRecord
indexes
end
+ # Returns an array of +MysqlColumn+ objects for the table specified by +table_name+.
def columns(table_name, name = nil)#:nodoc:
sql = "SHOW FIELDS FROM #{quote_table_name(table_name)}"
columns = []
@@ -638,6 +618,10 @@ module ActiveRecord
super(table_name, options.reverse_merge(:options => "ENGINE=InnoDB"))
end
+ # Renames a table.
+ #
+ # Example:
+ # rename_table('octopuses', 'octopi')
def rename_table(table_name, new_name)
execute "RENAME TABLE #{quote_table_name(table_name)} TO #{quote_table_name(new_name)}"
end
@@ -833,6 +817,46 @@ module ActiveRecord
end
private
+ def exec_stmt(sql, name, binds)
+ cache = {}
+ if binds.empty?
+ stmt = @connection.prepare(sql)
+ else
+ cache = @statements[sql] ||= {
+ :stmt => @connection.prepare(sql)
+ }
+ stmt = cache[:stmt]
+ end
+
+
+ begin
+ stmt.execute(*binds.map { |col, val| type_cast(val, col) })
+ rescue Mysql::Error => e
+ # Older versions of MySQL leave the prepared statement in a bad
+ # place when an error occurs. To support older mysql versions, we
+ # need to close the statement and delete the statement from the
+ # cache.
+ stmt.close
+ @statements.delete sql
+ raise e
+ end
+
+ cols = nil
+ if metadata = stmt.result_metadata
+ cols = cache[:cols] ||= metadata.fetch_fields.map { |field|
+ field.name
+ }
+ end
+
+ result = yield [cols, stmt]
+
+ stmt.result_metadata.free if cols
+ stmt.free_result
+ stmt.close if binds.empty?
+
+ result
+ end
+
def connect
encoding = @config[:encoding]
if encoding
@@ -875,6 +899,7 @@ module ActiveRecord
version[0] >= 5
end
+ # Returns the version of the connected MySQL server.
def version
@version ||= @connection.server_info.scan(/^(\d+)\.(\d+)\.(\d+)/).flatten.map { |v| v.to_i }
end
diff --git a/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb b/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb
index 0c2afc180b..37db2be7a9 100644
--- a/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb
+++ b/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb
@@ -122,6 +122,14 @@ module ActiveRecord
# Extracts the value from a PostgreSQL column default definition.
def self.extract_value_from_default(default)
case default
+ # This is a performance optimization for Ruby 1.9.2 in development.
+ # If the value is nil, we return nil straight away without checking
+ # the regular expressions. If we check each regular expression,
+ # Regexp#=== will call NilClass#to_str, which will trigger
+ # method_missing (defined by whiny nil in ActiveSupport) which
+ # makes this method very very slow.
+ when NilClass
+ nil
# Numeric types
when /\A\(?(-?\d+(\.\d*)?\)?)\z/
$1
@@ -237,7 +245,6 @@ module ActiveRecord
# @local_tz is initialized as nil to avoid warnings when connect tries to use it
@local_tz = nil
@table_alias_length = nil
- @postgresql_version = nil
@statements = {}
connect
@@ -259,28 +266,16 @@ module ActiveRecord
# Is this connection alive and ready for queries?
def active?
- if @connection.respond_to?(:status)
- @connection.status == PGconn::CONNECTION_OK
- else
- # We're asking the driver, not Active Record, so use @connection.query instead of #query
- @connection.query 'SELECT 1'
- true
- end
- # postgres-pr raises a NoMethodError when querying if no connection is available.
- rescue PGError, NoMethodError
+ @connection.status == PGconn::CONNECTION_OK
+ rescue PGError
false
end
# Close then reopen the connection.
def reconnect!
- if @connection.respond_to?(:reset)
- clear_cache!
- @connection.reset
- configure_connection
- else
- disconnect!
- connect
- end
+ clear_cache!
+ @connection.reset
+ configure_connection
end
def reset!
@@ -299,7 +294,7 @@ module ActiveRecord
NATIVE_DATABASE_TYPES
end
- # Does PostgreSQL support migrations?
+ # Returns true, since this connection adapter supports migrations.
def supports_migrations?
true
end
@@ -325,6 +320,7 @@ module ActiveRecord
true
end
+ # Returns true, since this connection adapter supports savepoints.
def supports_savepoints?
true
end
@@ -433,17 +429,17 @@ module ActiveRecord
# REFERENTIAL INTEGRITY ====================================
- def supports_disable_referential_integrity?() #:nodoc:
+ def supports_disable_referential_integrity? #:nodoc:
true
end
def disable_referential_integrity #:nodoc:
- if supports_disable_referential_integrity?() then
+ if supports_disable_referential_integrity? then
execute(tables.collect { |name| "ALTER TABLE #{quote_table_name(name)} DISABLE TRIGGER ALL" }.join(";"))
end
yield
ensure
- if supports_disable_referential_integrity?() then
+ if supports_disable_referential_integrity? then
execute(tables.collect { |name| "ALTER TABLE #{quote_table_name(name)} ENABLE TRIGGER ALL" }.join(";"))
end
end
@@ -517,12 +513,7 @@ module ActiveRecord
# Queries the database and returns the results in an Array-like object
def query(sql, name = nil) #:nodoc:
log(sql, name) do
- if @async
- res = @connection.async_exec(sql)
- else
- res = @connection.exec(sql)
- end
- return result_as_array(res)
+ result_as_array @connection.async_exec(sql)
end
end
@@ -530,11 +521,7 @@ module ActiveRecord
# or raising a PGError exception otherwise.
def execute(sql, name = nil)
log(sql, name) do
- if @async
- @connection.async_exec(sql)
- else
- @connection.exec(sql)
- end
+ @connection.async_exec(sql)
end
end
@@ -543,30 +530,27 @@ module ActiveRecord
end
def exec_query(sql, name = 'SQL', binds = [])
- return exec_no_cache(sql, name) if binds.empty?
-
log(sql, name, binds) do
- unless @statements.key? sql
- nextkey = "a#{@statements.length + 1}"
- @connection.prepare nextkey, sql
- @statements[sql] = nextkey
- end
+ result = binds.empty? ? exec_no_cache(sql, binds) :
+ exec_cache(sql, binds)
- key = @statements[sql]
-
- # Clear the queue
- @connection.get_last_result
- @connection.send_query_prepared(key, binds.map { |col, val|
- type_cast(val, col)
- })
- @connection.block
- result = @connection.get_last_result
ret = ActiveRecord::Result.new(result.fields, result_as_array(result))
result.clear
return ret
end
end
+ def exec_delete(sql, name = 'SQL', binds = [])
+ log(sql, name, binds) do
+ result = binds.empty? ? exec_no_cache(sql, binds) :
+ exec_cache(sql, binds)
+ affected = result.cmd_tuples
+ result.clear
+ affected
+ end
+ end
+ alias :exec_update :exec_delete
+
def sql_for_insert(sql, pk, id_value, sequence_name, binds)
unless pk
_, table = extract_schema_and_table(sql.split(" ", 4)[2])
@@ -699,7 +683,7 @@ module ActiveRecord
[schema, table]
end
- # Returns the list of all indexes for a table.
+ # Returns an array of indexes for the given table.
def indexes(table_name, name = nil)
schemas = schema_search_path.split(/,/).map { |p| quote(p) }.join(',')
result = query(<<-SQL, name)
@@ -864,6 +848,9 @@ module ActiveRecord
end
# Renames a table.
+ #
+ # Example:
+ # rename_table('octopuses', 'octopi')
def rename_table(name, new_name)
execute "ALTER TABLE #{quote_table_name(name)} RENAME TO #{quote_table_name(new_name)}"
end
@@ -948,24 +935,9 @@ module ActiveRecord
end
protected
- # Returns the version of the connected PostgreSQL version.
+ # Returns the version of the connected PostgreSQL server.
def postgresql_version
- @postgresql_version ||=
- if @connection.respond_to?(:server_version)
- @connection.server_version
- else
- # Mimic PGconn.server_version behavior
- begin
- if query('SELECT version()')[0][0] =~ /PostgreSQL ([0-9.]+)/
- major, minor, tiny = $1.split(".")
- (major.to_i * 10000) + (minor.to_i * 100) + tiny.to_i
- else
- 0
- end
- rescue
- 0
- end
- end
+ @connection.server_version
end
def translate_exception(exception, message)
@@ -980,13 +952,26 @@ module ActiveRecord
end
private
- def exec_no_cache(sql, name)
- log(sql, name) do
- result = @connection.async_exec(sql)
- ret = ActiveRecord::Result.new(result.fields, result_as_array(result))
- result.clear
- ret
+ def exec_no_cache(sql, binds)
+ @connection.async_exec(sql)
+ end
+
+ def exec_cache(sql, binds)
+ unless @statements.key? sql
+ nextkey = "a#{@statements.length + 1}"
+ @connection.prepare nextkey, sql
+ @statements[sql] = nextkey
end
+
+ key = @statements[sql]
+
+ # Clear the queue
+ @connection.get_last_result
+ @connection.send_query_prepared(key, binds.map { |col, val|
+ type_cast(val, col)
+ })
+ @connection.block
+ @connection.get_last_result
end
# The internal PostgreSQL identifier of the money data type.
@@ -998,10 +983,6 @@ module ActiveRecord
# connected server's characteristics.
def connect
@connection = PGconn.connect(*@connection_parameters)
- PGconn.translate_results = false if PGconn.respond_to?(:translate_results=)
-
- # Ignore async_exec and async_query when using postgres-pr.
- @async = @connection.respond_to?(:async_exec)
# Money type has a fixed precision of 10 in PostgreSQL 8.2 and below, and as of
# PostgreSQL 8.3 it has a fixed precision of 19. PostgreSQLColumn.extract_precision
@@ -1015,11 +996,7 @@ module ActiveRecord
# This is called by #connect and should not be called manually.
def configure_connection
if @config[:encoding]
- if @connection.respond_to?(:set_client_encoding)
- @connection.set_client_encoding(@config[:encoding])
- else
- execute("SET client_encoding TO '#{@config[:encoding]}'")
- end
+ @connection.set_client_encoding(@config[:encoding])
end
self.client_min_messages = @config[:min_messages] if @config[:min_messages]
self.schema_search_path = @config[:schema_search_path] || @config[:schema_order]
diff --git a/activerecord/lib/active_record/connection_adapters/sqlite_adapter.rb b/activerecord/lib/active_record/connection_adapters/sqlite_adapter.rb
index ed5006dcec..d2785b234a 100644
--- a/activerecord/lib/active_record/connection_adapters/sqlite_adapter.rb
+++ b/activerecord/lib/active_record/connection_adapters/sqlite_adapter.rb
@@ -58,10 +58,12 @@ module ActiveRecord
'SQLite'
end
+ # Returns true if SQLite version is '2.0.0' or greater, false otherwise.
def supports_ddl_transactions?
sqlite_version >= '2.0.0'
end
+ # Returns true if SQLite version is '3.6.8' or greater, false otherwise.
def supports_savepoints?
sqlite_version >= '3.6.8'
end
@@ -72,7 +74,7 @@ module ActiveRecord
true
end
- # Returns true.
+ # Returns true, since this connection adapter supports migrations.
def supports_migrations? #:nodoc:
true
end
@@ -86,6 +88,7 @@ module ActiveRecord
true
end
+ # Returns true if SQLite version is '3.1.6' or greater, false otherwise.
def supports_add_column?
sqlite_version >= '3.1.6'
end
@@ -103,10 +106,12 @@ module ActiveRecord
@statements.clear
end
+ # Returns true if SQLite version is '3.2.6' or greater, false otherwise.
def supports_count_distinct? #:nodoc:
sqlite_version >= '3.2.6'
end
+ # Returns true if SQLite version is '3.1.0' or greater, false otherwise.
def supports_autoincrement? #:nodoc:
sqlite_version >= '3.1.0'
end
@@ -178,6 +183,12 @@ module ActiveRecord
end
end
+ def exec_delete(sql, name = 'SQL', binds = [])
+ exec_query(sql, name, binds)
+ @connection.changes
+ end
+ alias :exec_update :exec_delete
+
def last_inserted_id(result)
@connection.last_insert_row_id
end
@@ -244,6 +255,7 @@ module ActiveRecord
end
end
+ # Returns an array of +SQLiteColumn+ objects for the table specified by +table_name+.
def columns(table_name, name = nil) #:nodoc:
table_structure(table_name).map do |field|
case field["dflt_value"]
@@ -259,6 +271,7 @@ module ActiveRecord
end
end
+ # Returns an array of indexes for the given table.
def indexes(table_name, name = nil) #:nodoc:
exec_query("PRAGMA index_list(#{quote_table_name(table_name)})", name).map do |row|
IndexDefinition.new(
@@ -282,6 +295,10 @@ module ActiveRecord
exec_query "DROP INDEX #{quote_column_name(index_name)}"
end
+ # Renames a table.
+ #
+ # Example:
+ # rename_table('octopuses', 'octopi')
def rename_table(name, new_name)
exec_query "ALTER TABLE #{quote_table_name(name)} RENAME TO #{quote_table_name(new_name)}"
end
diff --git a/activerecord/lib/active_record/fixtures.rb b/activerecord/lib/active_record/fixtures.rb
index 0939ec2626..96fea741e0 100644
--- a/activerecord/lib/active_record/fixtures.rb
+++ b/activerecord/lib/active_record/fixtures.rb
@@ -509,7 +509,9 @@ class Fixtures
# FIXME: Apparently JK uses this.
connection = block_given? ? yield : ActiveRecord::Base.connection
- files_to_read = table_names.reject { |table_name| fixture_is_cached?(connection, table_name) }
+ files_to_read = table_names.reject { |table_name|
+ fixture_is_cached?(connection, table_name)
+ }
unless files_to_read.empty?
connection.disable_referential_integrity do
@@ -521,7 +523,7 @@ class Fixtures
fixtures_map[path] = Fixtures.new(
connection,
table_name,
- class_names[table_name.to_sym],
+ class_names[table_name.to_sym] || table_name.classify,
File.join(fixtures_directory, path))
end
diff --git a/activerecord/lib/active_record/persistence.rb b/activerecord/lib/active_record/persistence.rb
index 787ac977e0..b4531ed35f 100644
--- a/activerecord/lib/active_record/persistence.rb
+++ b/activerecord/lib/active_record/persistence.rb
@@ -77,7 +77,15 @@ module ActiveRecord
def destroy
if persisted?
IdentityMap.remove(self) if IdentityMap.enabled?
- self.class.unscoped.where(self.class.arel_table[self.class.primary_key].eq(id)).delete_all
+ pk = self.class.primary_key
+ column = self.class.columns_hash[pk]
+ substitute = connection.substitute_at(column, 0)
+
+ relation = self.class.unscoped.where(
+ self.class.arel_table[pk].eq(substitute))
+
+ relation.bind_values = [[column, id]]
+ relation.delete_all
end
@destroyed = true
diff --git a/activerecord/lib/active_record/railties/databases.rake b/activerecord/lib/active_record/railties/databases.rake
index 7d76d7a19f..5703fac033 100644
--- a/activerecord/lib/active_record/railties/databases.rake
+++ b/activerecord/lib/active_record/railties/databases.rake
@@ -4,11 +4,11 @@ db_namespace = namespace :db do
task :load_config => :rails_env do
require 'active_record'
ActiveRecord::Base.configurations = Rails.application.config.database_configuration
- ActiveRecord::Migrator.migrations_paths = Rails.application.paths["db/migrate"].to_a
+ ActiveRecord::Migrator.migrations_paths = Rails.application.paths['db/migrate'].to_a
if defined?(ENGINE_PATH) && engine = Rails::Engine.find(ENGINE_PATH)
- if engine.paths["db/migrate"].existent
- ActiveRecord::Migrator.migrations_paths += engine.paths["db/migrate"].to_a
+ if engine.paths['db/migrate'].existent
+ ActiveRecord::Migrator.migrations_paths += engine.paths['db/migrate'].to_a
end
end
end
@@ -143,7 +143,7 @@ db_namespace = namespace :db do
end
def local_database?(config, &block)
- if config['host'].in?(["127.0.0.1", "localhost"]) || config['host'].blank?
+ if config['host'].in?(['127.0.0.1', 'localhost']) || config['host'].blank?
yield
else
$stderr.puts "This task only modifies local databases. #{config['database']} is on a remote host."
@@ -161,35 +161,35 @@ db_namespace = namespace :db do
namespace :migrate do
# desc 'Rollbacks the database one migration and re migrate up (options: STEP=x, VERSION=x).'
task :redo => [:environment, :load_config] do
- if ENV["VERSION"]
- db_namespace["migrate:down"].invoke
- db_namespace["migrate:up"].invoke
+ if ENV['VERSION']
+ db_namespace['migrate:down'].invoke
+ db_namespace['migrate:up'].invoke
else
- db_namespace["rollback"].invoke
- db_namespace["migrate"].invoke
+ db_namespace['rollback'].invoke
+ db_namespace['migrate'].invoke
end
end
# desc 'Resets your database using your migrations for the current environment'
- task :reset => ["db:drop", "db:create", "db:migrate"]
+ task :reset => ['db:drop', 'db:create', 'db:migrate']
# desc 'Runs the "up" for a given migration VERSION.'
task :up => [:environment, :load_config] do
- version = ENV["VERSION"] ? ENV["VERSION"].to_i : nil
- raise "VERSION is required" unless version
+ version = ENV['VERSION'] ? ENV['VERSION'].to_i : nil
+ raise 'VERSION is required' unless version
ActiveRecord::Migrator.run(:up, ActiveRecord::Migrator.migrations_paths, version)
- db_namespace["schema:dump"].invoke if ActiveRecord::Base.schema_format == :ruby
+ db_namespace['schema:dump'].invoke if ActiveRecord::Base.schema_format == :ruby
end
# desc 'Runs the "down" for a given migration VERSION.'
task :down => [:environment, :load_config] do
- version = ENV["VERSION"] ? ENV["VERSION"].to_i : nil
- raise "VERSION is required" unless version
+ version = ENV['VERSION'] ? ENV['VERSION'].to_i : nil
+ raise 'VERSION is required' unless version
ActiveRecord::Migrator.run(:down, ActiveRecord::Migrator.migrations_paths, version)
- db_namespace["schema:dump"].invoke if ActiveRecord::Base.schema_format == :ruby
+ db_namespace['schema:dump'].invoke if ActiveRecord::Base.schema_format == :ruby
end
- desc "Display status of migrations"
+ desc 'Display status of migrations'
task :status => [:environment, :load_config] do
config = ActiveRecord::Base.configurations[Rails.env || 'development']
ActiveRecord::Base.establish_connection(config)
@@ -208,7 +208,7 @@ db_namespace = namespace :db do
end
# output
puts "\ndatabase: #{config['database']}\n\n"
- puts "#{"Status".center(8)} #{"Migration ID".ljust(14)} Migration Name"
+ puts "#{'Status'.center(8)} #{'Migration ID'.ljust(14)} Migration Name"
puts "-" * 50
file_list.each do |file|
puts "#{file[0].center(8)} #{file[1].ljust(14)} #{file[2].humanize}"
@@ -224,14 +224,14 @@ db_namespace = namespace :db do
task :rollback => [:environment, :load_config] do
step = ENV['STEP'] ? ENV['STEP'].to_i : 1
ActiveRecord::Migrator.rollback(ActiveRecord::Migrator.migrations_paths, step)
- db_namespace["schema:dump"].invoke if ActiveRecord::Base.schema_format == :ruby
+ db_namespace['schema:dump'].invoke if ActiveRecord::Base.schema_format == :ruby
end
# desc 'Pushes the schema to the next version (specify steps w/ STEP=n).'
task :forward => [:environment, :load_config] do
step = ENV['STEP'] ? ENV['STEP'].to_i : 1
ActiveRecord::Migrator.forward(ActiveRecord::Migrator.migrations_paths, step)
- db_namespace["schema:dump"].invoke if ActiveRecord::Base.schema_format == :ruby
+ db_namespace['schema:dump'].invoke if ActiveRecord::Base.schema_format == :ruby
end
# desc 'Drops and recreates the database from db/schema.rb for the current environment and loads the seeds.'
@@ -244,10 +244,10 @@ db_namespace = namespace :db do
when /mysql/
ActiveRecord::Base.establish_connection(config)
puts ActiveRecord::Base.connection.charset
- when 'postgresql'
+ when /postgresql/
ActiveRecord::Base.establish_connection(config)
puts ActiveRecord::Base.connection.encoding
- when 'sqlite3'
+ when /sqlite/
ActiveRecord::Base.establish_connection(config)
puts ActiveRecord::Base.connection.encoding
else
@@ -267,7 +267,7 @@ db_namespace = namespace :db do
end
end
- desc "Retrieves the current schema version number"
+ desc 'Retrieves the current schema version number'
task :version => :environment do
puts "Current version: #{ActiveRecord::Migrator.current_version}"
end
@@ -301,8 +301,8 @@ db_namespace = namespace :db do
require 'active_record/fixtures'
ActiveRecord::Base.establish_connection(Rails.env)
- base_dir = ENV['FIXTURES_PATH'] ? File.join(Rails.root, ENV['FIXTURES_PATH']) : File.join(Rails.root, 'test', 'fixtures')
- fixtures_dir = ENV['FIXTURES_DIR'] ? File.join(base_dir, ENV['FIXTURES_DIR']) : base_dir
+ base_dir = File.join [Rails.root, ENV['FIXTURES_PATH'] || %w{test fixtures}].flatten
+ fixtures_dir = File.join [base_dir, ENV['FIXTURES_DIR']].compact
(ENV['FIXTURES'] ? ENV['FIXTURES'].split(/,/) : Dir["#{fixtures_dir}/**/*.{yml,csv}"].map {|f| f[(fixtures_dir.size + 1)..-5] }).each do |fixture_file|
Fixtures.create_fixtures(fixtures_dir, fixture_file)
@@ -313,8 +313,8 @@ db_namespace = namespace :db do
task :identify => :environment do
require 'active_record/fixtures'
- label, id = ENV["LABEL"], ENV["ID"]
- raise "LABEL or ID required" if label.blank? && id.blank?
+ label, id = ENV['LABEL'], ENV['ID']
+ raise 'LABEL or ID required' if label.blank? && id.blank?
puts %Q(The fixture ID for "#{label}" is #{Fixtures.identify(label)}.) if label
@@ -334,16 +334,16 @@ db_namespace = namespace :db do
end
namespace :schema do
- desc "Create a db/schema.rb file that can be portably used against any DB supported by AR"
+ desc 'Create a db/schema.rb file that can be portably used against any DB supported by AR'
task :dump => :load_config do
require 'active_record/schema_dumper'
File.open(ENV['SCHEMA'] || "#{Rails.root}/db/schema.rb", "w") do |file|
ActiveRecord::SchemaDumper.dump(ActiveRecord::Base.connection, file)
end
- db_namespace["schema:dump"].reenable
+ db_namespace['schema:dump'].reenable
end
- desc "Load a schema.rb file into the database"
+ desc 'Load a schema.rb file into the database'
task :load => :environment do
file = ENV['SCHEMA'] || "#{Rails.root}/db/schema.rb"
if File.exists?(file)
@@ -355,29 +355,29 @@ db_namespace = namespace :db do
end
namespace :structure do
- desc "Dump the database structure to an SQL file"
+ desc 'Dump the database structure to an SQL file'
task :dump => :environment do
abcs = ActiveRecord::Base.configurations
- case abcs[Rails.env]["adapter"]
- when /mysql/, "oci", "oracle"
+ case abcs[Rails.env]['adapter']
+ when /mysql/, 'oci', 'oracle'
ActiveRecord::Base.establish_connection(abcs[Rails.env])
File.open("#{Rails.root}/db/#{Rails.env}_structure.sql", "w+") { |f| f << ActiveRecord::Base.connection.structure_dump }
- when "postgresql"
- ENV['PGHOST'] = abcs[Rails.env]["host"] if abcs[Rails.env]["host"]
- ENV['PGPORT'] = abcs[Rails.env]["port"].to_s if abcs[Rails.env]["port"]
- ENV['PGPASSWORD'] = abcs[Rails.env]["password"].to_s if abcs[Rails.env]["password"]
- search_path = abcs[Rails.env]["schema_search_path"]
+ when /postgresql/
+ ENV['PGHOST'] = abcs[Rails.env]['host'] if abcs[Rails.env]['host']
+ ENV['PGPORT'] = abcs[Rails.env]["port"].to_s if abcs[Rails.env]['port']
+ ENV['PGPASSWORD'] = abcs[Rails.env]['password'].to_s if abcs[Rails.env]['password']
+ search_path = abcs[Rails.env]['schema_search_path']
unless search_path.blank?
search_path = search_path.split(",").map{|search_path| "--schema=#{search_path.strip}" }.join(" ")
end
- `pg_dump -i -U "#{abcs[Rails.env]["username"]}" -s -x -O -f db/#{Rails.env}_structure.sql #{search_path} #{abcs[Rails.env]["database"]}`
- raise "Error dumping database" if $?.exitstatus == 1
- when "sqlite", "sqlite3"
- dbfile = abcs[Rails.env]["database"] || abcs[Rails.env]["dbfile"]
- `#{abcs[Rails.env]["adapter"]} #{dbfile} .schema > db/#{Rails.env}_structure.sql`
- when "sqlserver"
- `scptxfr /s #{abcs[Rails.env]["host"]} /d #{abcs[Rails.env]["database"]} /I /f db\\#{Rails.env}_structure.sql /q /A /r`
- `scptxfr /s #{abcs[Rails.env]["host"]} /d #{abcs[Rails.env]["database"]} /I /F db\ /q /A /r`
+ `pg_dump -i -U "#{abcs[Rails.env]['username']}" -s -x -O -f db/#{Rails.env}_structure.sql #{search_path} #{abcs[Rails.env]['database']}`
+ raise 'Error dumping database' if $?.exitstatus == 1
+ when /sqlite/
+ dbfile = abcs[Rails.env]['database'] || abcs[Rails.env]['dbfile']
+ `sqlite3 #{dbfile} .schema > db/#{Rails.env}_structure.sql`
+ when 'sqlserver'
+ `scptxfr /s #{abcs[Rails.env]['host']} /d #{abcs[Rails.env]['database']} /I /f db\\#{Rails.env}_structure.sql /q /A /r`
+ `scptxfr /s #{abcs[Rails.env]['host']} /d #{abcs[Rails.env]['database']} /I /F db\ /q /A /r`
when "firebird"
set_firebird_env(abcs[Rails.env])
db_string = firebird_db_string(abcs[Rails.env])
@@ -397,81 +397,81 @@ db_namespace = namespace :db do
task :load => 'db:test:purge' do
ActiveRecord::Base.establish_connection(ActiveRecord::Base.configurations['test'])
ActiveRecord::Schema.verbose = false
- db_namespace["schema:load"].invoke
+ db_namespace['schema:load'].invoke
end
# desc "Recreate the test database from the current environment's database schema"
task :clone => %w(db:schema:dump db:test:load)
# desc "Recreate the test databases from the development structure"
- task :clone_structure => [ "db:structure:dump", "db:test:purge" ] do
+ task :clone_structure => [ 'db:structure:dump', 'db:test:purge' ] do
abcs = ActiveRecord::Base.configurations
- case abcs["test"]["adapter"]
+ case abcs['test']['adapter']
when /mysql/
ActiveRecord::Base.establish_connection(:test)
ActiveRecord::Base.connection.execute('SET foreign_key_checks = 0')
IO.readlines("#{Rails.root}/db/#{Rails.env}_structure.sql").join.split("\n\n").each do |table|
ActiveRecord::Base.connection.execute(table)
end
- when "postgresql"
- ENV['PGHOST'] = abcs["test"]["host"] if abcs["test"]["host"]
- ENV['PGPORT'] = abcs["test"]["port"].to_s if abcs["test"]["port"]
- ENV['PGPASSWORD'] = abcs["test"]["password"].to_s if abcs["test"]["password"]
- `psql -U "#{abcs["test"]["username"]}" -f #{Rails.root}/db/#{Rails.env}_structure.sql #{abcs["test"]["database"]} #{abcs["test"]["template"]}`
- when "sqlite", "sqlite3"
- dbfile = abcs["test"]["database"] || abcs["test"]["dbfile"]
- `#{abcs["test"]["adapter"]} #{dbfile} < #{Rails.root}/db/#{Rails.env}_structure.sql`
- when "sqlserver"
- `osql -E -S #{abcs["test"]["host"]} -d #{abcs["test"]["database"]} -i db\\#{Rails.env}_structure.sql`
- when "oci", "oracle"
+ when /postgresql/
+ ENV['PGHOST'] = abcs['test']['host'] if abcs['test']['host']
+ ENV['PGPORT'] = abcs['test']['port'].to_s if abcs['test']['port']
+ ENV['PGPASSWORD'] = abcs['test']['password'].to_s if abcs['test']['password']
+ `psql -U "#{abcs['test']['username']}" -f #{Rails.root}/db/#{Rails.env}_structure.sql #{abcs['test']['database']} #{abcs['test']['template']}`
+ when /sqlite/
+ dbfile = abcs['test']['database'] || abcs['test']['dbfile']
+ `sqlite3 #{dbfile} < #{Rails.root}/db/#{Rails.env}_structure.sql`
+ when 'sqlserver'
+ `osql -E -S #{abcs['test']['host']} -d #{abcs['test']['database']} -i db\\#{Rails.env}_structure.sql`
+ when 'oci', 'oracle'
ActiveRecord::Base.establish_connection(:test)
IO.readlines("#{Rails.root}/db/#{Rails.env}_structure.sql").join.split(";\n\n").each do |ddl|
ActiveRecord::Base.connection.execute(ddl)
end
- when "firebird"
- set_firebird_env(abcs["test"])
- db_string = firebird_db_string(abcs["test"])
+ when 'firebird'
+ set_firebird_env(abcs['test'])
+ db_string = firebird_db_string(abcs['test'])
sh "isql -i #{Rails.root}/db/#{Rails.env}_structure.sql #{db_string}"
else
- raise "Task not supported by '#{abcs["test"]["adapter"]}'"
+ raise "Task not supported by '#{abcs['test']['adapter']}'"
end
end
# desc "Empty the test database"
task :purge => :environment do
abcs = ActiveRecord::Base.configurations
- case abcs["test"]["adapter"]
+ case abcs['test']['adapter']
when /mysql/
ActiveRecord::Base.establish_connection(:test)
- ActiveRecord::Base.connection.recreate_database(abcs["test"]["database"], abcs["test"])
- when "postgresql"
+ ActiveRecord::Base.connection.recreate_database(abcs['test']['database'], abcs['test'])
+ when /postgresql/
ActiveRecord::Base.clear_active_connections!
drop_database(abcs['test'])
create_database(abcs['test'])
- when "sqlite","sqlite3"
- dbfile = abcs["test"]["database"] || abcs["test"]["dbfile"]
+ when /sqlite/
+ dbfile = abcs['test']['database'] || abcs['test']['dbfile']
File.delete(dbfile) if File.exist?(dbfile)
- when "sqlserver"
- dropfkscript = "#{abcs["test"]["host"]}.#{abcs["test"]["database"]}.DP1".gsub(/\\/,'-')
- `osql -E -S #{abcs["test"]["host"]} -d #{abcs["test"]["database"]} -i db\\#{dropfkscript}`
- `osql -E -S #{abcs["test"]["host"]} -d #{abcs["test"]["database"]} -i db\\#{Rails.env}_structure.sql`
+ when 'sqlserver'
+ dropfkscript = "#{abcs['test']['host']}.#{abcs['test']['database']}.DP1".gsub(/\\/,'-')
+ `osql -E -S #{abcs['test']['host']} -d #{abcs['test']['database']} -i db\\#{dropfkscript}`
+ `osql -E -S #{abcs['test']['host']} -d #{abcs['test']['database']} -i db\\#{Rails.env}_structure.sql`
when "oci", "oracle"
ActiveRecord::Base.establish_connection(:test)
ActiveRecord::Base.connection.structure_drop.split(";\n\n").each do |ddl|
ActiveRecord::Base.connection.execute(ddl)
end
- when "firebird"
+ when 'firebird'
ActiveRecord::Base.establish_connection(:test)
ActiveRecord::Base.connection.recreate_database!
else
- raise "Task not supported by '#{abcs["test"]["adapter"]}'"
+ raise "Task not supported by '#{abcs['test']['adapter']}'"
end
end
# desc 'Check for pending migrations and load the test schema'
task :prepare => 'db:abort_if_pending_migrations' do
if defined?(ActiveRecord) && !ActiveRecord::Base.configurations.blank?
- db_namespace[{ :sql => "test:clone_structure", :ruby => "test:load" }[ActiveRecord::Base.schema_format]].invoke
+ db_namespace[{ :sql => 'test:clone_structure', :ruby => 'test:load' }[ActiveRecord::Base.schema_format]].invoke
end
end
end
@@ -479,11 +479,11 @@ db_namespace = namespace :db do
namespace :sessions do
# desc "Creates a sessions migration for use with ActiveRecord::SessionStore"
task :create => :environment do
- raise "Task unavailable to this database (no migration support)" unless ActiveRecord::Base.connection.supports_migrations?
+ raise 'Task unavailable to this database (no migration support)' unless ActiveRecord::Base.connection.supports_migrations?
require 'rails/generators'
Rails::Generators.configure!
require 'rails/generators/rails/session_migration/session_migration_generator'
- Rails::Generators::SessionMigrationGenerator.start [ ENV["MIGRATION"] || "add_sessions_table" ]
+ Rails::Generators::SessionMigrationGenerator.start [ ENV['MIGRATION'] || 'add_sessions_table' ]
end
# desc "Clear the sessions table"
@@ -496,13 +496,13 @@ end
namespace :railties do
namespace :install do
# desc "Copies missing migrations from Railties (e.g. plugins, engines). You can specify Railties to use with FROM=railtie1,railtie2"
- task :migrations => :"db:load_config" do
- to_load = ENV["FROM"].blank? ? :all : ENV["FROM"].split(",").map {|n| n.strip }
+ task :migrations => :'db:load_config' do
+ to_load = ENV['FROM'].blank? ? :all : ENV['FROM'].split(",").map {|n| n.strip }
railties = {}
Rails.application.railties.all do |railtie|
next unless to_load == :all || to_load.include?(railtie.railtie_name)
- if railtie.respond_to?(:paths) && (path = railtie.paths["db/migrate"].first)
+ if railtie.respond_to?(:paths) && (path = railtie.paths['db/migrate'].first)
railties[railtie.railtie_name] = path
end
end
@@ -528,13 +528,13 @@ def drop_database(config)
when /mysql/
ActiveRecord::Base.establish_connection(config)
ActiveRecord::Base.connection.drop_database config['database']
- when /^sqlite/
+ when /sqlite/
require 'pathname'
path = Pathname.new(config['database'])
file = path.absolute? ? path.to_s : File.join(Rails.root, path)
FileUtils.rm(file)
- when 'postgresql'
+ when /postgresql/
ActiveRecord::Base.establish_connection(config.merge('database' => 'postgres', 'schema_search_path' => 'public'))
ActiveRecord::Base.connection.drop_database config['database']
end
@@ -545,8 +545,8 @@ def session_table_name
end
def set_firebird_env(config)
- ENV["ISC_USER"] = config["username"].to_s if config["username"]
- ENV["ISC_PASSWORD"] = config["password"].to_s if config["password"]
+ ENV['ISC_USER'] = config['username'].to_s if config['username']
+ ENV['ISC_PASSWORD'] = config['password'].to_s if config['password']
end
def firebird_db_string(config)
diff --git a/activerecord/lib/active_record/relation.rb b/activerecord/lib/active_record/relation.rb
index 8e5f66ec1d..ae9afad48a 100644
--- a/activerecord/lib/active_record/relation.rb
+++ b/activerecord/lib/active_record/relation.rb
@@ -220,7 +220,7 @@ module ActiveRecord
stmt.take limit if limit
stmt.order(*order)
stmt.key = table[primary_key]
- @klass.connection.update stmt.to_sql
+ @klass.connection.update stmt.to_sql, 'SQL', bind_values
end
end
@@ -338,7 +338,9 @@ module ActiveRecord
where(conditions).delete_all
else
statement = arel.compile_delete
- affected = @klass.connection.delete statement.to_sql
+ affected = @klass.connection.delete(
+ statement.to_sql, 'SQL', bind_values)
+
reset
affected
end
diff --git a/activerecord/lib/active_record/relation/predicate_builder.rb b/activerecord/lib/active_record/relation/predicate_builder.rb
index 982b3d7e9f..2814771002 100644
--- a/activerecord/lib/active_record/relation/predicate_builder.rb
+++ b/activerecord/lib/active_record/relation/predicate_builder.rb
@@ -25,7 +25,18 @@ module ActiveRecord
values = value.to_a.map { |x|
x.is_a?(ActiveRecord::Base) ? x.id : x
}
- attribute.in(values)
+
+ if values.include?(nil)
+ values = values.compact
+ if values.empty?
+ attribute.eq nil
+ else
+ attribute.in(values.compact).or attribute.eq(nil)
+ end
+ else
+ attribute.in(values)
+ end
+
when Range, Arel::Relation
attribute.in(value)
when ActiveRecord::Base
diff --git a/activerecord/lib/active_record/validations.rb b/activerecord/lib/active_record/validations.rb
index d73fce9fd0..de36dd20b3 100644
--- a/activerecord/lib/active_record/validations.rb
+++ b/activerecord/lib/active_record/validations.rb
@@ -30,7 +30,7 @@ module ActiveRecord
include ActiveModel::Validations
module ClassMethods
- # Creates an object just like Base.create but calls save! instead of save
+ # Creates an object just like Base.create but calls <tt>save!</tt> instead of +save+
# so an exception is raised if the record is invalid.
def create!(attributes = nil, &block)
if attributes.is_a?(Array)
@@ -44,13 +44,13 @@ module ActiveRecord
end
end
- # The validation process on save can be skipped by passing :validate => false. The regular Base#save method is
+ # The validation process on save can be skipped by passing <tt>:validate => false</tt>. The regular Base#save method is
# replaced with this when the validations module is mixed in, which it is by default.
def save(options={})
perform_validations(options) ? super : false
end
- # Attempts to save the record just like Base#save but will raise a RecordInvalid exception instead of returning false
+ # Attempts to save the record just like Base#save but will raise a +RecordInvalid+ exception instead of returning false
# if the record is not valid.
def save!(options={})
perform_validations(options) ? super : raise(RecordInvalid.new(self))
diff --git a/activerecord/test/cases/associations/belongs_to_associations_test.rb b/activerecord/test/cases/associations/belongs_to_associations_test.rb
index 9006914508..ddcc36c841 100644
--- a/activerecord/test/cases/associations/belongs_to_associations_test.rb
+++ b/activerecord/test/cases/associations/belongs_to_associations_test.rb
@@ -580,7 +580,7 @@ class BelongsToAssociationsTest < ActiveRecord::TestCase
post = posts(:welcome)
comment = comments(:greetings)
- assert_difference 'post.reload.taggings_count', -1 do
+ assert_difference lambda { post.reload.taggings_count }, -1 do
assert_difference 'comment.reload.taggings_count', +1 do
tagging.taggable = comment
end
diff --git a/activerecord/test/cases/associations/eager_test.rb b/activerecord/test/cases/associations/eager_test.rb
index 9bc7910fc6..3e92a77830 100644
--- a/activerecord/test/cases/associations/eager_test.rb
+++ b/activerecord/test/cases/associations/eager_test.rb
@@ -170,10 +170,10 @@ class EagerAssociationTest < ActiveRecord::TestCase
assert_equal [comment], category.posts[0].comments
end
end
-
+
def test_associations_loaded_for_all_records
post = Post.create!(:title => 'foo', :body => "I like cars!")
- comment = SpecialComment.create!(:body => 'Come on!', :post => post)
+ SpecialComment.create!(:body => 'Come on!', :post => post)
first_category = Category.create! :name => 'First!', :posts => [post]
second_category = Category.create! :name => 'Second!', :posts => [post]
diff --git a/activerecord/test/cases/associations/has_many_through_associations_test.rb b/activerecord/test/cases/associations/has_many_through_associations_test.rb
index 70a4e06dbe..89117593fd 100644
--- a/activerecord/test/cases/associations/has_many_through_associations_test.rb
+++ b/activerecord/test/cases/associations/has_many_through_associations_test.rb
@@ -760,7 +760,7 @@ class HasManyThroughAssociationsTest < ActiveRecord::TestCase
def test_primary_key_option_on_source
post = posts(:welcome)
category = categories(:general)
- categorization = Categorization.create!(:post_id => post.id, :named_category_name => category.name)
+ Categorization.create!(:post_id => post.id, :named_category_name => category.name)
assert_equal [category], post.named_categories
assert_equal [category.name], post.named_category_ids # checks when target loaded
diff --git a/activerecord/test/cases/finder_test.rb b/activerecord/test/cases/finder_test.rb
index 655437318f..be4ba18555 100644
--- a/activerecord/test/cases/finder_test.rb
+++ b/activerecord/test/cases/finder_test.rb
@@ -1045,6 +1045,29 @@ class FinderTest < ActiveRecord::TestCase
:order => ' author_addresses_authors.id DESC ', :limit => 3).size
end
+ def test_find_with_nil_inside_set_passed_for_one_attribute
+ client_of = Company.find(
+ :all,
+ :conditions => {
+ :client_of => [2, 1, nil],
+ :name => ['37signals', 'Summit', 'Microsoft'] },
+ :order => 'client_of DESC'
+ ).map { |x| x.client_of }
+
+ assert client_of.include?(nil)
+ assert_equal [2, 1].sort, client_of.compact.sort
+ end
+
+ def test_find_with_nil_inside_set_passed_for_attribute
+ client_of = Company.find(
+ :all,
+ :conditions => { :client_of => [nil] },
+ :order => 'client_of DESC'
+ ).map { |x| x.client_of }
+
+ assert_equal [], client_of.compact
+ end
+
def test_with_limiting_with_custom_select
posts = Post.find(:all, :include => :author, :select => ' posts.*, authors.id as "author_id"', :limit => 3, :order => 'posts.id')
assert_equal 3, posts.size
diff --git a/activerecord/test/cases/fixtures_test.rb b/activerecord/test/cases/fixtures_test.rb
index fa40fad56d..3e20155210 100644
--- a/activerecord/test/cases/fixtures_test.rb
+++ b/activerecord/test/cases/fixtures_test.rb
@@ -45,6 +45,11 @@ class FixturesTest < ActiveRecord::TestCase
end
end
+ def test_create_fixtures
+ Fixtures.create_fixtures(FIXTURES_ROOT, "parrots")
+ assert Parrot.find_by_name('Curious George'), 'George is in the database'
+ end
+
def test_multiple_clean_fixtures
fixtures_array = nil
assert_nothing_raised { fixtures_array = create_fixtures(*FIXTURES) }
diff --git a/activerecord/test/cases/identity_map_test.rb b/activerecord/test/cases/identity_map_test.rb
index 199e59657d..2238529f0f 100644
--- a/activerecord/test/cases/identity_map_test.rb
+++ b/activerecord/test/cases/identity_map_test.rb
@@ -137,8 +137,6 @@ class IdentityMapTest < ActiveRecord::TestCase
assert_equal(["name"], swistak.changed)
assert_equal({"name" => ["Marcin Raczkowski", "Swistak Sreberkowiec"]}, swistak.changes)
- s = Subscriber.find('swistak')
-
assert swistak.name_changed?
assert_equal("Swistak Sreberkowiec", swistak.name)
end
@@ -149,8 +147,6 @@ class IdentityMapTest < ActiveRecord::TestCase
Subscriber.update_all({:name => "Raczkowski Marcin"}, {:name => "Marcin Raczkowski"})
- s = Subscriber.find('swistak')
-
assert_equal({"name"=>["Marcin Raczkowski", "Swistak Sreberkowiec"]}, swistak.changes)
assert_equal("Swistak Sreberkowiec", swistak.name)
end
@@ -163,8 +159,6 @@ class IdentityMapTest < ActiveRecord::TestCase
Subscriber.update_all({:name => "Swistak Sreberkowiec"}, {:name => "Marcin Raczkowski"})
- s = Subscriber.find('swistak')
-
assert_equal("Swistak Sreberkowiec", swistak.name)
assert_equal({"name"=>["Marcin Raczkowski", "Swistak Sreberkowiec"]}, swistak.changes)
assert swistak.name_changed?
@@ -175,7 +169,7 @@ class IdentityMapTest < ActiveRecord::TestCase
pirate.birds.create!(:name => 'Posideons Killer')
pirate.birds.create!(:name => 'Killer bandita Dionne')
- posideons, killer = pirate.birds
+ posideons, _ = pirate.birds
pirate.reload