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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +1632 -1797
- data/MIT-LICENSE +1 -1
- data/README.rdoc +2 -2
- data/examples/performance.rb +30 -18
- data/examples/simple.rb +4 -4
- data/lib/active_record/aggregations.rb +2 -1
- data/lib/active_record/association_relation.rb +4 -0
- data/lib/active_record/associations/alias_tracker.rb +49 -29
- data/lib/active_record/associations/association.rb +9 -17
- data/lib/active_record/associations/association_scope.rb +59 -49
- data/lib/active_record/associations/belongs_to_association.rb +34 -25
- data/lib/active_record/associations/belongs_to_polymorphic_association.rb +6 -1
- data/lib/active_record/associations/builder/association.rb +84 -54
- data/lib/active_record/associations/builder/belongs_to.rb +90 -58
- data/lib/active_record/associations/builder/collection_association.rb +47 -45
- data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +119 -25
- data/lib/active_record/associations/builder/has_many.rb +3 -3
- data/lib/active_record/associations/builder/has_one.rb +5 -7
- data/lib/active_record/associations/builder/singular_association.rb +6 -7
- data/lib/active_record/associations/collection_association.rb +121 -111
- data/lib/active_record/associations/collection_proxy.rb +73 -18
- data/lib/active_record/associations/has_many_association.rb +14 -11
- data/lib/active_record/associations/has_many_through_association.rb +33 -6
- data/lib/active_record/associations/has_one_association.rb +1 -1
- data/lib/active_record/associations/join_dependency/join_association.rb +46 -104
- data/lib/active_record/associations/join_dependency/join_base.rb +6 -8
- data/lib/active_record/associations/join_dependency/join_part.rb +18 -37
- data/lib/active_record/associations/join_dependency.rb +208 -168
- data/lib/active_record/associations/preloader/association.rb +69 -27
- data/lib/active_record/associations/preloader/collection_association.rb +2 -2
- data/lib/active_record/associations/preloader/has_many_through.rb +1 -1
- data/lib/active_record/associations/preloader/singular_association.rb +3 -3
- data/lib/active_record/associations/preloader/through_association.rb +58 -26
- data/lib/active_record/associations/preloader.rb +63 -49
- data/lib/active_record/associations/singular_association.rb +6 -5
- data/lib/active_record/associations/through_association.rb +30 -9
- data/lib/active_record/associations.rb +116 -42
- data/lib/active_record/attribute_assignment.rb +6 -3
- data/lib/active_record/attribute_methods/before_type_cast.rb +2 -1
- data/lib/active_record/attribute_methods/dirty.rb +35 -26
- data/lib/active_record/attribute_methods/primary_key.rb +8 -1
- data/lib/active_record/attribute_methods/read.rb +56 -29
- data/lib/active_record/attribute_methods/serialization.rb +44 -12
- data/lib/active_record/attribute_methods/time_zone_conversion.rb +13 -1
- data/lib/active_record/attribute_methods/write.rb +59 -26
- data/lib/active_record/attribute_methods.rb +82 -43
- data/lib/active_record/autosave_association.rb +209 -194
- data/lib/active_record/base.rb +6 -2
- data/lib/active_record/callbacks.rb +2 -2
- data/lib/active_record/coders/json.rb +13 -0
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +5 -10
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +14 -24
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +13 -13
- data/lib/active_record/connection_adapters/abstract/quoting.rb +6 -3
- data/lib/active_record/connection_adapters/abstract/savepoints.rb +21 -0
- data/lib/active_record/connection_adapters/abstract/schema_creation.rb +90 -0
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +9 -8
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +45 -70
- data/lib/active_record/connection_adapters/abstract/transaction.rb +1 -0
- data/lib/active_record/connection_adapters/abstract_adapter.rb +28 -96
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +74 -66
- data/lib/active_record/connection_adapters/column.rb +1 -35
- data/lib/active_record/connection_adapters/connection_specification.rb +231 -43
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +10 -5
- data/lib/active_record/connection_adapters/mysql_adapter.rb +24 -17
- data/lib/active_record/connection_adapters/postgresql/array_parser.rb +22 -15
- data/lib/active_record/connection_adapters/postgresql/cast.rb +12 -4
- data/lib/active_record/connection_adapters/postgresql/database_statements.rb +18 -44
- data/lib/active_record/connection_adapters/postgresql/oid.rb +38 -14
- data/lib/active_record/connection_adapters/postgresql/quoting.rb +37 -12
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +20 -11
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +98 -52
- data/lib/active_record/connection_adapters/schema_cache.rb +8 -29
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +55 -60
- data/lib/active_record/connection_handling.rb +39 -5
- data/lib/active_record/core.rb +38 -54
- data/lib/active_record/counter_cache.rb +9 -10
- data/lib/active_record/dynamic_matchers.rb +6 -2
- data/lib/active_record/enum.rb +199 -0
- data/lib/active_record/errors.rb +22 -5
- data/lib/active_record/fixture_set/file.rb +2 -1
- data/lib/active_record/fixtures.rb +173 -76
- data/lib/active_record/gem_version.rb +15 -0
- data/lib/active_record/inheritance.rb +23 -9
- data/lib/active_record/integration.rb +54 -1
- data/lib/active_record/locking/optimistic.rb +7 -2
- data/lib/active_record/locking/pessimistic.rb +1 -1
- data/lib/active_record/log_subscriber.rb +6 -13
- data/lib/active_record/migration/command_recorder.rb +8 -2
- data/lib/active_record/migration.rb +91 -56
- data/lib/active_record/model_schema.rb +7 -14
- data/lib/active_record/nested_attributes.rb +25 -13
- data/lib/active_record/no_touching.rb +52 -0
- data/lib/active_record/null_relation.rb +26 -6
- data/lib/active_record/persistence.rb +23 -29
- data/lib/active_record/querying.rb +15 -12
- data/lib/active_record/railtie.rb +12 -61
- data/lib/active_record/railties/databases.rake +37 -56
- data/lib/active_record/readonly_attributes.rb +0 -6
- data/lib/active_record/reflection.rb +230 -79
- data/lib/active_record/relation/batches.rb +74 -24
- data/lib/active_record/relation/calculations.rb +52 -48
- data/lib/active_record/relation/delegation.rb +54 -39
- data/lib/active_record/relation/finder_methods.rb +210 -67
- data/lib/active_record/relation/merger.rb +15 -12
- data/lib/active_record/relation/predicate_builder/array_handler.rb +29 -0
- data/lib/active_record/relation/predicate_builder/relation_handler.rb +17 -0
- data/lib/active_record/relation/predicate_builder.rb +81 -40
- data/lib/active_record/relation/query_methods.rb +185 -108
- data/lib/active_record/relation/spawn_methods.rb +8 -5
- data/lib/active_record/relation.rb +79 -84
- data/lib/active_record/result.rb +45 -6
- data/lib/active_record/runtime_registry.rb +5 -0
- data/lib/active_record/sanitization.rb +4 -4
- data/lib/active_record/schema_dumper.rb +18 -6
- data/lib/active_record/schema_migration.rb +31 -18
- data/lib/active_record/scoping/default.rb +5 -18
- data/lib/active_record/scoping/named.rb +14 -29
- data/lib/active_record/scoping.rb +5 -0
- data/lib/active_record/store.rb +67 -18
- data/lib/active_record/tasks/database_tasks.rb +66 -26
- data/lib/active_record/tasks/mysql_database_tasks.rb +16 -10
- data/lib/active_record/tasks/postgresql_database_tasks.rb +1 -1
- data/lib/active_record/tasks/sqlite_database_tasks.rb +5 -1
- data/lib/active_record/timestamp.rb +6 -6
- data/lib/active_record/transactions.rb +10 -12
- data/lib/active_record/validations/presence.rb +1 -1
- data/lib/active_record/validations/uniqueness.rb +19 -9
- data/lib/active_record/version.rb +4 -7
- data/lib/active_record.rb +5 -7
- data/lib/rails/generators/active_record/migration/migration_generator.rb +4 -0
- data/lib/rails/generators/active_record/migration.rb +18 -0
- data/lib/rails/generators/active_record/model/model_generator.rb +4 -0
- data/lib/rails/generators/active_record.rb +2 -8
- metadata +18 -30
- data/lib/active_record/associations/has_and_belongs_to_many_association.rb +0 -65
- data/lib/active_record/associations/join_helper.rb +0 -45
- data/lib/active_record/associations/preloader/has_and_belongs_to_many.rb +0 -60
- data/lib/active_record/tasks/firebird_database_tasks.rb +0 -56
- data/lib/active_record/tasks/oracle_database_tasks.rb +0 -45
- data/lib/active_record/tasks/sqlserver_database_tasks.rb +0 -48
- data/lib/active_record/test_case.rb +0 -96
data/lib/active_record/store.rb
CHANGED
@@ -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
|
-
|
65
|
-
|
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
|
-
|
90
|
-
|
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
|
-
|
105
|
-
|
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
|
-
|
110
|
-
|
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
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
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
|
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
|
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
|
-
|
55
|
-
|
56
|
-
|
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 ||=
|
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
|
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
|
-
|
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
|
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 =
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
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 -
|
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" }
|
@@ -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
|
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
|
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?
|
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 =
|
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,
|
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
|
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
|
-
|
366
|
-
if
|
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.
|
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.
|
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
|
-
|
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.
|
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.
|
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
|
-
|
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
|
-
|
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-
|
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
|