activerecord 4.0.4 → 4.1.16

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 (143) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +1632 -1797
  3. data/MIT-LICENSE +1 -1
  4. data/README.rdoc +2 -2
  5. data/examples/performance.rb +30 -18
  6. data/examples/simple.rb +4 -4
  7. data/lib/active_record/aggregations.rb +2 -1
  8. data/lib/active_record/association_relation.rb +4 -0
  9. data/lib/active_record/associations/alias_tracker.rb +49 -29
  10. data/lib/active_record/associations/association.rb +9 -17
  11. data/lib/active_record/associations/association_scope.rb +59 -49
  12. data/lib/active_record/associations/belongs_to_association.rb +34 -25
  13. data/lib/active_record/associations/belongs_to_polymorphic_association.rb +6 -1
  14. data/lib/active_record/associations/builder/association.rb +84 -54
  15. data/lib/active_record/associations/builder/belongs_to.rb +90 -58
  16. data/lib/active_record/associations/builder/collection_association.rb +47 -45
  17. data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +119 -25
  18. data/lib/active_record/associations/builder/has_many.rb +3 -3
  19. data/lib/active_record/associations/builder/has_one.rb +5 -7
  20. data/lib/active_record/associations/builder/singular_association.rb +6 -7
  21. data/lib/active_record/associations/collection_association.rb +121 -111
  22. data/lib/active_record/associations/collection_proxy.rb +73 -18
  23. data/lib/active_record/associations/has_many_association.rb +14 -11
  24. data/lib/active_record/associations/has_many_through_association.rb +33 -6
  25. data/lib/active_record/associations/has_one_association.rb +1 -1
  26. data/lib/active_record/associations/join_dependency/join_association.rb +46 -104
  27. data/lib/active_record/associations/join_dependency/join_base.rb +6 -8
  28. data/lib/active_record/associations/join_dependency/join_part.rb +18 -37
  29. data/lib/active_record/associations/join_dependency.rb +208 -168
  30. data/lib/active_record/associations/preloader/association.rb +69 -27
  31. data/lib/active_record/associations/preloader/collection_association.rb +2 -2
  32. data/lib/active_record/associations/preloader/has_many_through.rb +1 -1
  33. data/lib/active_record/associations/preloader/singular_association.rb +3 -3
  34. data/lib/active_record/associations/preloader/through_association.rb +58 -26
  35. data/lib/active_record/associations/preloader.rb +63 -49
  36. data/lib/active_record/associations/singular_association.rb +6 -5
  37. data/lib/active_record/associations/through_association.rb +30 -9
  38. data/lib/active_record/associations.rb +116 -42
  39. data/lib/active_record/attribute_assignment.rb +6 -3
  40. data/lib/active_record/attribute_methods/before_type_cast.rb +2 -1
  41. data/lib/active_record/attribute_methods/dirty.rb +35 -26
  42. data/lib/active_record/attribute_methods/primary_key.rb +8 -1
  43. data/lib/active_record/attribute_methods/read.rb +56 -29
  44. data/lib/active_record/attribute_methods/serialization.rb +44 -12
  45. data/lib/active_record/attribute_methods/time_zone_conversion.rb +13 -1
  46. data/lib/active_record/attribute_methods/write.rb +59 -26
  47. data/lib/active_record/attribute_methods.rb +82 -43
  48. data/lib/active_record/autosave_association.rb +209 -194
  49. data/lib/active_record/base.rb +6 -2
  50. data/lib/active_record/callbacks.rb +2 -2
  51. data/lib/active_record/coders/json.rb +13 -0
  52. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +5 -10
  53. data/lib/active_record/connection_adapters/abstract/database_statements.rb +14 -24
  54. data/lib/active_record/connection_adapters/abstract/query_cache.rb +13 -13
  55. data/lib/active_record/connection_adapters/abstract/quoting.rb +6 -3
  56. data/lib/active_record/connection_adapters/abstract/savepoints.rb +21 -0
  57. data/lib/active_record/connection_adapters/abstract/schema_creation.rb +90 -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 +45 -70
  60. data/lib/active_record/connection_adapters/abstract/transaction.rb +1 -0
  61. data/lib/active_record/connection_adapters/abstract_adapter.rb +28 -96
  62. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +74 -66
  63. data/lib/active_record/connection_adapters/column.rb +1 -35
  64. data/lib/active_record/connection_adapters/connection_specification.rb +231 -43
  65. data/lib/active_record/connection_adapters/mysql2_adapter.rb +10 -5
  66. data/lib/active_record/connection_adapters/mysql_adapter.rb +24 -17
  67. data/lib/active_record/connection_adapters/postgresql/array_parser.rb +22 -15
  68. data/lib/active_record/connection_adapters/postgresql/cast.rb +12 -4
  69. data/lib/active_record/connection_adapters/postgresql/database_statements.rb +18 -44
  70. data/lib/active_record/connection_adapters/postgresql/oid.rb +38 -14
  71. data/lib/active_record/connection_adapters/postgresql/quoting.rb +37 -12
  72. data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +20 -11
  73. data/lib/active_record/connection_adapters/postgresql_adapter.rb +98 -52
  74. data/lib/active_record/connection_adapters/schema_cache.rb +8 -29
  75. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +55 -60
  76. data/lib/active_record/connection_handling.rb +39 -5
  77. data/lib/active_record/core.rb +38 -54
  78. data/lib/active_record/counter_cache.rb +9 -10
  79. data/lib/active_record/dynamic_matchers.rb +6 -2
  80. data/lib/active_record/enum.rb +199 -0
  81. data/lib/active_record/errors.rb +22 -5
  82. data/lib/active_record/fixture_set/file.rb +2 -1
  83. data/lib/active_record/fixtures.rb +173 -76
  84. data/lib/active_record/gem_version.rb +15 -0
  85. data/lib/active_record/inheritance.rb +23 -9
  86. data/lib/active_record/integration.rb +54 -1
  87. data/lib/active_record/locking/optimistic.rb +7 -2
  88. data/lib/active_record/locking/pessimistic.rb +1 -1
  89. data/lib/active_record/log_subscriber.rb +6 -13
  90. data/lib/active_record/migration/command_recorder.rb +8 -2
  91. data/lib/active_record/migration.rb +91 -56
  92. data/lib/active_record/model_schema.rb +7 -14
  93. data/lib/active_record/nested_attributes.rb +25 -13
  94. data/lib/active_record/no_touching.rb +52 -0
  95. data/lib/active_record/null_relation.rb +26 -6
  96. data/lib/active_record/persistence.rb +23 -29
  97. data/lib/active_record/querying.rb +15 -12
  98. data/lib/active_record/railtie.rb +12 -61
  99. data/lib/active_record/railties/databases.rake +37 -56
  100. data/lib/active_record/readonly_attributes.rb +0 -6
  101. data/lib/active_record/reflection.rb +230 -79
  102. data/lib/active_record/relation/batches.rb +74 -24
  103. data/lib/active_record/relation/calculations.rb +52 -48
  104. data/lib/active_record/relation/delegation.rb +54 -39
  105. data/lib/active_record/relation/finder_methods.rb +210 -67
  106. data/lib/active_record/relation/merger.rb +15 -12
  107. data/lib/active_record/relation/predicate_builder/array_handler.rb +29 -0
  108. data/lib/active_record/relation/predicate_builder/relation_handler.rb +17 -0
  109. data/lib/active_record/relation/predicate_builder.rb +81 -40
  110. data/lib/active_record/relation/query_methods.rb +185 -108
  111. data/lib/active_record/relation/spawn_methods.rb +8 -5
  112. data/lib/active_record/relation.rb +79 -84
  113. data/lib/active_record/result.rb +45 -6
  114. data/lib/active_record/runtime_registry.rb +5 -0
  115. data/lib/active_record/sanitization.rb +4 -4
  116. data/lib/active_record/schema_dumper.rb +18 -6
  117. data/lib/active_record/schema_migration.rb +31 -18
  118. data/lib/active_record/scoping/default.rb +5 -18
  119. data/lib/active_record/scoping/named.rb +14 -29
  120. data/lib/active_record/scoping.rb +5 -0
  121. data/lib/active_record/store.rb +67 -18
  122. data/lib/active_record/tasks/database_tasks.rb +66 -26
  123. data/lib/active_record/tasks/mysql_database_tasks.rb +16 -10
  124. data/lib/active_record/tasks/postgresql_database_tasks.rb +1 -1
  125. data/lib/active_record/tasks/sqlite_database_tasks.rb +5 -1
  126. data/lib/active_record/timestamp.rb +6 -6
  127. data/lib/active_record/transactions.rb +10 -12
  128. data/lib/active_record/validations/presence.rb +1 -1
  129. data/lib/active_record/validations/uniqueness.rb +19 -9
  130. data/lib/active_record/version.rb +4 -7
  131. data/lib/active_record.rb +5 -7
  132. data/lib/rails/generators/active_record/migration/migration_generator.rb +4 -0
  133. data/lib/rails/generators/active_record/migration.rb +18 -0
  134. data/lib/rails/generators/active_record/model/model_generator.rb +4 -0
  135. data/lib/rails/generators/active_record.rb +2 -8
  136. metadata +18 -30
  137. data/lib/active_record/associations/has_and_belongs_to_many_association.rb +0 -65
  138. data/lib/active_record/associations/join_helper.rb +0 -45
  139. data/lib/active_record/associations/preloader/has_and_belongs_to_many.rb +0 -60
  140. data/lib/active_record/tasks/firebird_database_tasks.rb +0 -56
  141. data/lib/active_record/tasks/oracle_database_tasks.rb +0 -45
  142. data/lib/active_record/tasks/sqlserver_database_tasks.rb +0 -48
  143. data/lib/active_record/test_case.rb +0 -96
