activerecord 4.1.15 → 4.2.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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +634 -2176
- data/README.rdoc +15 -10
- data/lib/active_record/aggregations.rb +12 -8
- data/lib/active_record/associations/association.rb +1 -1
- data/lib/active_record/associations/association_scope.rb +53 -21
- data/lib/active_record/associations/belongs_to_association.rb +15 -5
- data/lib/active_record/associations/builder/association.rb +16 -5
- data/lib/active_record/associations/builder/belongs_to.rb +7 -29
- data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +2 -11
- data/lib/active_record/associations/builder/has_one.rb +2 -2
- data/lib/active_record/associations/builder/singular_association.rb +8 -1
- data/lib/active_record/associations/collection_association.rb +32 -44
- data/lib/active_record/associations/collection_proxy.rb +1 -10
- data/lib/active_record/associations/has_many_association.rb +60 -14
- data/lib/active_record/associations/has_many_through_association.rb +34 -23
- data/lib/active_record/associations/has_one_association.rb +0 -1
- data/lib/active_record/associations/join_dependency/join_association.rb +18 -14
- data/lib/active_record/associations/join_dependency.rb +7 -9
- data/lib/active_record/associations/preloader/association.rb +9 -5
- data/lib/active_record/associations/preloader/through_association.rb +3 -3
- data/lib/active_record/associations/preloader.rb +2 -2
- data/lib/active_record/associations/singular_association.rb +16 -1
- data/lib/active_record/associations/through_association.rb +6 -22
- data/lib/active_record/associations.rb +58 -33
- data/lib/active_record/attribute.rb +131 -0
- data/lib/active_record/attribute_assignment.rb +19 -11
- data/lib/active_record/attribute_decorators.rb +66 -0
- data/lib/active_record/attribute_methods/before_type_cast.rb +2 -2
- data/lib/active_record/attribute_methods/dirty.rb +85 -42
- data/lib/active_record/attribute_methods/primary_key.rb +6 -8
- data/lib/active_record/attribute_methods/read.rb +14 -57
- data/lib/active_record/attribute_methods/serialization.rb +12 -146
- data/lib/active_record/attribute_methods/time_zone_conversion.rb +32 -40
- data/lib/active_record/attribute_methods/write.rb +8 -23
- data/lib/active_record/attribute_methods.rb +53 -90
- data/lib/active_record/attribute_set/builder.rb +32 -0
- data/lib/active_record/attribute_set.rb +77 -0
- data/lib/active_record/attributes.rb +122 -0
- data/lib/active_record/autosave_association.rb +11 -21
- data/lib/active_record/base.rb +9 -19
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +69 -45
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +22 -42
- data/lib/active_record/connection_adapters/abstract/quoting.rb +59 -60
- data/lib/active_record/connection_adapters/abstract/schema_creation.rb +37 -2
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +102 -21
- data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +9 -33
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +178 -55
- data/lib/active_record/connection_adapters/abstract/transaction.rb +120 -115
- data/lib/active_record/connection_adapters/abstract_adapter.rb +143 -57
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +156 -107
- data/lib/active_record/connection_adapters/column.rb +13 -244
- data/lib/active_record/connection_adapters/connection_specification.rb +6 -20
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +12 -15
- data/lib/active_record/connection_adapters/mysql_adapter.rb +55 -143
- data/lib/active_record/connection_adapters/postgresql/array_parser.rb +15 -27
- data/lib/active_record/connection_adapters/postgresql/column.rb +20 -0
- data/lib/active_record/connection_adapters/postgresql/database_statements.rb +39 -20
- data/lib/active_record/connection_adapters/postgresql/oid/array.rb +96 -0
- data/lib/active_record/connection_adapters/postgresql/oid/bit.rb +52 -0
- data/lib/active_record/connection_adapters/postgresql/oid/bit_varying.rb +13 -0
- data/lib/active_record/connection_adapters/postgresql/oid/bytea.rb +14 -0
- data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +46 -0
- data/lib/active_record/connection_adapters/postgresql/oid/date.rb +11 -0
- data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +27 -0
- data/lib/active_record/connection_adapters/postgresql/oid/decimal.rb +13 -0
- data/lib/active_record/connection_adapters/postgresql/oid/enum.rb +17 -0
- data/lib/active_record/connection_adapters/postgresql/oid/float.rb +21 -0
- data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +59 -0
- data/lib/active_record/connection_adapters/postgresql/oid/inet.rb +13 -0
- data/lib/active_record/connection_adapters/postgresql/oid/infinity.rb +13 -0
- data/lib/active_record/connection_adapters/postgresql/oid/integer.rb +11 -0
- data/lib/active_record/connection_adapters/postgresql/oid/json.rb +35 -0
- data/lib/active_record/connection_adapters/postgresql/oid/jsonb.rb +23 -0
- data/lib/active_record/connection_adapters/postgresql/oid/money.rb +43 -0
- data/lib/active_record/connection_adapters/postgresql/oid/point.rb +43 -0
- data/lib/active_record/connection_adapters/postgresql/oid/range.rb +76 -0
- data/lib/active_record/connection_adapters/postgresql/oid/specialized_string.rb +15 -0
- data/lib/active_record/connection_adapters/postgresql/oid/time.rb +11 -0
- data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +85 -0
- data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +26 -0
- data/lib/active_record/connection_adapters/postgresql/oid/vector.rb +26 -0
- data/lib/active_record/connection_adapters/postgresql/oid/xml.rb +28 -0
- data/lib/active_record/connection_adapters/postgresql/oid.rb +29 -388
- data/lib/active_record/connection_adapters/postgresql/quoting.rb +42 -122
- data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +4 -4
- data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +154 -0
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +86 -34
- data/lib/active_record/connection_adapters/postgresql/utils.rb +66 -0
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +188 -452
- data/lib/active_record/connection_adapters/schema_cache.rb +14 -28
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +54 -47
- data/lib/active_record/connection_handling.rb +1 -1
- data/lib/active_record/core.rb +119 -22
- data/lib/active_record/counter_cache.rb +60 -6
- data/lib/active_record/enum.rb +9 -10
- data/lib/active_record/errors.rb +27 -26
- data/lib/active_record/explain.rb +1 -1
- data/lib/active_record/fixtures.rb +52 -45
- data/lib/active_record/gem_version.rb +3 -3
- data/lib/active_record/inheritance.rb +33 -8
- data/lib/active_record/integration.rb +4 -4
- data/lib/active_record/locking/optimistic.rb +34 -16
- data/lib/active_record/migration/command_recorder.rb +19 -2
- data/lib/active_record/migration/join_table.rb +1 -1
- data/lib/active_record/migration.rb +22 -32
- data/lib/active_record/model_schema.rb +39 -48
- data/lib/active_record/nested_attributes.rb +8 -18
- data/lib/active_record/persistence.rb +39 -22
- data/lib/active_record/query_cache.rb +3 -3
- data/lib/active_record/querying.rb +1 -8
- data/lib/active_record/railtie.rb +17 -10
- data/lib/active_record/railties/databases.rake +47 -42
- data/lib/active_record/readonly_attributes.rb +0 -1
- data/lib/active_record/reflection.rb +225 -92
- data/lib/active_record/relation/batches.rb +0 -2
- data/lib/active_record/relation/calculations.rb +28 -32
- data/lib/active_record/relation/delegation.rb +1 -1
- data/lib/active_record/relation/finder_methods.rb +42 -20
- data/lib/active_record/relation/merger.rb +0 -1
- data/lib/active_record/relation/predicate_builder/array_handler.rb +16 -11
- data/lib/active_record/relation/predicate_builder/relation_handler.rb +0 -4
- data/lib/active_record/relation/predicate_builder.rb +1 -22
- data/lib/active_record/relation/query_methods.rb +98 -62
- data/lib/active_record/relation/spawn_methods.rb +6 -7
- data/lib/active_record/relation.rb +35 -11
- data/lib/active_record/result.rb +16 -9
- data/lib/active_record/sanitization.rb +8 -1
- data/lib/active_record/schema.rb +0 -1
- data/lib/active_record/schema_dumper.rb +51 -9
- data/lib/active_record/schema_migration.rb +4 -0
- data/lib/active_record/scoping/default.rb +5 -4
- data/lib/active_record/serializers/xml_serializer.rb +3 -7
- data/lib/active_record/statement_cache.rb +79 -5
- data/lib/active_record/store.rb +5 -5
- data/lib/active_record/tasks/database_tasks.rb +37 -5
- data/lib/active_record/tasks/mysql_database_tasks.rb +1 -1
- data/lib/active_record/tasks/postgresql_database_tasks.rb +2 -2
- data/lib/active_record/timestamp.rb +9 -7
- data/lib/active_record/transactions.rb +35 -21
- data/lib/active_record/type/binary.rb +40 -0
- data/lib/active_record/type/boolean.rb +19 -0
- data/lib/active_record/type/date.rb +46 -0
- data/lib/active_record/type/date_time.rb +43 -0
- data/lib/active_record/type/decimal.rb +40 -0
- data/lib/active_record/type/decimal_without_scale.rb +11 -0
- data/lib/active_record/type/float.rb +19 -0
- data/lib/active_record/type/hash_lookup_type_map.rb +19 -0
- data/lib/active_record/type/integer.rb +23 -0
- data/lib/active_record/type/mutable.rb +16 -0
- data/lib/active_record/type/numeric.rb +36 -0
- data/lib/active_record/type/serialized.rb +51 -0
- data/lib/active_record/type/string.rb +36 -0
- data/lib/active_record/type/text.rb +11 -0
- data/lib/active_record/type/time.rb +26 -0
- data/lib/active_record/type/time_value.rb +38 -0
- data/lib/active_record/type/type_map.rb +48 -0
- data/lib/active_record/type/value.rb +101 -0
- data/lib/active_record/type.rb +20 -0
- data/lib/active_record/validations/uniqueness.rb +9 -23
- data/lib/active_record/validations.rb +21 -16
- data/lib/active_record.rb +2 -1
- data/lib/rails/generators/active_record/migration/migration_generator.rb +8 -4
- data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb +1 -1
- data/lib/rails/generators/active_record/model/templates/model.rb +1 -1
- metadata +71 -14
- data/lib/active_record/connection_adapters/postgresql/cast.rb +0 -168
data/lib/active_record/errors.rb
CHANGED
@@ -30,17 +30,18 @@ module ActiveRecord
|
|
30
30
|
class SerializationTypeMismatch < ActiveRecordError
|
31
31
|
end
|
32
32
|
|
33
|
-
# Raised when adapter not specified on connection (or configuration file
|
34
|
-
# misses adapter field).
|
33
|
+
# Raised when adapter not specified on connection (or configuration file
|
34
|
+
# +config/database.yml+ misses adapter field).
|
35
35
|
class AdapterNotSpecified < ActiveRecordError
|
36
36
|
end
|
37
37
|
|
38
|
-
# Raised when Active Record cannot find database adapter specified in
|
38
|
+
# Raised when Active Record cannot find database adapter specified in
|
39
|
+
# +config/database.yml+ or programmatically.
|
39
40
|
class AdapterNotFound < ActiveRecordError
|
40
41
|
end
|
41
42
|
|
42
|
-
# Raised when connection to the database could not been established (for
|
43
|
-
# is given a nil object).
|
43
|
+
# Raised when connection to the database could not been established (for
|
44
|
+
# example when +connection=+ is given a nil object).
|
44
45
|
class ConnectionNotEstablished < ActiveRecordError
|
45
46
|
end
|
46
47
|
|
@@ -82,35 +83,26 @@ module ActiveRecord
|
|
82
83
|
class InvalidForeignKey < WrappedDatabaseException
|
83
84
|
end
|
84
85
|
|
85
|
-
# Raised when number of bind variables in statement given to
|
86
|
-
# when using +find+ method)
|
87
|
-
#
|
86
|
+
# Raised when number of bind variables in statement given to +:condition+ key
|
87
|
+
# (for example, when using +find+ method) does not match number of expected
|
88
|
+
# values supplied.
|
88
89
|
#
|
89
|
-
# For example,
|
90
|
+
# For example, when there are two placeholders with only one value supplied:
|
90
91
|
#
|
91
92
|
# Location.where("lat = ? AND lng = ?", 53.7362)
|
92
|
-
#
|
93
|
-
# two placeholders are given but only one variable to fill them.
|
94
93
|
class PreparedStatementInvalid < ActiveRecordError
|
95
94
|
end
|
96
95
|
|
97
|
-
# Raised when a given database does not exist
|
98
|
-
class NoDatabaseError <
|
99
|
-
def initialize(message)
|
100
|
-
super extend_message(message)
|
101
|
-
end
|
102
|
-
|
103
|
-
# can be over written to add additional error information.
|
104
|
-
def extend_message(message)
|
105
|
-
message
|
106
|
-
end
|
96
|
+
# Raised when a given database does not exist.
|
97
|
+
class NoDatabaseError < StatementInvalid
|
107
98
|
end
|
108
99
|
|
109
100
|
# Raised on attempt to save stale record. Record is stale when it's being saved in another query after
|
110
101
|
# instantiation, for example, when two users edit the same wiki page and one starts editing and saves
|
111
102
|
# the page before the other.
|
112
103
|
#
|
113
|
-
# Read more about optimistic locking in ActiveRecord::Locking module
|
104
|
+
# Read more about optimistic locking in ActiveRecord::Locking module
|
105
|
+
# documentation.
|
114
106
|
class StaleObjectError < ActiveRecordError
|
115
107
|
attr_reader :record, :attempted_action
|
116
108
|
|
@@ -122,8 +114,9 @@ module ActiveRecord
|
|
122
114
|
|
123
115
|
end
|
124
116
|
|
125
|
-
# Raised when association is being configured improperly or
|
126
|
-
#
|
117
|
+
# Raised when association is being configured improperly or user tries to use
|
118
|
+
# offset and limit together with +has_many+ or +has_and_belongs_to_many+
|
119
|
+
# associations.
|
127
120
|
class ConfigurationError < ActiveRecordError
|
128
121
|
end
|
129
122
|
|
@@ -161,7 +154,8 @@ module ActiveRecord
|
|
161
154
|
class Rollback < ActiveRecordError
|
162
155
|
end
|
163
156
|
|
164
|
-
# Raised when attribute has a name reserved by Active Record (when attribute
|
157
|
+
# Raised when attribute has a name reserved by Active Record (when attribute
|
158
|
+
# has name of one of Active Record instance methods).
|
165
159
|
class DangerousAttributeError < ActiveRecordError
|
166
160
|
end
|
167
161
|
|
@@ -179,7 +173,7 @@ module ActiveRecord
|
|
179
173
|
end
|
180
174
|
|
181
175
|
# Raised when an error occurred while doing a mass assignment to an attribute through the
|
182
|
-
#
|
176
|
+
# +attributes=+ method. The exception has an +attribute+ property that is the name of the
|
183
177
|
# offending attribute.
|
184
178
|
class AttributeAssignmentError < ActiveRecordError
|
185
179
|
attr_reader :exception, :attribute
|
@@ -225,6 +219,13 @@ module ActiveRecord
|
|
225
219
|
class ImmutableRelation < ActiveRecordError
|
226
220
|
end
|
227
221
|
|
222
|
+
# TransactionIsolationError will be raised under the following conditions:
|
223
|
+
#
|
224
|
+
# * The adapter does not support setting the isolation level
|
225
|
+
# * You are joining an existing open transaction
|
226
|
+
# * You are creating a nested (savepoint) transaction
|
227
|
+
#
|
228
|
+
# The mysql, mysql2 and postgresql adapters support setting the transaction isolation level.
|
228
229
|
class TransactionIsolationError < ActiveRecordError
|
229
230
|
end
|
230
231
|
end
|
@@ -2,6 +2,7 @@ require 'erb'
|
|
2
2
|
require 'yaml'
|
3
3
|
require 'zlib'
|
4
4
|
require 'active_support/dependencies'
|
5
|
+
require 'active_support/core_ext/digest/uuid'
|
5
6
|
require 'active_record/fixture_set/file'
|
6
7
|
require 'active_record/errors'
|
7
8
|
|
@@ -14,9 +15,10 @@ module ActiveRecord
|
|
14
15
|
# They are stored in YAML files, one file per model, which are placed in the directory
|
15
16
|
# appointed by <tt>ActiveSupport::TestCase.fixture_path=(path)</tt> (this is automatically
|
16
17
|
# configured for Rails, so you can just put your files in <tt><your-rails-app>/test/fixtures/</tt>).
|
17
|
-
# The fixture file ends with the
|
18
|
-
# <tt><your-rails-app>/test/fixtures/web_sites.yml</tt>).
|
19
|
-
#
|
18
|
+
# The fixture file ends with the +.yml+ file extension, for example:
|
19
|
+
# <tt><your-rails-app>/test/fixtures/web_sites.yml</tt>).
|
20
|
+
#
|
21
|
+
# The format of a fixture file looks like this:
|
20
22
|
#
|
21
23
|
# rubyonrails:
|
22
24
|
# id: 1
|
@@ -32,7 +34,7 @@ module ActiveRecord
|
|
32
34
|
# is followed by an indented list of key/value pairs in the "key: value" format. Records are
|
33
35
|
# separated by a blank line for your viewing pleasure.
|
34
36
|
#
|
35
|
-
# Note
|
37
|
+
# Note: Fixtures are unordered. If you want ordered fixtures, use the omap YAML type.
|
36
38
|
# See http://yaml.org/type/omap.html
|
37
39
|
# for the specification. You will need ordered fixtures when you have foreign key constraints
|
38
40
|
# on keys in the same table. This is commonly needed for tree structures. Example:
|
@@ -60,8 +62,8 @@ module ActiveRecord
|
|
60
62
|
# end
|
61
63
|
# end
|
62
64
|
#
|
63
|
-
# By default,
|
64
|
-
# so this test will succeed.
|
65
|
+
# By default, +test_helper.rb+ will load all of your fixtures into your test
|
66
|
+
# database, so this test will succeed.
|
65
67
|
#
|
66
68
|
# The testing environment will automatically load the all fixtures into the database before each
|
67
69
|
# test. To ensure consistent data, the environment deletes the fixtures before running the load.
|
@@ -124,7 +126,7 @@ module ActiveRecord
|
|
124
126
|
# that is included in <tt>ActiveRecord::FixtureSet.context_class</tt>.
|
125
127
|
#
|
126
128
|
# - define a helper method in `test_helper.rb`
|
127
|
-
#
|
129
|
+
# class FixtureFileHelpers
|
128
130
|
# def file_sha(path)
|
129
131
|
# Digest::SHA2.hexdigest(File.read(Rails.root.join('test/fixtures', path)))
|
130
132
|
# end
|
@@ -361,6 +363,7 @@ module ActiveRecord
|
|
361
363
|
# geeksomnia:
|
362
364
|
# name: Geeksomnia's Account
|
363
365
|
# subdomain: $LABEL
|
366
|
+
# email: $LABEL@email.com
|
364
367
|
#
|
365
368
|
# Also, sometimes (like when porting older join table fixtures) you'll need
|
366
369
|
# to be able to get a hold of the identifier for a given label. ERB
|
@@ -372,8 +375,9 @@ module ActiveRecord
|
|
372
375
|
#
|
373
376
|
# == Support for YAML defaults
|
374
377
|
#
|
375
|
-
# You
|
376
|
-
#
|
378
|
+
# You can set and reuse defaults in your fixtures YAML file.
|
379
|
+
# This is the same technique used in the +database.yml+ file to specify
|
380
|
+
# defaults:
|
377
381
|
#
|
378
382
|
# DEFAULTS: &DEFAULTS
|
379
383
|
# created_on: <%= 3.weeks.ago.to_s(:db) %>
|
@@ -389,7 +393,8 @@ module ActiveRecord
|
|
389
393
|
# Any fixture labeled "DEFAULTS" is safely ignored.
|
390
394
|
class FixtureSet
|
391
395
|
#--
|
392
|
-
# An instance of FixtureSet is normally stored in a single YAML file and
|
396
|
+
# An instance of FixtureSet is normally stored in a single YAML file and
|
397
|
+
# possibly in a folder with the same name.
|
393
398
|
#++
|
394
399
|
|
395
400
|
MAX_ID = 2 ** 30 - 1
|
@@ -459,13 +464,7 @@ module ActiveRecord
|
|
459
464
|
@config = config
|
460
465
|
|
461
466
|
# Remove string values that aren't constants or subclasses of AR
|
462
|
-
@class_names.delete_if { |
|
463
|
-
unless klass.is_a? Class
|
464
|
-
klass = klass.safe_constantize
|
465
|
-
ActiveSupport::Deprecation.warn("The ability to pass in strings as a class name to `set_fixture_class` will be removed in Rails 4.2. Use the class itself instead.")
|
466
|
-
end
|
467
|
-
!insert_class(@class_names, k, klass)
|
468
|
-
}
|
467
|
+
@class_names.delete_if { |klass_name, klass| !insert_class(@class_names, klass_name, klass) }
|
469
468
|
end
|
470
469
|
|
471
470
|
def [](fs_name)
|
@@ -532,10 +531,12 @@ module ActiveRecord
|
|
532
531
|
conn.insert_fixture(row, fixture_set_name)
|
533
532
|
end
|
534
533
|
end
|
534
|
+
end
|
535
535
|
|
536
|
-
|
537
|
-
|
538
|
-
|
536
|
+
# Cap primary key sequences to max(pk).
|
537
|
+
if connection.respond_to?(:reset_pk_sequence!)
|
538
|
+
fixture_sets.each do |fs|
|
539
|
+
connection.reset_pk_sequence!(fs.table_name)
|
539
540
|
end
|
540
541
|
end
|
541
542
|
end
|
@@ -547,9 +548,13 @@ module ActiveRecord
|
|
547
548
|
end
|
548
549
|
|
549
550
|
# Returns a consistent, platform-independent identifier for +label+.
|
550
|
-
#
|
551
|
-
def self.identify(label)
|
552
|
-
|
551
|
+
# Integer identifiers are values less than 2^30. UUIDs are RFC 4122 version 5 SHA-1 hashes.
|
552
|
+
def self.identify(label, column_type = :integer)
|
553
|
+
if column_type == :uuid
|
554
|
+
Digest::UUID.uuid_v5(Digest::UUID::OID_NAMESPACE, label.to_s)
|
555
|
+
else
|
556
|
+
Zlib.crc32(label.to_s) % MAX_ID
|
557
|
+
end
|
553
558
|
end
|
554
559
|
|
555
560
|
# Superclass for the evaluation contexts used by ERB fixtures.
|
@@ -565,10 +570,6 @@ module ActiveRecord
|
|
565
570
|
@config = config
|
566
571
|
@model_class = nil
|
567
572
|
|
568
|
-
if class_name.is_a?(String)
|
569
|
-
ActiveSupport::Deprecation.warn("The ability to pass in strings as a class name to `FixtureSet.new` will be removed in Rails 4.2. Use the class itself instead.")
|
570
|
-
end
|
571
|
-
|
572
573
|
if class_name.is_a?(Class) # TODO: Should be an AR::Base type class, or any?
|
573
574
|
@model_class = class_name
|
574
575
|
else
|
@@ -625,12 +626,12 @@ module ActiveRecord
|
|
625
626
|
|
626
627
|
# interpolate the fixture label
|
627
628
|
row.each do |key, value|
|
628
|
-
row[key] =
|
629
|
+
row[key] = value.gsub("$LABEL", label) if value.is_a?(String)
|
629
630
|
end
|
630
631
|
|
631
632
|
# generate a primary key if necessary
|
632
633
|
if has_primary_key_column? && !row.include?(primary_key_name)
|
633
|
-
row[primary_key_name] = ActiveRecord::FixtureSet.identify(label)
|
634
|
+
row[primary_key_name] = ActiveRecord::FixtureSet.identify(label, primary_key_type)
|
634
635
|
end
|
635
636
|
|
636
637
|
# If STI is used, find the correct subclass for association reflection
|
@@ -648,12 +649,13 @@ module ActiveRecord
|
|
648
649
|
fk_name = (association.options[:foreign_key] || "#{association.name}_id").to_s
|
649
650
|
|
650
651
|
if association.name.to_s != fk_name && value = row.delete(association.name.to_s)
|
651
|
-
if association.
|
652
|
+
if association.polymorphic? && value.sub!(/\s*\(([^\)]*)\)\s*$/, "")
|
652
653
|
# support polymorphic belongs_to as "label (Type)"
|
653
654
|
row[association.foreign_type] = $1
|
654
655
|
end
|
655
656
|
|
656
|
-
|
657
|
+
fk_type = association.active_record.columns_hash[association.foreign_key].type
|
658
|
+
row[fk_name] = ActiveRecord::FixtureSet.identify(value, fk_type)
|
657
659
|
end
|
658
660
|
when :has_many
|
659
661
|
if association.options[:through]
|
@@ -680,6 +682,10 @@ module ActiveRecord
|
|
680
682
|
def name
|
681
683
|
@association.name
|
682
684
|
end
|
685
|
+
|
686
|
+
def primary_key_type
|
687
|
+
@association.klass.column_types[@association.klass.primary_key].type
|
688
|
+
end
|
683
689
|
end
|
684
690
|
|
685
691
|
class HasManyThroughProxy < ReflectionProxy # :nodoc:
|
@@ -690,10 +696,6 @@ module ActiveRecord
|
|
690
696
|
def lhs_key
|
691
697
|
@association.through_reflection.foreign_key
|
692
698
|
end
|
693
|
-
|
694
|
-
def join_table
|
695
|
-
@association.through_reflection.table_name
|
696
|
-
end
|
697
699
|
end
|
698
700
|
|
699
701
|
private
|
@@ -701,17 +703,22 @@ module ActiveRecord
|
|
701
703
|
@primary_key_name ||= model_class && model_class.primary_key
|
702
704
|
end
|
703
705
|
|
706
|
+
def primary_key_type
|
707
|
+
@primary_key_type ||= model_class && model_class.column_types[model_class.primary_key].type
|
708
|
+
end
|
709
|
+
|
704
710
|
def add_join_records(rows, row, association)
|
705
711
|
# This is the case when the join table has no fixtures file
|
706
712
|
if (targets = row.delete(association.name.to_s))
|
707
|
-
table_name
|
708
|
-
|
709
|
-
|
713
|
+
table_name = association.join_table
|
714
|
+
column_type = association.primary_key_type
|
715
|
+
lhs_key = association.lhs_key
|
716
|
+
rhs_key = association.rhs_key
|
710
717
|
|
711
718
|
targets = targets.is_a?(Array) ? targets : targets.split(/\s*,\s*/)
|
712
719
|
rows[table_name].concat targets.map { |target|
|
713
720
|
{ lhs_key => row[primary_key_name],
|
714
|
-
rhs_key => ActiveRecord::FixtureSet.identify(target) }
|
721
|
+
rhs_key => ActiveRecord::FixtureSet.identify(target, column_type) }
|
715
722
|
}
|
716
723
|
end
|
717
724
|
end
|
@@ -792,7 +799,7 @@ module ActiveRecord
|
|
792
799
|
|
793
800
|
def find
|
794
801
|
if model_class
|
795
|
-
model_class.
|
802
|
+
model_class.find(fixture[model_class.primary_key])
|
796
803
|
else
|
797
804
|
raise FixtureClassNotFound, "No class attached to find."
|
798
805
|
end
|
@@ -863,11 +870,11 @@ module ActiveRecord
|
|
863
870
|
def try_to_load_dependency(file_name)
|
864
871
|
require_dependency file_name
|
865
872
|
rescue LoadError => e
|
866
|
-
|
867
|
-
|
868
|
-
|
869
|
-
|
870
|
-
|
873
|
+
# Let's hope the developer has included it
|
874
|
+
# Let's warn in case this is a subdependency, otherwise
|
875
|
+
# subdependency error messages are totally cryptic
|
876
|
+
if ActiveRecord::Base.logger
|
877
|
+
ActiveRecord::Base.logger.warn("Unable to load #{file_name}, underlying cause #{e.message} \n\n #{e.backtrace.join("\n")}")
|
871
878
|
end
|
872
879
|
end
|
873
880
|
|
@@ -1,6 +1,37 @@
|
|
1
1
|
require 'active_support/core_ext/hash/indifferent_access'
|
2
2
|
|
3
3
|
module ActiveRecord
|
4
|
+
# == Single table inheritance
|
5
|
+
#
|
6
|
+
# Active Record allows inheritance by storing the name of the class in a column that by
|
7
|
+
# default is named "type" (can be changed by overwriting <tt>Base.inheritance_column</tt>).
|
8
|
+
# This means that an inheritance looking like this:
|
9
|
+
#
|
10
|
+
# class Company < ActiveRecord::Base; end
|
11
|
+
# class Firm < Company; end
|
12
|
+
# class Client < Company; end
|
13
|
+
# class PriorityClient < Client; end
|
14
|
+
#
|
15
|
+
# When you do <tt>Firm.create(name: "37signals")</tt>, this record will be saved in
|
16
|
+
# the companies table with type = "Firm". You can then fetch this row again using
|
17
|
+
# <tt>Company.where(name: '37signals').first</tt> and it will return a Firm object.
|
18
|
+
#
|
19
|
+
# Be aware that because the type column is an attribute on the record every new
|
20
|
+
# subclass will instantly be marked as dirty and the type column will be included
|
21
|
+
# in the list of changed attributes on the record. This is different from non
|
22
|
+
# STI classes:
|
23
|
+
#
|
24
|
+
# Company.new.changed? # => false
|
25
|
+
# Firm.new.changed? # => true
|
26
|
+
# Firm.new.changes # => {"type"=>["","Firm"]}
|
27
|
+
#
|
28
|
+
# If you don't have a type column defined in your table, single-table inheritance won't
|
29
|
+
# be triggered. In that case, it'll work just like normal subclasses with no special magic
|
30
|
+
# for differentiating between them or reloading the right type with find.
|
31
|
+
#
|
32
|
+
# Note, all the attributes for all the cases are kept in the same table. Read more:
|
33
|
+
# http://www.martinfowler.com/eaaCatalog/singleTableInheritance.html
|
34
|
+
#
|
4
35
|
module Inheritance
|
5
36
|
extend ActiveSupport::Concern
|
6
37
|
|
@@ -120,14 +151,8 @@ module ActiveRecord
|
|
120
151
|
candidates << type_name
|
121
152
|
|
122
153
|
candidates.each do |candidate|
|
123
|
-
|
124
|
-
|
125
|
-
return constant if candidate == constant.to_s
|
126
|
-
# We don't want to swallow NoMethodError < NameError errors
|
127
|
-
rescue NoMethodError
|
128
|
-
raise
|
129
|
-
rescue NameError
|
130
|
-
end
|
154
|
+
constant = ActiveSupport::Dependencies.safe_constantize(candidate)
|
155
|
+
return constant if candidate == constant.to_s
|
131
156
|
end
|
132
157
|
|
133
158
|
raise NameError.new("uninitialized constant #{candidates.first}", candidates.first)
|
@@ -55,16 +55,16 @@ module ActiveRecord
|
|
55
55
|
def cache_key(*timestamp_names)
|
56
56
|
case
|
57
57
|
when new_record?
|
58
|
-
"#{
|
58
|
+
"#{model_name.cache_key}/new"
|
59
59
|
when timestamp_names.any?
|
60
60
|
timestamp = max_updated_column_timestamp(timestamp_names)
|
61
61
|
timestamp = timestamp.utc.to_s(cache_timestamp_format)
|
62
|
-
"#{
|
62
|
+
"#{model_name.cache_key}/#{id}-#{timestamp}"
|
63
63
|
when timestamp = max_updated_column_timestamp
|
64
64
|
timestamp = timestamp.utc.to_s(cache_timestamp_format)
|
65
|
-
"#{
|
65
|
+
"#{model_name.cache_key}/#{id}-#{timestamp}"
|
66
66
|
else
|
67
|
-
"#{
|
67
|
+
"#{model_name.cache_key}/#{id}"
|
68
68
|
end
|
69
69
|
end
|
70
70
|
|
@@ -66,7 +66,7 @@ module ActiveRecord
|
|
66
66
|
send(lock_col + '=', previous_lock_value + 1)
|
67
67
|
end
|
68
68
|
|
69
|
-
def _update_record(attribute_names =
|
69
|
+
def _update_record(attribute_names = self.attribute_names) #:nodoc:
|
70
70
|
return super unless locking_enabled?
|
71
71
|
return 0 if attribute_names.empty?
|
72
72
|
|
@@ -141,7 +141,7 @@ module ActiveRecord
|
|
141
141
|
|
142
142
|
# Set the column to use for optimistic locking. Defaults to +lock_version+.
|
143
143
|
def locking_column=(value)
|
144
|
-
|
144
|
+
clear_caches_calculated_from_columns
|
145
145
|
@locking_column = value.to_s
|
146
146
|
end
|
147
147
|
|
@@ -151,12 +151,6 @@ module ActiveRecord
|
|
151
151
|
@locking_column
|
152
152
|
end
|
153
153
|
|
154
|
-
# Quote the column name used for optimistic locking.
|
155
|
-
def quoted_locking_column
|
156
|
-
ActiveSupport::Deprecation.warn "ActiveRecord::Base.quoted_locking_column is deprecated and will be removed in Rails 4.2 or later."
|
157
|
-
connection.quote_column_name(locking_column)
|
158
|
-
end
|
159
|
-
|
160
154
|
# Reset the column used for optimistic locking back to the +lock_version+ default.
|
161
155
|
def reset_locking_column
|
162
156
|
self.locking_column = DEFAULT_LOCKING_COLUMN
|
@@ -169,18 +163,42 @@ module ActiveRecord
|
|
169
163
|
super
|
170
164
|
end
|
171
165
|
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
166
|
+
private
|
167
|
+
|
168
|
+
# We need to apply this decorator here, rather than on module inclusion. The closure
|
169
|
+
# created by the matcher would otherwise evaluate for `ActiveRecord::Base`, not the
|
170
|
+
# sub class being decorated. As such, changes to `lock_optimistically`, or
|
171
|
+
# `locking_column` would not be picked up.
|
172
|
+
def inherited(subclass)
|
173
|
+
subclass.class_eval do
|
174
|
+
is_lock_column = ->(name, _) { lock_optimistically && name == locking_column }
|
175
|
+
decorate_matching_attribute_types(is_lock_column, :_optimistic_locking) do |type|
|
176
|
+
LockingType.new(type)
|
178
177
|
end
|
179
|
-
|
180
|
-
defaults
|
181
178
|
end
|
179
|
+
super
|
182
180
|
end
|
183
181
|
end
|
184
182
|
end
|
183
|
+
|
184
|
+
class LockingType < SimpleDelegator # :nodoc:
|
185
|
+
def type_cast_from_database(value)
|
186
|
+
# `nil` *should* be changed to 0
|
187
|
+
super.to_i
|
188
|
+
end
|
189
|
+
|
190
|
+
def changed?(old_value, *)
|
191
|
+
# Ensure we save if the default was `nil`
|
192
|
+
super || old_value == 0
|
193
|
+
end
|
194
|
+
|
195
|
+
def init_with(coder)
|
196
|
+
__setobj__(coder['subtype'])
|
197
|
+
end
|
198
|
+
|
199
|
+
def encode_with(coder)
|
200
|
+
coder['subtype'] = __getobj__
|
201
|
+
end
|
202
|
+
end
|
185
203
|
end
|
186
204
|
end
|
@@ -74,7 +74,9 @@ module ActiveRecord
|
|
74
74
|
:rename_index, :rename_column, :add_index, :remove_index, :add_timestamps, :remove_timestamps,
|
75
75
|
:change_column_default, :add_reference, :remove_reference, :transaction,
|
76
76
|
:drop_join_table, :drop_table, :execute_block, :enable_extension,
|
77
|
-
:change_column, :execute, :remove_columns, :change_column_null
|
77
|
+
:change_column, :execute, :remove_columns, :change_column_null,
|
78
|
+
:add_foreign_key, :remove_foreign_key
|
79
|
+
# irreversible methods need to be here too
|
78
80
|
].each do |method|
|
79
81
|
class_eval <<-EOV, __FILE__, __LINE__ + 1
|
80
82
|
def #{method}(*args, &block) # def create_table(*args, &block)
|
@@ -85,7 +87,7 @@ module ActiveRecord
|
|
85
87
|
alias :add_belongs_to :add_reference
|
86
88
|
alias :remove_belongs_to :remove_reference
|
87
89
|
|
88
|
-
def change_table(table_name, options = {})
|
90
|
+
def change_table(table_name, options = {}) # :nodoc:
|
89
91
|
yield delegate.update_table_definition(table_name, self)
|
90
92
|
end
|
91
93
|
|
@@ -167,6 +169,21 @@ module ActiveRecord
|
|
167
169
|
[:change_column_null, args]
|
168
170
|
end
|
169
171
|
|
172
|
+
def invert_add_foreign_key(args)
|
173
|
+
from_table, to_table, add_options = args
|
174
|
+
add_options ||= {}
|
175
|
+
|
176
|
+
if add_options[:name]
|
177
|
+
options = { name: add_options[:name] }
|
178
|
+
elsif add_options[:column]
|
179
|
+
options = { column: add_options[:column] }
|
180
|
+
else
|
181
|
+
options = to_table
|
182
|
+
end
|
183
|
+
|
184
|
+
[:remove_foreign_key, [from_table, options]]
|
185
|
+
end
|
186
|
+
|
170
187
|
# Forwards any missing method call to the \target.
|
171
188
|
def method_missing(method, *args, &block)
|
172
189
|
if @delegate.respond_to?(method)
|