activerecord 4.1.15 → 4.2.11.3
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 +5 -5
- data/CHANGELOG.md +1162 -1792
- data/README.rdoc +15 -10
- data/lib/active_record.rb +4 -0
- data/lib/active_record/aggregations.rb +15 -8
- data/lib/active_record/association_relation.rb +13 -0
- data/lib/active_record/associations.rb +158 -49
- data/lib/active_record/associations/alias_tracker.rb +3 -12
- data/lib/active_record/associations/association.rb +16 -4
- data/lib/active_record/associations/association_scope.rb +83 -38
- data/lib/active_record/associations/belongs_to_association.rb +28 -10
- data/lib/active_record/associations/builder/association.rb +15 -4
- data/lib/active_record/associations/builder/belongs_to.rb +7 -29
- data/lib/active_record/associations/builder/collection_association.rb +5 -1
- data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +8 -13
- data/lib/active_record/associations/builder/has_many.rb +1 -1
- 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 +63 -27
- data/lib/active_record/associations/collection_proxy.rb +29 -35
- data/lib/active_record/associations/foreign_association.rb +11 -0
- data/lib/active_record/associations/has_many_association.rb +83 -22
- data/lib/active_record/associations/has_many_through_association.rb +49 -26
- data/lib/active_record/associations/has_one_association.rb +1 -1
- data/lib/active_record/associations/join_dependency.rb +26 -13
- data/lib/active_record/associations/join_dependency/join_association.rb +25 -15
- data/lib/active_record/associations/join_dependency/join_part.rb +0 -1
- data/lib/active_record/associations/preloader.rb +36 -26
- data/lib/active_record/associations/preloader/association.rb +14 -11
- data/lib/active_record/associations/preloader/through_association.rb +4 -3
- data/lib/active_record/associations/singular_association.rb +17 -2
- data/lib/active_record/associations/through_association.rb +5 -12
- data/lib/active_record/attribute.rb +163 -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.rb +56 -94
- data/lib/active_record/attribute_methods/before_type_cast.rb +7 -2
- data/lib/active_record/attribute_methods/dirty.rb +107 -43
- data/lib/active_record/attribute_methods/primary_key.rb +7 -8
- data/lib/active_record/attribute_methods/query.rb +1 -1
- data/lib/active_record/attribute_methods/read.rb +22 -59
- data/lib/active_record/attribute_methods/serialization.rb +16 -150
- data/lib/active_record/attribute_methods/time_zone_conversion.rb +38 -40
- data/lib/active_record/attribute_methods/write.rb +9 -24
- data/lib/active_record/attribute_set.rb +81 -0
- data/lib/active_record/attribute_set/builder.rb +106 -0
- data/lib/active_record/attributes.rb +147 -0
- data/lib/active_record/autosave_association.rb +19 -12
- data/lib/active_record/base.rb +13 -24
- data/lib/active_record/callbacks.rb +6 -6
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +84 -52
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +52 -50
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +1 -1
- data/lib/active_record/connection_adapters/abstract/quoting.rb +60 -60
- data/lib/active_record/connection_adapters/abstract/savepoints.rb +1 -1
- data/lib/active_record/connection_adapters/abstract/schema_creation.rb +39 -4
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +138 -56
- data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +14 -34
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +268 -71
- data/lib/active_record/connection_adapters/abstract/transaction.rb +125 -118
- data/lib/active_record/connection_adapters/abstract_adapter.rb +171 -59
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +293 -139
- data/lib/active_record/connection_adapters/column.rb +29 -240
- data/lib/active_record/connection_adapters/connection_specification.rb +15 -24
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +16 -32
- data/lib/active_record/connection_adapters/mysql_adapter.rb +67 -144
- 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 +40 -25
- data/lib/active_record/connection_adapters/postgresql/oid.rb +29 -388
- data/lib/active_record/connection_adapters/postgresql/oid/array.rb +100 -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 +15 -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 +36 -0
- data/lib/active_record/connection_adapters/postgresql/oid/decimal.rb +13 -0
- data/lib/active_record/connection_adapters/postgresql/oid/enum.rb +19 -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 +79 -0
- data/lib/active_record/connection_adapters/postgresql/oid/specialized_string.rb +19 -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 +109 -0
- data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +21 -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/quoting.rb +46 -136
- data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +4 -4
- data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +152 -0
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +131 -43
- data/lib/active_record/connection_adapters/postgresql/utils.rb +77 -0
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +224 -477
- data/lib/active_record/connection_adapters/schema_cache.rb +14 -28
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +61 -75
- data/lib/active_record/connection_handling.rb +1 -1
- data/lib/active_record/core.rb +163 -39
- data/lib/active_record/counter_cache.rb +60 -6
- data/lib/active_record/enum.rb +9 -11
- data/lib/active_record/errors.rb +53 -30
- data/lib/active_record/explain.rb +1 -1
- data/lib/active_record/explain_subscriber.rb +1 -1
- data/lib/active_record/fixtures.rb +55 -69
- data/lib/active_record/gem_version.rb +4 -4
- data/lib/active_record/inheritance.rb +35 -10
- data/lib/active_record/integration.rb +4 -4
- data/lib/active_record/legacy_yaml_adapter.rb +30 -0
- data/lib/active_record/locking/optimistic.rb +46 -26
- data/lib/active_record/migration.rb +71 -46
- data/lib/active_record/migration/command_recorder.rb +19 -2
- data/lib/active_record/migration/join_table.rb +1 -1
- data/lib/active_record/model_schema.rb +52 -58
- data/lib/active_record/nested_attributes.rb +5 -5
- data/lib/active_record/no_touching.rb +1 -1
- data/lib/active_record/persistence.rb +46 -26
- data/lib/active_record/query_cache.rb +3 -3
- data/lib/active_record/querying.rb +10 -7
- data/lib/active_record/railtie.rb +18 -11
- data/lib/active_record/railties/databases.rake +50 -51
- data/lib/active_record/readonly_attributes.rb +0 -1
- data/lib/active_record/reflection.rb +273 -114
- data/lib/active_record/relation.rb +57 -25
- data/lib/active_record/relation/batches.rb +0 -2
- data/lib/active_record/relation/calculations.rb +41 -37
- data/lib/active_record/relation/finder_methods.rb +70 -47
- data/lib/active_record/relation/merger.rb +39 -29
- data/lib/active_record/relation/predicate_builder.rb +16 -8
- data/lib/active_record/relation/predicate_builder/array_handler.rb +32 -13
- data/lib/active_record/relation/predicate_builder/relation_handler.rb +1 -5
- data/lib/active_record/relation/query_methods.rb +114 -65
- data/lib/active_record/relation/spawn_methods.rb +3 -0
- data/lib/active_record/result.rb +18 -7
- data/lib/active_record/sanitization.rb +12 -2
- data/lib/active_record/schema.rb +0 -1
- data/lib/active_record/schema_dumper.rb +59 -28
- data/lib/active_record/schema_migration.rb +5 -4
- data/lib/active_record/scoping/default.rb +6 -4
- data/lib/active_record/scoping/named.rb +4 -0
- data/lib/active_record/serializers/xml_serializer.rb +3 -7
- data/lib/active_record/statement_cache.rb +95 -10
- data/lib/active_record/store.rb +5 -5
- data/lib/active_record/tasks/database_tasks.rb +61 -6
- data/lib/active_record/tasks/mysql_database_tasks.rb +32 -17
- data/lib/active_record/tasks/postgresql_database_tasks.rb +20 -9
- data/lib/active_record/timestamp.rb +9 -7
- data/lib/active_record/transactions.rb +53 -27
- data/lib/active_record/type.rb +23 -0
- data/lib/active_record/type/big_integer.rb +13 -0
- data/lib/active_record/type/binary.rb +50 -0
- data/lib/active_record/type/boolean.rb +31 -0
- data/lib/active_record/type/date.rb +50 -0
- data/lib/active_record/type/date_time.rb +54 -0
- data/lib/active_record/type/decimal.rb +64 -0
- data/lib/active_record/type/decimal_without_scale.rb +11 -0
- data/lib/active_record/type/decorator.rb +14 -0
- data/lib/active_record/type/float.rb +19 -0
- data/lib/active_record/type/hash_lookup_type_map.rb +23 -0
- data/lib/active_record/type/integer.rb +59 -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 +62 -0
- data/lib/active_record/type/string.rb +40 -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 +64 -0
- data/lib/active_record/type/unsigned_integer.rb +15 -0
- data/lib/active_record/type/value.rb +110 -0
- data/lib/active_record/validations.rb +25 -19
- data/lib/active_record/validations/associated.rb +5 -3
- data/lib/active_record/validations/presence.rb +5 -3
- data/lib/active_record/validations/uniqueness.rb +25 -29
- 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 +66 -11
- data/lib/active_record/connection_adapters/postgresql/cast.rb +0 -168
@@ -1,14 +1,14 @@
|
|
1
1
|
module ActiveRecord
|
2
|
-
# Returns the version of the currently loaded
|
2
|
+
# Returns the version of the currently loaded Active Record as a <tt>Gem::Version</tt>
|
3
3
|
def self.gem_version
|
4
4
|
Gem::Version.new VERSION::STRING
|
5
5
|
end
|
6
6
|
|
7
7
|
module VERSION
|
8
8
|
MAJOR = 4
|
9
|
-
MINOR =
|
10
|
-
TINY =
|
11
|
-
PRE =
|
9
|
+
MINOR = 2
|
10
|
+
TINY = 11
|
11
|
+
PRE = "3"
|
12
12
|
|
13
13
|
STRING = [MAJOR, MINOR, TINY, PRE].compact.join(".")
|
14
14
|
end
|
@@ -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
|
|
@@ -49,12 +80,12 @@ module ActiveRecord
|
|
49
80
|
end
|
50
81
|
|
51
82
|
def symbolized_base_class
|
52
|
-
ActiveSupport::Deprecation.warn(
|
83
|
+
ActiveSupport::Deprecation.warn('`ActiveRecord::Base.symbolized_base_class` is deprecated and will be removed without replacement.')
|
53
84
|
@symbolized_base_class ||= base_class.to_s.to_sym
|
54
85
|
end
|
55
86
|
|
56
87
|
def symbolized_sti_name
|
57
|
-
ActiveSupport::Deprecation.warn(
|
88
|
+
ActiveSupport::Deprecation.warn('`ActiveRecord::Base.symbolized_sti_name` is deprecated and will be removed without replacement.')
|
58
89
|
@symbolized_sti_name ||= sti_name.present? ? sti_name.to_sym : symbolized_base_class
|
59
90
|
end
|
60
91
|
|
@@ -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
|
|
@@ -0,0 +1,30 @@
|
|
1
|
+
module ActiveRecord
|
2
|
+
module LegacyYamlAdapter
|
3
|
+
def self.convert(klass, coder)
|
4
|
+
return coder unless coder.is_a?(Psych::Coder)
|
5
|
+
|
6
|
+
case coder["active_record_yaml_version"]
|
7
|
+
when 0 then coder
|
8
|
+
else
|
9
|
+
if coder["attributes"].is_a?(AttributeSet)
|
10
|
+
coder
|
11
|
+
else
|
12
|
+
Rails41.convert(klass, coder)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
module Rails41
|
18
|
+
def self.convert(klass, coder)
|
19
|
+
attributes = klass.attributes_builder
|
20
|
+
.build_from_database(coder["attributes"])
|
21
|
+
new_record = coder["attributes"][klass.primary_key].blank?
|
22
|
+
|
23
|
+
{
|
24
|
+
"attributes" => attributes,
|
25
|
+
"new_record" => new_record,
|
26
|
+
}
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -66,7 +66,16 @@ module ActiveRecord
|
|
66
66
|
send(lock_col + '=', previous_lock_value + 1)
|
67
67
|
end
|
68
68
|
|
69
|
-
def
|
69
|
+
def _create_record(attribute_names = self.attribute_names, *) # :nodoc:
|
70
|
+
if locking_enabled?
|
71
|
+
# We always want to persist the locking version, even if we don't detect
|
72
|
+
# a change from the default, since the database might have no default
|
73
|
+
attribute_names |= [self.class.locking_column]
|
74
|
+
end
|
75
|
+
super
|
76
|
+
end
|
77
|
+
|
78
|
+
def _update_record(attribute_names = self.attribute_names) #:nodoc:
|
70
79
|
return super unless locking_enabled?
|
71
80
|
return 0 if attribute_names.empty?
|
72
81
|
|
@@ -80,17 +89,15 @@ module ActiveRecord
|
|
80
89
|
begin
|
81
90
|
relation = self.class.unscoped
|
82
91
|
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
92
|
+
affected_rows = relation.where(
|
93
|
+
self.class.primary_key => id,
|
94
|
+
lock_col => previous_lock_value,
|
95
|
+
).update_all(
|
96
|
+
Hash[attributes_for_update(attribute_names).map do |name|
|
97
|
+
[name, _read_attribute(name)]
|
98
|
+
end]
|
90
99
|
)
|
91
100
|
|
92
|
-
affected_rows = self.class.connection.update stmt
|
93
|
-
|
94
101
|
unless affected_rows == 1
|
95
102
|
raise ActiveRecord::StaleObjectError.new(self, "update")
|
96
103
|
end
|
@@ -120,7 +127,7 @@ module ActiveRecord
|
|
120
127
|
if locking_enabled?
|
121
128
|
column_name = self.class.locking_column
|
122
129
|
column = self.class.columns_hash[column_name]
|
123
|
-
substitute = self.class.connection.substitute_at(column
|
130
|
+
substitute = self.class.connection.substitute_at(column)
|
124
131
|
|
125
132
|
relation = relation.where(self.class.arel_table[column_name].eq(substitute))
|
126
133
|
relation.bind_values << [column, self[column_name].to_i]
|
@@ -141,7 +148,7 @@ module ActiveRecord
|
|
141
148
|
|
142
149
|
# Set the column to use for optimistic locking. Defaults to +lock_version+.
|
143
150
|
def locking_column=(value)
|
144
|
-
|
151
|
+
clear_caches_calculated_from_columns
|
145
152
|
@locking_column = value.to_s
|
146
153
|
end
|
147
154
|
|
@@ -151,12 +158,6 @@ module ActiveRecord
|
|
151
158
|
@locking_column
|
152
159
|
end
|
153
160
|
|
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
161
|
# Reset the column used for optimistic locking back to the +lock_version+ default.
|
161
162
|
def reset_locking_column
|
162
163
|
self.locking_column = DEFAULT_LOCKING_COLUMN
|
@@ -169,18 +170,37 @@ module ActiveRecord
|
|
169
170
|
super
|
170
171
|
end
|
171
172
|
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
173
|
+
private
|
174
|
+
|
175
|
+
# We need to apply this decorator here, rather than on module inclusion. The closure
|
176
|
+
# created by the matcher would otherwise evaluate for `ActiveRecord::Base`, not the
|
177
|
+
# sub class being decorated. As such, changes to `lock_optimistically`, or
|
178
|
+
# `locking_column` would not be picked up.
|
179
|
+
def inherited(subclass)
|
180
|
+
subclass.class_eval do
|
181
|
+
is_lock_column = ->(name, _) { lock_optimistically && name == locking_column }
|
182
|
+
decorate_matching_attribute_types(is_lock_column, :_optimistic_locking) do |type|
|
183
|
+
LockingType.new(type)
|
178
184
|
end
|
179
|
-
|
180
|
-
defaults
|
181
185
|
end
|
186
|
+
super
|
182
187
|
end
|
183
188
|
end
|
184
189
|
end
|
190
|
+
|
191
|
+
class LockingType < SimpleDelegator # :nodoc:
|
192
|
+
def type_cast_from_database(value)
|
193
|
+
# `nil` *should* be changed to 0
|
194
|
+
super.to_i
|
195
|
+
end
|
196
|
+
|
197
|
+
def init_with(coder)
|
198
|
+
__setobj__(coder['subtype'])
|
199
|
+
end
|
200
|
+
|
201
|
+
def encode_with(coder)
|
202
|
+
coder['subtype'] = __getobj__
|
203
|
+
end
|
204
|
+
end
|
185
205
|
end
|
186
206
|
end
|
@@ -39,7 +39,7 @@ module ActiveRecord
|
|
39
39
|
|
40
40
|
class PendingMigrationError < MigrationError#:nodoc:
|
41
41
|
def initialize
|
42
|
-
if defined?(Rails)
|
42
|
+
if defined?(Rails.env)
|
43
43
|
super("Migrations are pending. To resolve this issue, run:\n\n\tbin/rake db:migrate RAILS_ENV=#{::Rails.env}")
|
44
44
|
else
|
45
45
|
super("Migrations are pending. To resolve this issue, run:\n\n\tbin/rake db:migrate")
|
@@ -161,21 +161,14 @@ module ActiveRecord
|
|
161
161
|
# in the <tt>db/migrate/</tt> directory where <tt>timestamp</tt> is the
|
162
162
|
# UTC formatted date and time that the migration was generated.
|
163
163
|
#
|
164
|
-
# You may then edit the <tt>up</tt> and <tt>down</tt> methods of
|
165
|
-
# MyNewMigration.
|
166
|
-
#
|
167
164
|
# There is a special syntactic shortcut to generate migrations that add fields to a table.
|
168
165
|
#
|
169
166
|
# rails generate migration add_fieldname_to_tablename fieldname:string
|
170
167
|
#
|
171
168
|
# This will generate the file <tt>timestamp_add_fieldname_to_tablename</tt>, which will look like this:
|
172
169
|
# class AddFieldnameToTablename < ActiveRecord::Migration
|
173
|
-
# def
|
174
|
-
# add_column :tablenames, :
|
175
|
-
# end
|
176
|
-
#
|
177
|
-
# def down
|
178
|
-
# remove_column :tablenames, :fieldname
|
170
|
+
# def change
|
171
|
+
# add_column :tablenames, :field, :string
|
179
172
|
# end
|
180
173
|
# end
|
181
174
|
#
|
@@ -188,14 +181,17 @@ module ActiveRecord
|
|
188
181
|
#
|
189
182
|
# To roll the database back to a previous migration version, use
|
190
183
|
# <tt>rake db:migrate VERSION=X</tt> where <tt>X</tt> is the version to which
|
191
|
-
# you wish to downgrade.
|
192
|
-
# <tt>
|
193
|
-
#
|
184
|
+
# you wish to downgrade. Alternatively, you can also use the STEP option if you
|
185
|
+
# wish to rollback last few migrations. <tt>rake db:migrate STEP=2</tt> will rollback
|
186
|
+
# the latest two migrations.
|
187
|
+
#
|
188
|
+
# If any of the migrations throw an <tt>ActiveRecord::IrreversibleMigration</tt> exception,
|
189
|
+
# that step will fail and you'll have some manual work to do.
|
194
190
|
#
|
195
191
|
# == Database support
|
196
192
|
#
|
197
193
|
# Migrations are currently supported in MySQL, PostgreSQL, SQLite,
|
198
|
-
# SQL Server,
|
194
|
+
# SQL Server, and Oracle (all supported databases except DB2).
|
199
195
|
#
|
200
196
|
# == More examples
|
201
197
|
#
|
@@ -311,9 +307,8 @@ module ActiveRecord
|
|
311
307
|
#
|
312
308
|
# == Reversible Migrations
|
313
309
|
#
|
314
|
-
# Starting with Rails 3.1, you will be able to define reversible migrations.
|
315
310
|
# Reversible migrations are migrations that know how to go +down+ for you.
|
316
|
-
# You simply supply the +up+ logic, and the Migration system
|
311
|
+
# You simply supply the +up+ logic, and the Migration system figures out
|
317
312
|
# how to execute the down commands for you.
|
318
313
|
#
|
319
314
|
# To define a reversible migration, define the +change+ method in your
|
@@ -372,13 +367,21 @@ module ActiveRecord
|
|
372
367
|
end
|
373
368
|
|
374
369
|
def call(env)
|
375
|
-
|
376
|
-
|
377
|
-
|
378
|
-
|
370
|
+
if connection.supports_migrations?
|
371
|
+
mtime = ActiveRecord::Migrator.last_migration.mtime.to_i
|
372
|
+
if @last_check < mtime
|
373
|
+
ActiveRecord::Migration.check_pending!(connection)
|
374
|
+
@last_check = mtime
|
375
|
+
end
|
379
376
|
end
|
380
377
|
@app.call(env)
|
381
378
|
end
|
379
|
+
|
380
|
+
private
|
381
|
+
|
382
|
+
def connection
|
383
|
+
ActiveRecord::Base.connection
|
384
|
+
end
|
382
385
|
end
|
383
386
|
|
384
387
|
class << self
|
@@ -390,7 +393,7 @@ module ActiveRecord
|
|
390
393
|
end
|
391
394
|
|
392
395
|
def load_schema_if_pending!
|
393
|
-
if ActiveRecord::Migrator.needs_migration?
|
396
|
+
if ActiveRecord::Migrator.needs_migration? || !ActiveRecord::Migrator.any_migrations?
|
394
397
|
# Roundrip to Rake to allow plugins to hook into database initialization.
|
395
398
|
FileUtils.cd Rails.root do
|
396
399
|
current_config = Base.connection_config
|
@@ -417,7 +420,10 @@ module ActiveRecord
|
|
417
420
|
new.migrate direction
|
418
421
|
end
|
419
422
|
|
420
|
-
# Disable
|
423
|
+
# Disable the transaction wrapping this migration.
|
424
|
+
# You can still create your own transactions even after calling #disable_ddl_transaction!
|
425
|
+
#
|
426
|
+
# For more details read the {"Transactional Migrations" section above}[rdoc-ref:Migration].
|
421
427
|
def disable_ddl_transaction!
|
422
428
|
@disable_ddl_transaction = true
|
423
429
|
end
|
@@ -649,7 +655,10 @@ module ActiveRecord
|
|
649
655
|
unless @connection.respond_to? :revert
|
650
656
|
unless arguments.empty? || [:execute, :enable_extension, :disable_extension].include?(method)
|
651
657
|
arguments[0] = proper_table_name(arguments.first, table_name_options)
|
652
|
-
|
658
|
+
if [:rename_table, :add_foreign_key].include?(method) ||
|
659
|
+
(method == :remove_foreign_key && !arguments.second.is_a?(Hash))
|
660
|
+
arguments[1] = proper_table_name(arguments.second, table_name_options)
|
661
|
+
end
|
653
662
|
end
|
654
663
|
end
|
655
664
|
return super unless connection.respond_to?(method)
|
@@ -811,22 +820,22 @@ module ActiveRecord
|
|
811
820
|
migrations = migrations(migrations_paths)
|
812
821
|
migrations.select! { |m| yield m } if block_given?
|
813
822
|
|
814
|
-
|
823
|
+
new(:up, migrations, target_version).migrate
|
815
824
|
end
|
816
825
|
|
817
826
|
def down(migrations_paths, target_version = nil, &block)
|
818
827
|
migrations = migrations(migrations_paths)
|
819
828
|
migrations.select! { |m| yield m } if block_given?
|
820
829
|
|
821
|
-
|
830
|
+
new(:down, migrations, target_version).migrate
|
822
831
|
end
|
823
832
|
|
824
833
|
def run(direction, migrations_paths, target_version)
|
825
|
-
|
834
|
+
new(direction, migrations(migrations_paths), target_version).run
|
826
835
|
end
|
827
836
|
|
828
837
|
def open(migrations_paths)
|
829
|
-
|
838
|
+
new(:up, migrations(migrations_paths), nil)
|
830
839
|
end
|
831
840
|
|
832
841
|
def schema_migrations_table_name
|
@@ -849,6 +858,10 @@ module ActiveRecord
|
|
849
858
|
(migrations(migrations_paths).collect(&:version) - get_all_versions(connection)).size > 0
|
850
859
|
end
|
851
860
|
|
861
|
+
def any_migrations?
|
862
|
+
migrations(migrations_paths).any?
|
863
|
+
end
|
864
|
+
|
852
865
|
def last_version
|
853
866
|
last_migration.version
|
854
867
|
end
|
@@ -857,19 +870,6 @@ module ActiveRecord
|
|
857
870
|
migrations(migrations_paths).last || NullMigration.new
|
858
871
|
end
|
859
872
|
|
860
|
-
def proper_table_name(name, options = {})
|
861
|
-
ActiveSupport::Deprecation.warn "ActiveRecord::Migrator.proper_table_name is deprecated and will be removed in Rails 4.2. Use the proper_table_name instance method on ActiveRecord::Migration instead"
|
862
|
-
options = {
|
863
|
-
table_name_prefix: ActiveRecord::Base.table_name_prefix,
|
864
|
-
table_name_suffix: ActiveRecord::Base.table_name_suffix
|
865
|
-
}.merge(options)
|
866
|
-
if name.respond_to? :table_name
|
867
|
-
name.table_name
|
868
|
-
else
|
869
|
-
"#{options[:table_name_prefix]}#{name}#{options[:table_name_suffix]}"
|
870
|
-
end
|
871
|
-
end
|
872
|
-
|
873
873
|
def migrations_paths
|
874
874
|
@migrations_paths ||= ['db/migrate']
|
875
875
|
# just to not break things if someone uses: migration_path = some_string
|
@@ -880,14 +880,15 @@ module ActiveRecord
|
|
880
880
|
migrations_paths.first
|
881
881
|
end
|
882
882
|
|
883
|
+
def parse_migration_filename(filename) # :nodoc:
|
884
|
+
File.basename(filename).scan(/\A([0-9]+)_([_a-z0-9]*)\.?([_a-z0-9]*)?\.rb\z/).first
|
885
|
+
end
|
886
|
+
|
883
887
|
def migrations(paths)
|
884
888
|
paths = Array(paths)
|
885
889
|
|
886
|
-
|
887
|
-
|
888
|
-
migrations = files.map do |file|
|
889
|
-
version, name, scope = file.scan(/([0-9]+)_([_a-z0-9]*)\.?([_a-z0-9]*)?\.rb\z/).first
|
890
|
-
|
890
|
+
migrations = migration_files(paths).map do |file|
|
891
|
+
version, name, scope = parse_migration_filename(file)
|
891
892
|
raise IllegalMigrationNameError.new(file) unless version
|
892
893
|
version = version.to_i
|
893
894
|
name = name.camelize
|
@@ -898,10 +899,34 @@ module ActiveRecord
|
|
898
899
|
migrations.sort_by(&:version)
|
899
900
|
end
|
900
901
|
|
902
|
+
def migrations_status(paths)
|
903
|
+
paths = Array(paths)
|
904
|
+
|
905
|
+
db_list = ActiveRecord::SchemaMigration.normalized_versions
|
906
|
+
|
907
|
+
file_list = migration_files(paths).map do |file|
|
908
|
+
version, name, scope = parse_migration_filename(file)
|
909
|
+
raise IllegalMigrationNameError.new(file) unless version
|
910
|
+
version = ActiveRecord::SchemaMigration.normalize_migration_number(version)
|
911
|
+
status = db_list.delete(version) ? "up" : "down"
|
912
|
+
[status, version, (name + scope).humanize]
|
913
|
+
end.compact
|
914
|
+
|
915
|
+
db_list.map! do |version|
|
916
|
+
["up", version, "********** NO FILE **********"]
|
917
|
+
end
|
918
|
+
|
919
|
+
(db_list + file_list).sort_by { |_, version, _| version }
|
920
|
+
end
|
921
|
+
|
922
|
+
def migration_files(paths)
|
923
|
+
Dir[*paths.flat_map { |path| "#{path}/**/[0-9]*_*.rb" }]
|
924
|
+
end
|
925
|
+
|
901
926
|
private
|
902
927
|
|
903
928
|
def move(direction, migrations_paths, steps)
|
904
|
-
migrator =
|
929
|
+
migrator = new(direction, migrations(migrations_paths))
|
905
930
|
start_index = migrator.migrations.index(migrator.current_migration)
|
906
931
|
|
907
932
|
if start_index
|