@@ -15,6 +15,11 @@ module ActiveRecord
15
15
  # You can set custom coder to encode/decode your serialized attributes to/from different formats.
16
16
  # JSON, YAML, Marshal are supported out of the box. Generally it can be any wrapper that provides +load+ and +dump+.
17
17
  #
18
+ # NOTE - If you are using PostgreSQL specific columns like +hstore+ or +json+ there is no need for
19
+ # the serialization provided by +store+. Simply use +store_accessor+ instead to generate
20
+ # the accessor methods. Be aware that these columns use a string keyed hash and do not allow access
21
+ # using a symbol.
22
+ #
18
23
  # Examples:
19
24
  #
20
25
  # class User < ActiveRecord::Base
@@ -61,8 +66,9 @@ module ActiveRecord
61
66
  extend ActiveSupport::Concern
62
67
 
63
68
  included do
64
- class_attribute :stored_attributes, instance_accessor: false
65
- self.stored_attributes = {}
69
+ class << self
70
+ attr_accessor :local_stored_attributes
71
+ end
66
72
  end
67
73
 
68
74
  module ClassMethods
@@ -86,8 +92,11 @@ module ActiveRecord
86
92
  end
87
93
  end
88
94
 
89
- self.stored_attributes[store_attribute] ||= []
90
- self.stored_attributes[store_attribute] |= keys
95
+ # assign new store attribute and create new hash to ensure that each class in the hierarchy
96
+ # has its own hash of stored attributes.
97
+ self.local_stored_attributes ||= {}
98
+ self.local_stored_attributes[store_attribute] ||= []
99
+ self.local_stored_attributes[store_attribute] |= keys
91
100
  end
