activerecord 4.0.13 → 4.1.0.beta1

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of activerecord might be problematic. Click here for more details.

Files changed (135) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +745 -2700
  3. data/README.rdoc +2 -2
  4. data/examples/performance.rb +30 -18
  5. data/examples/simple.rb +4 -4
  6. data/lib/active_record.rb +2 -6
  7. data/lib/active_record/aggregations.rb +2 -1
  8. data/lib/active_record/association_relation.rb +0 -4
  9. data/lib/active_record/associations.rb +87 -43
  10. data/lib/active_record/associations/alias_tracker.rb +1 -3
  11. data/lib/active_record/associations/association.rb +8 -16
  12. data/lib/active_record/associations/association_scope.rb +5 -16
  13. data/lib/active_record/associations/belongs_to_association.rb +34 -25
  14. data/lib/active_record/associations/belongs_to_polymorphic_association.rb +1 -1
  15. data/lib/active_record/associations/builder/association.rb +78 -54
  16. data/lib/active_record/associations/builder/belongs_to.rb +91 -58
  17. data/lib/active_record/associations/builder/collection_association.rb +47 -45
  18. data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +107 -25
  19. data/lib/active_record/associations/builder/has_many.rb +2 -2
  20. data/lib/active_record/associations/builder/has_one.rb +5 -7
  21. data/lib/active_record/associations/builder/singular_association.rb +6 -7
  22. data/lib/active_record/associations/collection_association.rb +68 -105
  23. data/lib/active_record/associations/collection_proxy.rb +12 -15
  24. data/lib/active_record/associations/has_many_association.rb +11 -9
  25. data/lib/active_record/associations/has_many_through_association.rb +16 -12
  26. data/lib/active_record/associations/has_one_association.rb +1 -1
  27. data/lib/active_record/associations/join_dependency.rb +204 -165
  28. data/lib/active_record/associations/join_dependency/join_association.rb +43 -101
  29. data/lib/active_record/associations/join_dependency/join_base.rb +6 -8
  30. data/lib/active_record/associations/join_dependency/join_part.rb +18 -37
  31. data/lib/active_record/associations/join_helper.rb +2 -11
  32. data/lib/active_record/associations/preloader.rb +89 -34
  33. data/lib/active_record/associations/preloader/association.rb +43 -25
  34. data/lib/active_record/associations/preloader/collection_association.rb +2 -2
  35. data/lib/active_record/associations/preloader/has_many_through.rb +1 -1
  36. data/lib/active_record/associations/preloader/singular_association.rb +3 -3
  37. data/lib/active_record/associations/preloader/through_association.rb +58 -26
  38. data/lib/active_record/associations/singular_association.rb +6 -5
  39. data/lib/active_record/associations/through_association.rb +2 -2
  40. data/lib/active_record/attribute_assignment.rb +5 -2
  41. data/lib/active_record/attribute_methods.rb +45 -40
  42. data/lib/active_record/attribute_methods/before_type_cast.rb +2 -1
  43. data/lib/active_record/attribute_methods/dirty.rb +8 -22
  44. data/lib/active_record/attribute_methods/primary_key.rb +1 -7
  45. data/lib/active_record/attribute_methods/read.rb +55 -28
  46. data/lib/active_record/attribute_methods/serialization.rb +12 -33
  47. data/lib/active_record/attribute_methods/time_zone_conversion.rb +1 -13
  48. data/lib/active_record/attribute_methods/write.rb +37 -12
  49. data/lib/active_record/autosave_association.rb +207 -207
  50. data/lib/active_record/base.rb +5 -1
  51. data/lib/active_record/callbacks.rb +2 -2
  52. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +2 -7
  53. data/lib/active_record/connection_adapters/abstract/database_statements.rb +11 -22
  54. data/lib/active_record/connection_adapters/abstract/query_cache.rb +12 -14
  55. data/lib/active_record/connection_adapters/abstract/quoting.rb +1 -5
  56. data/lib/active_record/connection_adapters/abstract/savepoints.rb +21 -0
  57. data/lib/active_record/connection_adapters/abstract/schema_creation.rb +84 -0
  58. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +9 -8
  59. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +52 -83
  60. data/lib/active_record/connection_adapters/abstract/transaction.rb +0 -5
  61. data/lib/active_record/connection_adapters/abstract_adapter.rb +14 -97
  62. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +58 -60
  63. data/lib/active_record/connection_adapters/column.rb +1 -35
  64. data/lib/active_record/connection_adapters/connection_specification.rb +2 -2
  65. data/lib/active_record/connection_adapters/mysql2_adapter.rb +3 -4
  66. data/lib/active_record/connection_adapters/mysql_adapter.rb +16 -15
  67. data/lib/active_record/connection_adapters/postgresql/array_parser.rb +24 -18
  68. data/lib/active_record/connection_adapters/postgresql/cast.rb +20 -16
  69. data/lib/active_record/connection_adapters/postgresql/database_statements.rb +23 -43
  70. data/lib/active_record/connection_adapters/postgresql/oid.rb +19 -12
  71. data/lib/active_record/connection_adapters/postgresql/quoting.rb +28 -23
  72. data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +8 -30
  73. data/lib/active_record/connection_adapters/postgresql_adapter.rb +92 -75
  74. data/lib/active_record/connection_adapters/schema_cache.rb +8 -29
  75. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +31 -64
  76. data/lib/active_record/connection_handling.rb +2 -2
  77. data/lib/active_record/core.rb +22 -43
  78. data/lib/active_record/counter_cache.rb +7 -7
  79. data/lib/active_record/enum.rb +100 -0
  80. data/lib/active_record/errors.rb +10 -5
  81. data/lib/active_record/fixture_set/file.rb +2 -1
  82. data/lib/active_record/fixtures.rb +171 -74
  83. data/lib/active_record/inheritance.rb +16 -22
  84. data/lib/active_record/integration.rb +52 -1
  85. data/lib/active_record/locking/optimistic.rb +7 -2
  86. data/lib/active_record/locking/pessimistic.rb +1 -1
  87. data/lib/active_record/log_subscriber.rb +5 -12
  88. data/lib/active_record/migration.rb +62 -46
  89. data/lib/active_record/migration/command_recorder.rb +7 -13
  90. data/lib/active_record/model_schema.rb +7 -14
  91. data/lib/active_record/nested_attributes.rb +10 -8
  92. data/lib/active_record/no_touching.rb +52 -0
  93. data/lib/active_record/null_relation.rb +3 -3
  94. data/lib/active_record/persistence.rb +16 -34
  95. data/lib/active_record/querying.rb +14 -12
  96. data/lib/active_record/railtie.rb +0 -50
  97. data/lib/active_record/railties/databases.rake +12 -15
  98. data/lib/active_record/readonly_attributes.rb +0 -6
  99. data/lib/active_record/reflection.rb +189 -75
  100. data/lib/active_record/relation.rb +69 -94
  101. data/lib/active_record/relation/batches.rb +57 -23
  102. data/lib/active_record/relation/calculations.rb +36 -43
  103. data/lib/active_record/relation/delegation.rb +54 -39
  104. data/lib/active_record/relation/finder_methods.rb +107 -62
  105. data/lib/active_record/relation/merger.rb +7 -20
  106. data/lib/active_record/relation/predicate_builder.rb +57 -38
  107. data/lib/active_record/relation/predicate_builder/array_handler.rb +29 -0
  108. data/lib/active_record/relation/predicate_builder/relation_handler.rb +13 -0
  109. data/lib/active_record/relation/query_methods.rb +110 -98
  110. data/lib/active_record/relation/spawn_methods.rb +1 -2
  111. data/lib/active_record/result.rb +45 -6
  112. data/lib/active_record/runtime_registry.rb +5 -0
  113. data/lib/active_record/sanitization.rb +6 -8
  114. data/lib/active_record/schema_dumper.rb +16 -5
  115. data/lib/active_record/schema_migration.rb +24 -25
  116. data/lib/active_record/scoping/default.rb +5 -18
  117. data/lib/active_record/scoping/named.rb +8 -29
  118. data/lib/active_record/store.rb +56 -28
  119. data/lib/active_record/tasks/database_tasks.rb +8 -4
  120. data/lib/active_record/timestamp.rb +4 -4
  121. data/lib/active_record/transactions.rb +8 -10
  122. data/lib/active_record/validations/presence.rb +1 -1
  123. data/lib/active_record/validations/uniqueness.rb +1 -6
  124. data/lib/active_record/version.rb +1 -1
  125. data/lib/rails/generators/active_record.rb +2 -8
  126. data/lib/rails/generators/active_record/migration.rb +18 -0
  127. data/lib/rails/generators/active_record/migration/migration_generator.rb +4 -0
  128. data/lib/rails/generators/active_record/model/model_generator.rb +4 -0
  129. metadata +32 -45
  130. data/lib/active_record/associations/has_and_belongs_to_many_association.rb +0 -65
  131. data/lib/active_record/associations/preloader/has_and_belongs_to_many.rb +0 -60
  132. data/lib/active_record/tasks/firebird_database_tasks.rb +0 -56
  133. data/lib/active_record/tasks/oracle_database_tasks.rb +0 -45
  134. data/lib/active_record/tasks/sqlserver_database_tasks.rb +0 -48
  135. data/lib/active_record/test_case.rb +0 -102