92
101
 
93
102
  def _store_accessors_module
@@ -97,30 +106,70 @@ module ActiveRecord
97
106
  mod
98
107
  end
99
108
  end
109
+
110
+ def stored_attributes
111
+ parent = superclass.respond_to?(:stored_attributes) ? superclass.stored_attributes : {}
112
+ if self.local_stored_attributes
113
+ parent.merge!(self.local_stored_attributes) { |k, a, b| a | b }
114
+ end
115
+ parent
116
+ end
100
117
  end
101
118
 
102
119
  protected
103
120
  def read_store_attribute(store_attribute, key)
104
- attribute = initialize_store_attribute(store_attribute)
105
- attribute[key]
121
+ accessor = store_accessor_for(store_attribute)
122
+ accessor.read(self, store_attribute, key)
106
123
  end
107
124
 
108
125
  def write_store_attribute(store_attribute, key, value)
109
- attribute = initialize_store_attribute(store_attribute)
110
- if value != attribute[key]
111
- send :"#{store_attribute}_will_change!"
112
- attribute[key] = value
113
- end
126
+ accessor = store_accessor_for(store_attribute)
127
+ accessor.write(self, store_attribute, key, value)
114
128
  end
115
129
 
116
130
  private
117
- def initialize_store_attribute(store_attribute)
118
- attribute = send(store_attribute)
119
- unless attribute.is_a?(ActiveSupport::HashWithIndifferentAccess)
120
- attribute = IndifferentCoder.as_indifferent_hash(attribute)
121
- send :"#{store_attribute}=", attribute
131
+ def store_accessor_for(store_attribute)
132
+ @column_types[store_attribute.to_s].accessor
133
+ end
134
+
135
+ class HashAccessor
136
+ def self.read(object, attribute, key)
137
+ prepare(object, attribute)
138
+ object.public_send(attribute)[key]
139
+ end
140
+
141
+ def self.write(object, attribute, key, value)
142
+ prepare(object, attribute)
143
+ if value != read(object, attribute, key)
144
+ object.public_send :"#{attribute}_will_change!"
145
+ object.public_send(attribute)[key] = value
146
+ end
147
+ end
148
+
149
+ def self.prepare(object, attribute)
150
+ object.public_send :"#{attribute}=", {} unless object.send(attribute)
151
+ end
152
+ end
153
+
154
+ class StringKeyedHashAccessor < HashAccessor
155
+ def self.read(object, attribute, key)
156
+ super object, attribute, key.to_s
157
+ end
158
+
159
+ def self.write(object, attribute, key, value)
160
+ super object, attribute, key.to_s, value
161
+ end
162
+ end
163
+
164
+ class IndifferentHashAccessor < ActiveRecord::Store::HashAccessor
165
+ def self.prepare(object, store_attribute)
166
+ attribute = object.send(store_attribute)
167
+ unless attribute.is_a?(ActiveSupport::HashWithIndifferentAccess)
168
+ attribute = IndifferentCoder.as_indifferent_hash(attribute)
169
+ object.send :"#{store_attribute}=", attribute
170
+ end
171
+ attribute
122
172
  end
123
- attribute
124
173
  end
125
174
 
126
175
  class IndifferentCoder # :nodoc:
@@ -138,7 +187,7 @@ module ActiveRecord
138
187
  end
139
188
 
140
189
  def load(yaml)
141
- self.class.as_indifferent_hash @coder.load(yaml || '')
190
+ self.class.as_indifferent_hash(@coder.load(yaml || ''))
142
191
  end
143
192
 
144
193
  def self.as_indifferent_hash(obj)
@@ -36,9 +36,8 @@ module ActiveRecord
36
36
  module DatabaseTasks
37
37
  extend self
38
38
 
39
- attr_writer :current_config
40
- attr_accessor :database_configuration, :migrations_paths, :seed_loader, :db_dir,
41
- :fixtures_path, :env, :root
39
+ attr_writer :current_config, :db_dir, :migrations_paths, :fixtures_path, :root, :env, :seed_loader
40
+ attr_accessor :database_configuration
42
41
 
43
42
  LOCAL_HOSTS = ['127.0.0.1', 'localhost']
44
43
 
@@ -51,20 +50,36 @@ module ActiveRecord
51
50
  register_task(/postgresql/, ActiveRecord::Tasks::PostgreSQLDatabaseTasks)
52
51
  register_task(/sqlite/, ActiveRecord::Tasks::SQLiteDatabaseTasks)
53
52
 
54
- register_task(/firebird/, ActiveRecord::Tasks::FirebirdDatabaseTasks)
55
- register_task(/sqlserver/, ActiveRecord::Tasks::SqlserverDatabaseTasks)
56
- register_task(/(oci|oracle)/, ActiveRecord::Tasks::OracleDatabaseTasks)
53
+ def db_dir
54
+ @db_dir ||= Rails.application.config.paths["db"].first
55
+ end
56
+
57
+ def migrations_paths
58
+ @migrations_paths ||= Rails.application.paths['db/migrate'].to_a
59
+ end
60
+
61
+ def fixtures_path
62
+ @fixtures_path ||= File.join(root, 'test', 'fixtures')
63
+ end
64
+
65
+ def root
66
+ @root ||= Rails.root
67
+ end
68
+
69
+ def env
70
+ @env ||= Rails.env
71
+ end
72
+
73
+ def seed_loader
74
+ @seed_loader ||= Rails.application
75
+ end
57
76
 
58
77
  def current_config(options = {})
59
78
  options.reverse_merge! :env => env
60
79
  if options.has_key?(:config)
61
80
  @current_config = options[:config]
62
81
  else
63
- @current_config ||= if ENV['DATABASE_URL']
64
- database_url_config
65
- else
66
- ActiveRecord::Base.configurations[options[:env]]
67
- end
82
+ @current_config ||= ActiveRecord::Base.configurations[options[:env]]
68
83
  end
69
84
  end
70
85
 
@@ -86,11 +101,7 @@ module ActiveRecord
86
101
  each_current_configuration(environment) { |configuration|
87
102
  create configuration
88
103
  }
89
- ActiveRecord::Base.establish_connection environment
90
- end
91
-
92
- def create_database_url
93
- create database_url_config
104
+ ActiveRecord::Base.establish_connection(environment.to_sym)
94
105
  end
95
106
 
96
107
  def drop(*arguments)
@@ -111,10 +122,6 @@ module ActiveRecord
111
122
  }
112
123
  end
113
124
 
114
- def drop_database_url
115
- drop database_url_config
116
- end
117
-
118
125
  def charset_current(environment = env)
119
126
  charset ActiveRecord::Base.configurations[environment]
120
127
  end
@@ -149,6 +156,43 @@ module ActiveRecord
149
156
  class_for_adapter(configuration['adapter']).new(*arguments).structure_load(filename)
150
157
  end
151
158
 