@@ -1,65 +0,0 @@
1
- module ActiveRecord
2
- # = Active Record Has And Belongs To Many Association
3
- module Associations
4
- class HasAndBelongsToManyAssociation < CollectionAssociation #:nodoc:
5
- attr_reader :join_table
6
-
7
- def initialize(owner, reflection)
8
- @join_table = Arel::Table.new(reflection.join_table)
9
- super
10
- end
11
-
12
- def insert_record(record, validate = true, raise = false)
13
- if record.new_record?
14
- if raise
15
- record.save!(:validate => validate)
16
- else
17
- return unless record.save(:validate => validate)
18
- end
19
- end
20
-
21
- if options[:insert_sql]
22
- owner.connection.insert(interpolate(options[:insert_sql], record))
23
- else
24
- stmt = join_table.compile_insert(
25
- join_table[reflection.foreign_key] => owner.id,
26
- join_table[reflection.association_foreign_key] => record.id
27
- )
28
-
29
- owner.class.connection.insert stmt
30
- end
31
-
32
- record
33
- end
34
-
35
- private
36
-
37
- def count_records
38
- load_target.reject { |r| r.new_record? }.size
39
- end
40
-
41
- def delete_records(records, method)
42
- if sql = options[:delete_sql]
43
- records = load_target if records == :all
44
- records.each { |record| owner.class.connection.delete(interpolate(sql, record)) }
45
- else
46
- relation = join_table
47
- condition = relation[reflection.foreign_key].eq(owner.id)
48
-
49
- unless records == :all
50
- condition = condition.and(
51
- relation[reflection.association_foreign_key]
52
- .in(records.map { |x| x.id }.compact)
53
- )
54
- end
55
-
56
- owner.class.connection.delete(relation.where(condition).compile_delete)
57
- end
58
- end
59
-
60
- def invertible_for?(record)
61
- false
62
- end
63
- end
64
- end
65
- end
@@ -1,60 +0,0 @@
1
- module ActiveRecord
2
- module Associations
3
- class Preloader
4
- class HasAndBelongsToMany < CollectionAssociation #:nodoc:
5
- attr_reader :join_table
6
-
7
- def initialize(klass, records, reflection, preload_options)
8
- super
9
- @join_table = Arel::Table.new(reflection.join_table).alias('t0')
10
- end
11
-
12
- # Unlike the other associations, we want to get a raw array of rows so that we can
13
- # access the aliased column on the join table
14
- def records_for(ids)
15
- scope = super
16
- klass.connection.select_all(scope.arel, 'SQL', scope.bind_values)
17
- end
18
-
19
- def owner_key_name
20
- reflection.active_record_primary_key
21
- end
22
-
23
- def association_key_name
24
- 'ar_association_key_name'
25
- end
26
-
27
- def association_key
28
- join_table[reflection.foreign_key]
29
- end
30
-
31
- private
32
-
33
- # Once we have used the join table column (in super), we manually instantiate the
34
- # actual records, ensuring that we don't create more than one instances of the same
35
- # record
36
- def associated_records_by_owner
37
- records = {}
38
- super.each_value do |rows|
39
- rows.map! { |row| records[row[klass.primary_key]] ||= klass.instantiate(row) }
40
- end
41
- end
42
-
43
- def build_scope
44
- super.joins(join).select(join_select)
45
- end
46
-
47
- def join_select
48
- association_key.as(Arel.sql(association_key_name))
49
- end
50
-
51
- def join
52
- condition = table[reflection.association_primary_key].eq(
53
- join_table[reflection.association_foreign_key])
54
-
55
- table.create_join(join_table, table.create_on(condition))
56
- end
57
- end
58
- end
59
- end
60
- end
@@ -1,56 +0,0 @@
1
- module ActiveRecord
2
- module Tasks # :nodoc:
3
- class FirebirdDatabaseTasks # :nodoc:
4
- delegate :connection, :establish_connection, to: ActiveRecord::Base
5
-
6
- def initialize(configuration)
7
- ActiveSupport::Deprecation.warn "This database tasks were deprecated, because this tasks should be served by the 3rd party adapter."
8
- @configuration = configuration
9
- end
10
-
11
- def create
12
- $stderr.puts 'sorry, your database adapter is not supported yet, feel free to submit a patch'
13
- end
14
-
15
- def drop
16
- $stderr.puts 'sorry, your database adapter is not supported yet, feel free to submit a patch'
17
- end
18
-
19
- def purge
20
- establish_connection(:test)
21
- connection.recreate_database!
22
- end
23
-
24
- def charset
25
- $stderr.puts 'sorry, your database adapter is not supported yet, feel free to submit a patch'
26
- end
27
-
28
- def structure_dump(filename)
29
- set_firebird_env(configuration)
30
- db_string = firebird_db_string(configuration)
31
- Kernel.system "isql -a #{db_string} > #{filename}"
32
- end
33
-
34
- def structure_load(filename)
35
- set_firebird_env(configuration)
36
- db_string = firebird_db_string(configuration)
37
- Kernel.system "isql -i #{filename} #{db_string}"
38
- end
39
-
40
- private
41
-
42
- def set_firebird_env(config)
43
- ENV['ISC_USER'] = config['username'].to_s if config['username']
44
- ENV['ISC_PASSWORD'] = config['password'].to_s if config['password']
45
- end
46
-
47
- def firebird_db_string(config)
48
- FireRuby::Database.db_string_for(config.symbolize_keys)
49
- end
50
-
51
- def configuration
52
- @configuration
53
- end
54
- end
55
- end
56
- end
@@ -1,45 +0,0 @@
1
- module ActiveRecord
2
- module Tasks # :nodoc:
3
- class OracleDatabaseTasks # :nodoc:
4
- delegate :connection, :establish_connection, to: ActiveRecord::Base
5
-
6
- def initialize(configuration)
7
- ActiveSupport::Deprecation.warn "This database tasks were deprecated, because this tasks should be served by the 3rd party adapter."
8
- @configuration = configuration
9
- end
10
-
11
- def create
12
- $stderr.puts 'sorry, your database adapter is not supported yet, feel free to submit a patch'
13
- end
14
-
15
- def drop
16
- $stderr.puts 'sorry, your database adapter is not supported yet, feel free to submit a patch'
17
- end
18
-
19
- def purge
20
- establish_connection(:test)
21
- connection.structure_drop.split(";\n\n").each { |ddl| connection.execute(ddl) }
22
- end
23
-
24
- def charset
25
- $stderr.puts 'sorry, your database adapter is not supported yet, feel free to submit a patch'
26
- end
27
-
28
- def structure_dump(filename)
29
- establish_connection(configuration)
30
- File.open(filename, "w:utf-8") { |f| f << connection.structure_dump }
31
- end
32
-
33
- def structure_load(filename)
34
- establish_connection(configuration)
35
- IO.read(filename).split(";\n\n").each { |ddl| connection.execute(ddl) }
36
- end
37
-
38
- private
39
-
40
- def configuration
41
- @configuration
42
- end
43
- end
44
- end
45
- end
@@ -1,48 +0,0 @@
1
- require 'shellwords'
2
-
3
- module ActiveRecord
4
- module Tasks # :nodoc:
5
- class SqlserverDatabaseTasks # :nodoc:
6
- delegate :connection, :establish_connection, to: ActiveRecord::Base
7
-
8
- def initialize(configuration)
9
- ActiveSupport::Deprecation.warn "This database tasks were deprecated, because this tasks should be served by the 3rd party adapter."
10
- @configuration = configuration
11
- end
12
-
13
- def create
14
- $stderr.puts 'sorry, your database adapter is not supported yet, feel free to submit a patch'
15
- end
16
-
17
- def drop
18
- $stderr.puts 'sorry, your database adapter is not supported yet, feel free to submit a patch'
19
- end
20
-
21
- def purge
22
- test = configuration.deep_dup
23
- test_database = test['database']
24
- test['database'] = 'master'
25
- establish_connection(test)
26
- connection.recreate_database!(test_database)
27
- end
28
-
29
- def charset
30
- $stderr.puts 'sorry, your database adapter is not supported yet, feel free to submit a patch'
31
- end
32
-
33
- def structure_dump(filename)
34
- Kernel.system("smoscript -s #{configuration['host']} -d #{configuration['database']} -u #{configuration['username']} -p #{configuration['password']} -f #{filename} -A -U")
35
- end
36
-
37
- def structure_load(filename)
38
- Kernel.system("sqlcmd -S #{configuration['host']} -d #{configuration['database']} -U #{configuration['username']} -P #{configuration['password']} -i #{filename}")
39
- end
40
-
41
- private
42
-
43
- def configuration
44
- @configuration
45
- end
46
- end
47
- end
48
- end
@@ -1,102 +0,0 @@
1
- require 'active_support/test_case'
2
-
3
- ActiveSupport::Deprecation.warn('ActiveRecord::TestCase is deprecated, please use ActiveSupport::TestCase')
4
- module ActiveRecord
5
- # = Active Record Test Case
6
- #
7
- # Defines some test assertions to test against SQL queries.
8
- class TestCase < ActiveSupport::TestCase #:nodoc:
9
- def teardown
10
- SQLCounter.clear_log
11
- end
12
-
13
- def assert_date_from_db(expected, actual, message = nil)
14
- # SybaseAdapter doesn't have a separate column type just for dates,
15
- # so the time is in the string and incorrectly formatted
16
- if current_adapter?(:SybaseAdapter)
17
- assert_equal expected.to_s, actual.to_date.to_s, message
18
- else
19
- assert_equal expected.to_s, actual.to_s, message
20
- end
21
- end
22
-
23
- def capture_sql
24
- SQLCounter.clear_log
25
- yield
26
- SQLCounter.log_all.dup
27
- end
28
-
29
- def assert_sql(*patterns_to_match)
30
- SQLCounter.clear_log
31
- yield
32
- SQLCounter.log_all
33
- ensure
34
- failed_patterns = []
35
- patterns_to_match.each do |pattern|
36
- failed_patterns << pattern unless SQLCounter.log_all.any?{ |sql| pattern === sql }
37
- end
38
- assert failed_patterns.empty?, "Query pattern(s) #{failed_patterns.map{ |p| p.inspect }.join(', ')} not found.#{SQLCounter.log.size == 0 ? '' : "\nQueries:\n#{SQLCounter.log.join("\n")}"}"
39
- end
40
-
41
- def assert_queries(num = 1, options = {})
42
- ignore_none = options.fetch(:ignore_none) { num == :any }
43
- SQLCounter.clear_log
44
- yield
45
- ensure
46
- the_log = ignore_none ? SQLCounter.log_all : SQLCounter.log
47
- if num == :any
48
- assert_operator the_log.size, :>=, 1, "1 or more queries expected, but none were executed."
49
- else
50
- mesg = "#{the_log.size} instead of #{num} queries were executed.#{the_log.size == 0 ? '' : "\nQueries:\n#{the_log.join("\n")}"}"
51
- assert_equal num, the_log.size, mesg
52
- end
53
- end
54
-
55
- def assert_no_queries(&block)
56
- assert_queries(0, :ignore_none => true, &block)
57
- end
58
-
59
- end
60
-
61
- class SQLCounter
62
- class << self
63
- attr_accessor :ignored_sql, :log, :log_all
64
- def clear_log; self.log = []; self.log_all = []; end
65
- end
66
-
67
- self.clear_log
68
-
69
- self.ignored_sql = [/^PRAGMA/, /^SELECT currval/, /^SELECT CAST/, /^SELECT @@IDENTITY/, /^SELECT @@ROWCOUNT/, /^SAVEPOINT/, /^ROLLBACK TO SAVEPOINT/, /^RELEASE SAVEPOINT/, /^SHOW max_identifier_length/, /^BEGIN/, /^COMMIT/]
70
-
71
- # FIXME: this needs to be refactored so specific database can add their own
72
- # ignored SQL, or better yet, use a different notification for the queries
73
- # instead examining the SQL content.
74
- oracle_ignored = [/^select .*nextval/i, /^SAVEPOINT/, /^ROLLBACK TO/, /^\s*select .* from all_triggers/im]
75
- mysql_ignored = [/^SHOW TABLES/i, /^SHOW FULL FIELDS/]
76
- postgresql_ignored = [/^\s*select\b.*\bfrom\b.*pg_namespace\b/im, /^\s*select\b.*\battname\b.*\bfrom\b.*\bpg_attribute\b/im, /^SHOW search_path/i]
77
- sqlite3_ignored = [/^\s*SELECT name\b.*\bFROM sqlite_master/im]
78
-
79
- [oracle_ignored, mysql_ignored, postgresql_ignored, sqlite3_ignored].each do |db_ignored_sql|
80
- ignored_sql.concat db_ignored_sql
81
- end
82
-
83
- attr_reader :ignore
84
-
85
- def initialize(ignore = Regexp.union(self.class.ignored_sql))
86
- @ignore = ignore
87
- end
88
-
89
- def call(name, start, finish, message_id, values)
90
- sql = values[:sql]
91
-
92
- # FIXME: this seems bad. we should probably have a better way to indicate
93
- # the query was cached
94
- return if 'CACHE' == values[:name]
95
-
96
- self.class.log_all << sql
97
- self.class.log << sql unless ignore =~ sql
98
- end
99
- end
100
-
101
- ActiveSupport::Notifications.subscribe('sql.active_record', SQLCounter.new)
102
- end