159
+ def load_schema(format = ActiveRecord::Base.schema_format, file = nil)
160
+ load_schema_current(format, file)
161
+ end
162
+
163
+ # This method is the successor of +load_schema+. We should rename it
164
+ # after +load_schema+ went through a deprecation cycle. (Rails > 4.2)
165
+ def load_schema_for(configuration, format = ActiveRecord::Base.schema_format, file = nil) # :nodoc:
166
+ case format
167
+ when :ruby
168
+ file ||= File.join(db_dir, "schema.rb")
169
+ check_schema_file(file)
170
+ ActiveRecord::Base.establish_connection(configuration)
171
+ load(file)
172
+ when :sql
173
+ file ||= File.join(db_dir, "structure.sql")
174
+ check_schema_file(file)
175
+ structure_load(configuration, file)
176
+ else
177
+ raise ArgumentError, "unknown format #{format.inspect}"
178
+ end
179
+ end
180
+
181
+ def load_schema_current(format = ActiveRecord::Base.schema_format, file = nil, environment = env)
182
+ each_current_configuration(environment) { |configuration|
183
+ load_schema_for configuration, format, file
184
+ }
185
+ ActiveRecord::Base.establish_connection(environment.to_sym)
186
+ end
187
+
188
+ def check_schema_file(filename)
189
+ unless File.exist?(filename)
190
+ message = %{#{filename} doesn't exist yet. Run `rake db:migrate` to create it, then try again.}
191
+ message << %{ If you do not intend to use a database, you should instead alter #{Rails.root}/config/application.rb to limit the frameworks that will be loaded.} if defined?(::Rails)
192
+ Kernel.abort message
193
+ end
194
+ end
195
+
152
196
  def load_seed
153
197
  if seed_loader
154
198
  seed_loader.load_seed
@@ -161,11 +205,6 @@ module ActiveRecord
161
205
 
162
206
  private
163
207
 
164
- def database_url_config
165
- @database_url_config ||=
166
- ConnectionAdapters::ConnectionSpecification::Resolver.new(ENV["DATABASE_URL"], {}).spec.config.stringify_keys
167
- end
168
-
169
208
  def class_for_adapter(adapter)
170
209
  key = @tasks.keys.detect { |pattern| adapter[pattern] }
171
210
  unless key
@@ -176,7 +215,8 @@ module ActiveRecord
176
215
 
177
216
  def each_current_configuration(environment)
178
217
  environments = [environment]
179
- environments << 'test' if environment == 'development'
218
+ # add test environment only if no RAILS_ENV was specified.
219
+ environments << 'test' if environment == 'development' && ENV['RAILS_ENV'].nil?
180
220
 
181
221
  configurations = ActiveRecord::Base.configurations.values_at(*environments)
182
222
  configurations.compact.each do |configuration|
@@ -42,7 +42,7 @@ module ActiveRecord
42
42
  end
43
43
 
44
44
  def purge
45
- establish_connection :test
45
+ establish_connection configuration
46
46
  connection.recreate_database configuration['database'], creation_options
47
47
  end
48
48
 
@@ -129,15 +129,21 @@ IDENTIFIED BY '#{configuration['password']}' WITH GRANT OPTION;
129
129
  end
130
130
 
131
131
  def prepare_command_options(command)
132
- args = [command]
133
- args.concat(['--user', configuration['username']]) if configuration['username']
134
- args << "--password=#{configuration['password']}" if configuration['password']
135
- args.concat(['--default-character-set', configuration['encoding']]) if configuration['encoding']
136
- configuration.slice('host', 'port', 'socket').each do |k, v|
137
- args.concat([ "--#{k}", v.to_s ]) if v
138
- end
139
-
140
- args
132
+ args = {
133
+ 'host' => '--host',
134
+ 'port' => '--port',
135
+ 'socket' => '--socket',
136
+ 'username' => '--user',
137
+ 'password' => '--password',
138
+ 'encoding' => '--default-character-set',
139
+ 'sslca' => '--ssl-ca',
140
+ 'sslcert' => '--ssl-cert',
141
+ 'sslcapath' => '--ssl-capath',
142
+ 'sslcipher' => '--ssl-cipher',
143
+ 'sslkey' => '--ssl-key'
144
+ }.map { |opt, arg| "#{arg}=#{configuration[opt]}" if configuration[opt] }.compact
145
+
146
+ [command, *args]
141
147
  end
142
148
  end
143
149
  end
@@ -51,7 +51,7 @@ module ActiveRecord
51
51
  search_path = search_path.split(",").map{|search_path_part| "--schema=#{Shellwords.escape(search_path_part.strip)}" }.join(" ")
52
52
  end
53
53
 
54
- command = "pg_dump -i -s -x -O -f #{Shellwords.escape(filename)} #{search_path} #{Shellwords.escape(configuration['database'])}"
54
+ command = "pg_dump -s -x -O -f #{Shellwords.escape(filename)} #{search_path} #{Shellwords.escape(configuration['database'])}"
55
55
  raise 'Error dumping database' unless Kernel.system(command)
56
56
 
57
57
  File.open(filename, "a") { |f| f << "SET search_path TO #{ActiveRecord::Base.connection.schema_search_path};\n\n" }
@@ -21,7 +21,11 @@ module ActiveRecord
21
21
 
22
22
  FileUtils.rm(file) if File.exist?(file)
23
23
  end
24
- alias :purge :drop
24
+
25
+ def purge
26
+ drop
27
+ create
28
+ end
25
29
 
26
30
  def charset
27
31
  connection.encoding
@@ -37,13 +37,13 @@ module ActiveRecord
37
37
  end
38
38
 
39
39
  def initialize_dup(other) # :nodoc:
40
- clear_timestamp_attributes
41
40
  super
41
+ clear_timestamp_attributes
42
42
  end
43
43
 
44
44
  private
45
45
 
46
- def create_record
46
+ def _create_record
47
47
  if self.record_timestamps
48
48
  current_time = current_time_from_proper_timezone
49
49
 
@@ -57,7 +57,7 @@ module ActiveRecord
57
57
  super
58
58
  end
59
59
 
60
- def update_record(*args)
60
+ def _update_record(*args)
61
61
  if should_record_timestamps?
62
62
  current_time = current_time_from_proper_timezone
63
63
 
@@ -71,7 +71,7 @@ module ActiveRecord
71
71
  end
72
72
 
73
73
  def should_record_timestamps?
74
- self.record_timestamps && (!partial_writes? || changed? || (attributes.keys & self.class.serialized_attributes.keys).present?)
74
+ self.record_timestamps && (!partial_writes? || changed?)
75
75
  end
76
76
 
77
77
  def timestamp_attributes_for_create_in_model
@@ -98,8 +98,8 @@ module ActiveRecord
98
98
  timestamp_attributes_for_create + timestamp_attributes_for_update
99
99
  end
100
100
 
101
- def max_updated_column_timestamp
102
- if (timestamps = timestamp_attributes_for_update.map { |attr| self[attr] }.compact).present?
101
+ def max_updated_column_timestamp(timestamp_names = timestamp_attributes_for_update)
102
+ if (timestamps = timestamp_names.map { |attr| self[attr] }.compact).present?
103
103
  timestamps.map { |ts| ts.to_time }.max
104
104
  end
105
105
  end
@@ -6,11 +6,10 @@ module ActiveRecord
6
6
  extend ActiveSupport::Concern
7
7
  ACTIONS = [:create, :destroy, :update]
8
8
 
9
- class TransactionError < ActiveRecordError # :nodoc:
10
- end
11
-
12
9
  included do
13
- define_callbacks :commit, :rollback, :terminator => "result == false", :scope => [:kind, :name]
10
+ define_callbacks :commit, :rollback,
11
+ terminator: ->(_, result) { result == false },
12
+ scope: [:kind, :name]
14
13
  end
15
14
 
16
15
  # = Active Record Transactions
@@ -241,17 +240,16 @@ module ActiveRecord
241
240
  def set_options_for_callbacks!(args)
242
241
  options = args.last
243
242
  if options.is_a?(Hash) && options[:on]
244
- assert_valid_transaction_action(options[:on])
245
- options[:if] = Array(options[:if])
246
243
  fire_on = Array(options[:on])
244
+ assert_valid_transaction_action(fire_on)
245
+ options[:if] = Array(options[:if])
247
246
  options[:if] << "transaction_include_any_action?(#{fire_on})"
248
247
  end
249
248
  end
250
249
 
251
250
  def assert_valid_transaction_action(actions)
252
- actions = Array(actions)
253
251
  if (actions - ACTIONS).any?
254
- raise ArgumentError, ":on conditions for after_commit and after_rollback callbacks have to be one of #{ACTIONS.join(",")}"
252
+ raise ArgumentError, ":on conditions for after_commit and after_rollback callbacks have to be one of #{ACTIONS}"
255
253
  end
256
254
  end
257
255
  end
@@ -306,6 +304,7 @@ module ActiveRecord
306
304
  run_callbacks :rollback
307
305
  ensure
308
306
  restore_transaction_record_state(force_restore_state)
307
+ clear_transaction_record_state
309
308
  end
310
309
 
311
310
  # Add the record to the current transaction so that the +after_rollback+ and +after_commit+ callbacks
@@ -362,21 +361,20 @@ module ActiveRecord
362
361
  # Restore the new record state and id of a record that was previously saved by a call to save_record_state.
363
362
  def restore_transaction_record_state(force = false) #:nodoc:
364
363
  unless @_start_transaction_state.empty?
365
- @_start_transaction_state[:level] = (@_start_transaction_state[:level] || 0) - 1
366
- if @_start_transaction_state[:level] < 1 || force
364
+ transaction_level = (@_start_transaction_state[:level] || 0) - 1
365
+ if transaction_level < 1 || force
367
366
  restore_state = @_start_transaction_state
368
367
  was_frozen = restore_state[:frozen?]
369
368
  @attributes = @attributes.dup if @attributes.frozen?
370
369
  @new_record = restore_state[:new_record]
371
370
  @destroyed = restore_state[:destroyed]
372
371
  if restore_state.has_key?(:id)
373
- self.id = restore_state[:id]
372
+ write_attribute(self.class.primary_key, restore_state[:id])
374
373
  else
375
374
  @attributes.delete(self.class.primary_key)
376
375
  @attributes_cache.delete(self.class.primary_key)
377
376
  end
378
377
  @attributes.freeze if was_frozen
379
- @_start_transaction_state.clear
380
378
  end
381
379
  end
382
380
  end
@@ -4,7 +4,7 @@ module ActiveRecord
4
4
  def validate(record)
5
5
  super
6
6
  attributes.each do |attribute|
7
- next unless record.class.reflect_on_association(attribute)
7
+ next unless record.class._reflect_on_association(attribute)
8
8
  associated_records = Array.wrap(record.send(attribute))
9
9
 
10
10
  # Superclass validates presence. Ensure present records aren't about to be destroyed.
@@ -7,16 +7,13 @@ module ActiveRecord
7
7
  "Pass a callable instead: `conditions: -> { where(approved: true) }`"
8
8
  end
9
9
  super({ case_sensitive: true }.merge!(options))
10
- end
11
-
12
- # Unfortunately, we have to tie Uniqueness validators to a class.
13
- def setup(klass)
14
- @klass = klass
10
+ @klass = options[:class]
15
11
  end
16
12
 
17
13
  def validate_each(record, attribute, value)
18
14
  finder_class = find_finder_class_for(record)
19
15
  table = finder_class.arel_table
16
+ value = map_enum_attribute(finder_class,attribute,value)
20
17
  value = deserialize_attribute(record, attribute, value)
21
18
 
22
19
  relation = build_relation(finder_class, table, attribute, value)
@@ -34,7 +31,6 @@ module ActiveRecord
34
31
  end
35
32
 
36
33
  protected
37
-
38
34
  # The check for an existing value should be run from a class that
39
35
  # isn't abstract. This means working down from the current class
40
36
  # (self), to the first non-abstract class. Since classes don't know
@@ -51,7 +47,7 @@ module ActiveRecord
51
47
  end
52
48
 
53
49
  def build_relation(klass, table, attribute, value) #:nodoc:
54
- if reflection = klass.reflect_on_association(attribute)
50
+ if reflection = klass._reflect_on_association(attribute)
55
51
  attribute = reflection.foreign_key
56
52
  value = value.attributes[reflection.primary_key_column.name] unless value.nil?
57
53
  end
@@ -79,13 +75,21 @@ module ActiveRecord
79
75
 
80
76
  def scope_relation(record, table, relation)
81
77
  Array(options[:scope]).each do |scope_item|
82
- if reflection = record.class.reflect_on_association(scope_item)
78
+ if reflection = record.class._reflect_on_association(scope_item)
83
79
  scope_value = record.send(reflection.foreign_key)
84
80
  scope_item = reflection.foreign_key
85
81
  else
86
82
  scope_value = record.read_attribute(scope_item)
87
83
  end
88
- relation = relation.and(table[scope_item].eq(scope_value))
84
+
85
+ # This is basically emulating an Arel::Nodes::Casted
86
+ column = record.class.columns_hash[scope_item.to_s]
87
+ quoted_value = record.class.connection.quote(scope_value, column)
88
+ unless scope_value.nil?
89
+ node = Arel::Nodes::SqlLiteral.new(quoted_value)
90
+ end
91
+
92
+ relation = relation.and(table[scope_item].eq(node))
89
93
  end
90
94
 
91
95
  relation
@@ -96,6 +100,12 @@ module ActiveRecord
96
100
  value = coder.dump value if value && coder
97
101
  value
98
102
  end
103
+
104
+ def map_enum_attribute(klass, attribute, value)
105
+ mapping = klass.defined_enums[attribute.to_s]
106
+ value = mapping[value] if value && mapping
107
+ value
108
+ end
99
109
  end
100
110
 
101
111
  module ClassMethods
@@ -1,11 +1,8 @@
1
+ require_relative 'gem_version'
2
+
1
3
  module ActiveRecord
2
- # Returns the version of the currently loaded ActiveRecord as a Gem::Version
4
+ # Returns the version of the currently loaded ActiveRecord as a <tt>Gem::Version</tt>
3
5
  def self.version
4
- Gem::Version.new "4.0.4"
5
- end
6
-
7
- module VERSION #:nodoc:
8
- MAJOR, MINOR, TINY, PRE = ActiveRecord.version.segments
9
- STRING = ActiveRecord.version.to_s
6
+ gem_version
10
7
  end
11
8
  end
data/lib/active_record.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  #--
2
- # Copyright (c) 2004-2013 David Heinemeier Hansson
2
+ # Copyright (c) 2004-2014 David Heinemeier Hansson
3
3
  #
4
4
  # Permission is hereby granted, free of charge, to any person obtaining
5
5
  # a copy of this software and associated documentation files (the
@@ -25,7 +25,6 @@ require 'active_support'
25
25
  require 'active_support/rails'
26
26
  require 'active_model'
27
27
  require 'arel'
28
- require 'active_record/deprecated_finders'
29
28
 
30
29
  require 'active_record/version'
31
30
 
@@ -38,6 +37,7 @@ module ActiveRecord
38
37
  autoload :ConnectionHandling
39
38
  autoload :CounterCache
40
39
  autoload :DynamicMatchers
40
+ autoload :Enum
41
41
  autoload :Explain
42
42
  autoload :Inheritance
43
43
  autoload :Integration
@@ -45,10 +45,12 @@ module ActiveRecord
45
45
  autoload :Migrator, 'active_record/migration'
46
46
  autoload :ModelSchema
47
47
  autoload :NestedAttributes
48
+ autoload :NoTouching
48
49
  autoload :Persistence
49
50
  autoload :QueryCache
50
51
  autoload :Querying
51
52
  autoload :ReadonlyAttributes
53
+ autoload :RecordInvalid, 'active_record/validations'
52
54
  autoload :Reflection
53
55
  autoload :RuntimeRegistry
54
56
  autoload :Sanitization
@@ -94,6 +96,7 @@ module ActiveRecord
94
96
 
95
97
  module Coders
96
98
  autoload :YAMLColumn, 'active_record/coders/yaml_column'
99
+ autoload :JSON, 'active_record/coders/json'
97
100
  end
98
101
 
99
102
  module AttributeMethods
@@ -146,13 +149,8 @@ module ActiveRecord
146
149
  autoload :MySQLDatabaseTasks, 'active_record/tasks/mysql_database_tasks'
147
150
  autoload :PostgreSQLDatabaseTasks,
148
151
  'active_record/tasks/postgresql_database_tasks'
149
-
150
- autoload :FirebirdDatabaseTasks, 'active_record/tasks/firebird_database_tasks'
151
- autoload :SqlserverDatabaseTasks, 'active_record/tasks/sqlserver_database_tasks'
152
- autoload :OracleDatabaseTasks, 'active_record/tasks/oracle_database_tasks'
153
152
  end
154
153
 
155
- autoload :TestCase
156
154
  autoload :TestFixtures, 'active_record/fixtures'
157
155
 
158
156
  def self.eager_load!
@@ -14,6 +14,10 @@ module ActiveRecord
14
14
  protected
15
15
  attr_reader :migration_action, :join_tables
16
16
 
17
+ # sets the default migration template that is being used for the generation of the migration
18
+ # depending on the arguments which would be sent out in the command line, the migration template
19
+ # and the table name instance variables are setup.
20
+
17
21
  def set_local_assigns!
18
22
  @migration_template = "migration.rb"
19
23
  case file_name
@@ -0,0 +1,18 @@
1
+ require 'rails/generators/migration'
2
+
3
+ module ActiveRecord
4
+ module Generators # :nodoc:
5
+ module Migration
6
+ extend ActiveSupport::Concern
7
+ include Rails::Generators::Migration
8
+
9
+ module ClassMethods
10
+ # Implement the required interface for Rails::Generators::Migration.
11
+ def next_migration_number(dirname)
12
+ next_migration_number = current_migration_number(dirname) + 1
13
+ ActiveRecord::Migration.next_migration_number(next_migration_number)
14
+ end
15
+ end
16
+ end
17
+ end
18
+ end
@@ -12,6 +12,9 @@ module ActiveRecord
12
12
  class_option :parent, :type => :string, :desc => "The parent class for the generated model"
13
13
  class_option :indexes, :type => :boolean, :default => true, :desc => "Add indexes for references and belongs_to columns"
14
14
 
15
+
16
+ # creates the migration file for the model.
17
+
15
18
  def create_migration_file
16
19
  return unless options[:migration] && options[:parent].nil?
17
20
  attributes.each { |a| a.attr_options.delete(:index) if a.reference? && !a.has_index? } if options[:indexes] == false
@@ -39,6 +42,7 @@ module ActiveRecord
39
42
 
40
43
  protected
41
44
 
45
+ # Used by the migration template to determine the parent name of the model
42
46
  def parent_class_name
43
47
  options[:parent] || "ActiveRecord::Base"
44
48
  end