activerecord 4.1.0 → 4.2.0
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 +776 -1330
- data/README.rdoc +15 -10
- data/lib/active_record/aggregations.rb +12 -8
- data/lib/active_record/association_relation.rb +4 -0
- data/lib/active_record/associations/alias_tracker.rb +14 -13
- data/lib/active_record/associations/association.rb +2 -2
- data/lib/active_record/associations/association_scope.rb +83 -43
- data/lib/active_record/associations/belongs_to_association.rb +15 -5
- 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/has_and_belongs_to_many.rb +9 -6
- 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 +66 -29
- data/lib/active_record/associations/collection_proxy.rb +22 -26
- data/lib/active_record/associations/has_many_association.rb +65 -18
- data/lib/active_record/associations/has_many_through_association.rb +55 -27
- data/lib/active_record/associations/has_one_association.rb +0 -1
- data/lib/active_record/associations/join_dependency/join_association.rb +19 -15
- data/lib/active_record/associations/join_dependency/join_part.rb +0 -1
- data/lib/active_record/associations/join_dependency.rb +20 -12
- data/lib/active_record/associations/preloader/association.rb +34 -11
- data/lib/active_record/associations/preloader/through_association.rb +4 -3
- data/lib/active_record/associations/preloader.rb +49 -59
- data/lib/active_record/associations/singular_association.rb +25 -4
- data/lib/active_record/associations/through_association.rb +23 -14
- data/lib/active_record/associations.rb +171 -42
- data/lib/active_record/attribute.rb +149 -0
- data/lib/active_record/attribute_assignment.rb +18 -10
- 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 +98 -44
- data/lib/active_record/attribute_methods/primary_key.rb +14 -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 +37 -147
- data/lib/active_record/attribute_methods/time_zone_conversion.rb +34 -28
- data/lib/active_record/attribute_methods/write.rb +14 -21
- data/lib/active_record/attribute_methods.rb +67 -94
- data/lib/active_record/attribute_set/builder.rb +86 -0
- data/lib/active_record/attribute_set.rb +77 -0
- data/lib/active_record/attributes.rb +139 -0
- data/lib/active_record/autosave_association.rb +45 -38
- data/lib/active_record/base.rb +10 -20
- data/lib/active_record/callbacks.rb +7 -7
- data/lib/active_record/coders/json.rb +13 -0
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +78 -52
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +38 -59
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +1 -0
- data/lib/active_record/connection_adapters/abstract/quoting.rb +59 -55
- data/lib/active_record/connection_adapters/abstract/schema_creation.rb +46 -5
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +126 -54
- data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +14 -34
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +198 -64
- data/lib/active_record/connection_adapters/abstract/transaction.rb +126 -114
- data/lib/active_record/connection_adapters/abstract_adapter.rb +154 -55
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +240 -135
- data/lib/active_record/connection_adapters/column.rb +28 -239
- data/lib/active_record/connection_adapters/connection_specification.rb +16 -25
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +20 -22
- data/lib/active_record/connection_adapters/mysql_adapter.rb +65 -149
- 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 -27
- data/lib/active_record/connection_adapters/postgresql/oid/array.rb +99 -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 +79 -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 +97 -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/oid.rb +29 -374
- data/lib/active_record/connection_adapters/postgresql/quoting.rb +55 -135
- 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 +127 -38
- data/lib/active_record/connection_adapters/postgresql/utils.rb +77 -0
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +220 -466
- data/lib/active_record/connection_adapters/schema_cache.rb +14 -28
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +66 -61
- data/lib/active_record/connection_handling.rb +3 -3
- data/lib/active_record/core.rb +143 -32
- data/lib/active_record/counter_cache.rb +60 -7
- data/lib/active_record/enum.rb +10 -11
- data/lib/active_record/errors.rb +49 -27
- data/lib/active_record/explain.rb +1 -1
- data/lib/active_record/fixtures.rb +56 -70
- data/lib/active_record/gem_version.rb +2 -2
- data/lib/active_record/inheritance.rb +35 -10
- data/lib/active_record/integration.rb +4 -4
- data/lib/active_record/locking/optimistic.rb +35 -17
- data/lib/active_record/log_subscriber.rb +1 -1
- 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 +52 -49
- data/lib/active_record/model_schema.rb +49 -57
- data/lib/active_record/nested_attributes.rb +7 -7
- data/lib/active_record/null_relation.rb +19 -5
- data/lib/active_record/persistence.rb +50 -31
- data/lib/active_record/query_cache.rb +3 -3
- data/lib/active_record/querying.rb +10 -7
- data/lib/active_record/railtie.rb +14 -11
- data/lib/active_record/railties/databases.rake +56 -54
- data/lib/active_record/readonly_attributes.rb +0 -1
- data/lib/active_record/reflection.rb +286 -102
- data/lib/active_record/relation/batches.rb +0 -1
- data/lib/active_record/relation/calculations.rb +39 -31
- data/lib/active_record/relation/delegation.rb +2 -2
- data/lib/active_record/relation/finder_methods.rb +80 -36
- data/lib/active_record/relation/merger.rb +25 -30
- data/lib/active_record/relation/predicate_builder/array_handler.rb +31 -13
- data/lib/active_record/relation/predicate_builder/relation_handler.rb +1 -1
- data/lib/active_record/relation/predicate_builder.rb +11 -10
- data/lib/active_record/relation/query_methods.rb +141 -55
- data/lib/active_record/relation/spawn_methods.rb +3 -0
- data/lib/active_record/relation.rb +69 -30
- 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 +58 -26
- data/lib/active_record/schema_migration.rb +11 -0
- data/lib/active_record/scoping/default.rb +8 -7
- 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 +19 -10
- data/lib/active_record/tasks/database_tasks.rb +73 -7
- data/lib/active_record/tasks/mysql_database_tasks.rb +3 -2
- 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 +11 -9
- data/lib/active_record/transactions.rb +37 -21
- 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 +30 -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/decorator.rb +14 -0
- data/lib/active_record/type/float.rb +19 -0
- data/lib/active_record/type/hash_lookup_type_map.rb +17 -0
- data/lib/active_record/type/integer.rb +55 -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 +56 -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 +64 -0
- data/lib/active_record/type/unsigned_integer.rb +15 -0
- data/lib/active_record/type/value.rb +101 -0
- data/lib/active_record/type.rb +23 -0
- data/lib/active_record/validations/associated.rb +5 -3
- data/lib/active_record/validations/presence.rb +6 -4
- data/lib/active_record/validations/uniqueness.rb +11 -17
- data/lib/active_record/validations.rb +25 -19
- data/lib/active_record.rb +3 -0
- data/lib/rails/generators/active_record/migration/migration_generator.rb +8 -4
- data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb +4 -1
- data/lib/rails/generators/active_record/migration/templates/migration.rb +6 -0
- data/lib/rails/generators/active_record/model/templates/model.rb +1 -1
- metadata +65 -10
- data/lib/active_record/connection_adapters/postgresql/cast.rb +0 -168
@@ -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
|
|
@@ -66,7 +66,7 @@ module ActiveRecord
|
|
66
66
|
send(lock_col + '=', previous_lock_value + 1)
|
67
67
|
end
|
68
68
|
|
69
|
-
def
|
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
|
|
@@ -120,7 +120,7 @@ module ActiveRecord
|
|
120
120
|
if locking_enabled?
|
121
121
|
column_name = self.class.locking_column
|
122
122
|
column = self.class.columns_hash[column_name]
|
123
|
-
substitute = self.class.connection.substitute_at(column
|
123
|
+
substitute = self.class.connection.substitute_at(column)
|
124
124
|
|
125
125
|
relation = relation.where(self.class.arel_table[column_name].eq(substitute))
|
126
126
|
relation.bind_values << [column, self[column_name].to_i]
|
@@ -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
|
@@ -25,7 +25,7 @@ module ActiveRecord
|
|
25
25
|
if column.binary?
|
26
26
|
# This specifically deals with the PG adapter that casts bytea columns into a Hash.
|
27
27
|
value = value[:value] if value.is_a?(Hash)
|
28
|
-
value = "<#{value.bytesize} bytes of binary data>"
|
28
|
+
value = value ? "<#{value.bytesize} bytes of binary data>" : "<NULL binary data>"
|
29
29
|
end
|
30
30
|
|
31
31
|
[column.name, value]
|
@@ -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)
|
@@ -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
|
#
|
@@ -372,13 +368,21 @@ module ActiveRecord
|
|
372
368
|
end
|
373
369
|
|
374
370
|
def call(env)
|
375
|
-
|
376
|
-
|
377
|
-
|
378
|
-
|
371
|
+
if connection.supports_migrations?
|
372
|
+
mtime = ActiveRecord::Migrator.last_migration.mtime.to_i
|
373
|
+
if @last_check < mtime
|
374
|
+
ActiveRecord::Migration.check_pending!(connection)
|
375
|
+
@last_check = mtime
|
376
|
+
end
|
379
377
|
end
|
380
378
|
@app.call(env)
|
381
379
|
end
|
380
|
+
|
381
|
+
private
|
382
|
+
|
383
|
+
def connection
|
384
|
+
ActiveRecord::Base.connection
|
385
|
+
end
|
382
386
|
end
|
383
387
|
|
384
388
|
class << self
|
@@ -390,8 +394,15 @@ module ActiveRecord
|
|
390
394
|
end
|
391
395
|
|
392
396
|
def load_schema_if_pending!
|
393
|
-
if ActiveRecord::Migrator.needs_migration?
|
394
|
-
|
397
|
+
if ActiveRecord::Migrator.needs_migration? || !ActiveRecord::Migrator.any_migrations?
|
398
|
+
# Roundrip to Rake to allow plugins to hook into database initialization.
|
399
|
+
FileUtils.cd Rails.root do
|
400
|
+
current_config = Base.connection_config
|
401
|
+
Base.clear_all_connections!
|
402
|
+
system("bin/rake db:test:prepare")
|
403
|
+
# Establish a new connection, the old database may be gone (db:test:prepare uses purge)
|
404
|
+
Base.establish_connection(current_config)
|
405
|
+
end
|
395
406
|
check_pending!
|
396
407
|
end
|
397
408
|
end
|
@@ -640,9 +651,11 @@ module ActiveRecord
|
|
640
651
|
|
641
652
|
say_with_time "#{method}(#{arg_list})" do
|
642
653
|
unless @connection.respond_to? :revert
|
643
|
-
unless arguments.empty? ||
|
654
|
+
unless arguments.empty? || [:execute, :enable_extension, :disable_extension].include?(method)
|
644
655
|
arguments[0] = proper_table_name(arguments.first, table_name_options)
|
645
|
-
|
656
|
+
if [:rename_table, :add_foreign_key].include?(method)
|
657
|
+
arguments[1] = proper_table_name(arguments.second, table_name_options)
|
658
|
+
end
|
646
659
|
end
|
647
660
|
end
|
648
661
|
return super unless connection.respond_to?(method)
|
@@ -711,7 +724,7 @@ module ActiveRecord
|
|
711
724
|
if ActiveRecord::Base.timestamped_migrations
|
712
725
|
[Time.now.utc.strftime("%Y%m%d%H%M%S"), "%.14d" % number].max
|
713
726
|
else
|
714
|
-
|
727
|
+
SchemaMigration.normalize_migration_number(number)
|
715
728
|
end
|
716
729
|
end
|
717
730
|
|
@@ -804,43 +817,46 @@ module ActiveRecord
|
|
804
817
|
migrations = migrations(migrations_paths)
|
805
818
|
migrations.select! { |m| yield m } if block_given?
|
806
819
|
|
807
|
-
|
820
|
+
new(:up, migrations, target_version).migrate
|
808
821
|
end
|
809
822
|
|
810
823
|
def down(migrations_paths, target_version = nil, &block)
|
811
824
|
migrations = migrations(migrations_paths)
|
812
825
|
migrations.select! { |m| yield m } if block_given?
|
813
826
|
|
814
|
-
|
827
|
+
new(:down, migrations, target_version).migrate
|
815
828
|
end
|
816
829
|
|
817
830
|
def run(direction, migrations_paths, target_version)
|
818
|
-
|
831
|
+
new(direction, migrations(migrations_paths), target_version).run
|
819
832
|
end
|
820
833
|
|
821
834
|
def open(migrations_paths)
|
822
|
-
|
835
|
+
new(:up, migrations(migrations_paths), nil)
|
823
836
|
end
|
824
837
|
|
825
838
|
def schema_migrations_table_name
|
826
839
|
SchemaMigration.table_name
|
827
840
|
end
|
828
841
|
|
829
|
-
def get_all_versions
|
830
|
-
|
842
|
+
def get_all_versions(connection = Base.connection)
|
843
|
+
if connection.table_exists?(schema_migrations_table_name)
|
844
|
+
SchemaMigration.all.map { |x| x.version.to_i }.sort
|
845
|
+
else
|
846
|
+
[]
|
847
|
+
end
|
831
848
|
end
|
832
849
|
|
833
850
|
def current_version(connection = Base.connection)
|
834
|
-
|
835
|
-
if connection.table_exists?(sm_table)
|
836
|
-
get_all_versions.max || 0
|
837
|
-
else
|
838
|
-
0
|
839
|
-
end
|
851
|
+
get_all_versions(connection).max || 0
|
840
852
|
end
|
841
853
|
|
842
854
|
def needs_migration?(connection = Base.connection)
|
843
|
-
|
855
|
+
(migrations(migrations_paths).collect(&:version) - get_all_versions(connection)).size > 0
|
856
|
+
end
|
857
|
+
|
858
|
+
def any_migrations?
|
859
|
+
migrations(migrations_paths).any?
|
844
860
|
end
|
845
861
|
|
846
862
|
def last_version
|
@@ -851,19 +867,6 @@ module ActiveRecord
|
|
851
867
|
migrations(migrations_paths).last || NullMigration.new
|
852
868
|
end
|
853
869
|
|
854
|
-
def proper_table_name(name, options = {})
|
855
|
-
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"
|
856
|
-
options = {
|
857
|
-
table_name_prefix: ActiveRecord::Base.table_name_prefix,
|
858
|
-
table_name_suffix: ActiveRecord::Base.table_name_suffix
|
859
|
-
}.merge(options)
|
860
|
-
if name.respond_to? :table_name
|
861
|
-
name.table_name
|
862
|
-
else
|
863
|
-
"#{options[:table_name_prefix]}#{name}#{options[:table_name_suffix]}"
|
864
|
-
end
|
865
|
-
end
|
866
|
-
|
867
870
|
def migrations_paths
|
868
871
|
@migrations_paths ||= ['db/migrate']
|
869
872
|
# just to not break things if someone uses: migration_path = some_string
|
@@ -895,7 +898,7 @@ module ActiveRecord
|
|
895
898
|
private
|
896
899
|
|
897
900
|
def move(direction, migrations_paths, steps)
|
898
|
-
migrator =
|
901
|
+
migrator = new(direction, migrations(migrations_paths))
|
899
902
|
start_index = migrator.migrations.index(migrator.current_migration)
|
900
903
|
|
901
904
|
if start_index
|
@@ -29,6 +29,10 @@ module ActiveRecord
|
|
29
29
|
# :singleton-method:
|
30
30
|
# Works like +table_name_prefix+, but appends instead of prepends (set to "_basecamp" gives "projects_basecamp",
|
31
31
|
# "people_basecamp"). By default, the suffix is the empty string.
|
32
|
+
#
|
33
|
+
# If you are organising your models within modules, you can add a suffix to the models within
|
34
|
+
# a namespace by defining a singleton method in the parent module called table_name_suffix which
|
35
|
+
# returns your chosen suffix.
|
32
36
|
class_attribute :table_name_suffix, instance_writer: false
|
33
37
|
self.table_name_suffix = ""
|
34
38
|
|
@@ -47,6 +51,19 @@ module ActiveRecord
|
|
47
51
|
self.pluralize_table_names = true
|
48
52
|
|
49
53
|
self.inheritance_column = 'type'
|
54
|
+
|
55
|
+
delegate :type_for_attribute, to: :class
|
56
|
+
end
|
57
|
+
|
58
|
+
# Derives the join table name for +first_table+ and +second_table+. The
|
59
|
+
# table names appear in alphabetical order. A common prefix is removed
|
60
|
+
# (useful for namespaced models like Music::Artist and Music::Record):
|
61
|
+
#
|
62
|
+
# artists, records => artists_records
|
63
|
+
# records, artists => artists_records
|
64
|
+
# music_artists, music_records => music_artists_records
|
65
|
+
def self.derive_join_table_name(first_table, second_table) # :nodoc:
|
66
|
+
[first_table.to_s, second_table.to_s].sort.join("\0").gsub(/^(.*_)(.+)\0\1(.+)/, '\1\2_\3').tr("\0", "_")
|
50
67
|
end
|
51
68
|
|
52
69
|
module ClassMethods
|
@@ -153,6 +170,10 @@ module ActiveRecord
|
|
153
170
|
(parents.detect{ |p| p.respond_to?(:table_name_prefix) } || self).table_name_prefix
|
154
171
|
end
|
155
172
|
|
173
|
+
def full_table_name_suffix #:nodoc:
|
174
|
+
(parents.detect {|p| p.respond_to?(:table_name_suffix) } || self).table_name_suffix
|
175
|
+
end
|
176
|
+
|
156
177
|
# Defines the name of the table column which will store the class name on single-table
|
157
178
|
# inheritance situations.
|
158
179
|
#
|
@@ -190,7 +211,7 @@ module ActiveRecord
|
|
190
211
|
# given block. This is required for Oracle and is useful for any
|
191
212
|
# database which relies on sequences for primary key generation.
|
192
213
|
#
|
193
|
-
# If a sequence name is not explicitly set when using Oracle
|
214
|
+
# If a sequence name is not explicitly set when using Oracle,
|
194
215
|
# it will default to the commonly used pattern of: #{table_name}_seq
|
195
216
|
#
|
196
217
|
# If a sequence name is not explicitly set when using PostgreSQL, it
|
@@ -209,50 +230,29 @@ module ActiveRecord
|
|
209
230
|
connection.schema_cache.table_exists?(table_name)
|
210
231
|
end
|
211
232
|
|
212
|
-
|
213
|
-
|
214
|
-
@columns ||= connection.schema_cache.columns(table_name).map do |col|
|
215
|
-
col = col.dup
|
216
|
-
col.primary = (col.name == primary_key)
|
217
|
-
col
|
218
|
-
end
|
219
|
-
end
|
220
|
-
|
221
|
-
# Returns a hash of column objects for the table associated with this class.
|
222
|
-
def columns_hash
|
223
|
-
@columns_hash ||= Hash[columns.map { |c| [c.name, c] }]
|
233
|
+
def attributes_builder # :nodoc:
|
234
|
+
@attributes_builder ||= AttributeSet::Builder.new(column_types, primary_key)
|
224
235
|
end
|
225
236
|
|
226
237
|
def column_types # :nodoc:
|
227
|
-
@column_types ||=
|
228
|
-
|
229
|
-
|
230
|
-
def decorate_columns(columns_hash) # :nodoc:
|
231
|
-
return if columns_hash.empty?
|
232
|
-
|
233
|
-
@serialized_column_names ||= self.columns_hash.keys.find_all do |name|
|
234
|
-
serialized_attributes.key?(name)
|
235
|
-
end
|
236
|
-
|
237
|
-
@serialized_column_names.each do |name|
|
238
|
-
columns_hash[name] = AttributeMethods::Serialization::Type.new(columns_hash[name])
|
239
|
-
end
|
240
|
-
|
241
|
-
@time_zone_column_names ||= self.columns_hash.find_all do |name, col|
|
242
|
-
create_time_zone_conversion_attribute?(name, col)
|
243
|
-
end.map!(&:first)
|
244
|
-
|
245
|
-
@time_zone_column_names.each do |name|
|
246
|
-
columns_hash[name] = AttributeMethods::TimeZoneConversion::Type.new(columns_hash[name])
|
238
|
+
@column_types ||= columns_hash.transform_values(&:cast_type).tap do |h|
|
239
|
+
h.default = Type::Value.new
|
247
240
|
end
|
241
|
+
end
|
248
242
|
|
249
|
-
|
243
|
+
def type_for_attribute(attr_name) # :nodoc:
|
244
|
+
column_types[attr_name]
|
250
245
|
end
|
251
246
|
|
252
247
|
# Returns a hash where the keys are column names and the values are
|
253
248
|
# default values when instantiating the AR object for this table.
|
254
249
|
def column_defaults
|
255
|
-
|
250
|
+
_default_attributes.to_hash
|
251
|
+
end
|
252
|
+
|
253
|
+
def _default_attributes # :nodoc:
|
254
|
+
@default_attributes ||= attributes_builder.build_from_database(
|
255
|
+
raw_default_values)
|
256
256
|
end
|
257
257
|
|
258
258
|
# Returns an array of column names as strings.
|
@@ -263,7 +263,7 @@ module ActiveRecord
|
|
263
263
|
# Returns an array of column objects where the primary id, all columns ending in "_id" or "_count",
|
264
264
|
# and columns used for single table inheritance have been removed.
|
265
265
|
def content_columns
|
266
|
-
@content_columns ||= columns.reject { |c| c.
|
266
|
+
@content_columns ||= columns.reject { |c| c.name == primary_key || c.name =~ /(_id|_count)$/ || c.name == inheritance_column }
|
267
267
|
end
|
268
268
|
|
269
269
|
# Resets all the cached information about columns, which will cause them
|
@@ -297,26 +297,13 @@ module ActiveRecord
|
|
297
297
|
undefine_attribute_methods
|
298
298
|
connection.schema_cache.clear_table_cache!(table_name) if table_exists?
|
299
299
|
|
300
|
-
@arel_engine
|
301
|
-
@
|
302
|
-
@
|
303
|
-
@
|
304
|
-
@
|
305
|
-
@
|
306
|
-
@
|
307
|
-
@dynamic_methods_hash = nil
|
308
|
-
@inheritance_column = nil unless defined?(@explicit_inheritance_column) && @explicit_inheritance_column
|
309
|
-
@relation = nil
|
310
|
-
@serialized_column_names = nil
|
311
|
-
@time_zone_column_names = nil
|
312
|
-
@cached_time_zone = nil
|
313
|
-
end
|
314
|
-
|
315
|
-
# This is a hook for use by modules that need to do extra stuff to
|
316
|
-
# attributes when they are initialized. (e.g. attribute
|
317
|
-
# serialization)
|
318
|
-
def initialize_attributes(attributes, options = {}) #:nodoc:
|
319
|
-
attributes
|
300
|
+
@arel_engine = nil
|
301
|
+
@column_names = nil
|
302
|
+
@column_types = nil
|
303
|
+
@content_columns = nil
|
304
|
+
@default_attributes = nil
|
305
|
+
@inheritance_column = nil unless defined?(@explicit_inheritance_column) && @explicit_inheritance_column
|
306
|
+
@relation = nil
|
320
307
|
end
|
321
308
|
|
322
309
|
private
|
@@ -337,12 +324,17 @@ module ActiveRecord
|
|
337
324
|
contained = contained.singularize if parent.pluralize_table_names
|
338
325
|
contained += '_'
|
339
326
|
end
|
340
|
-
|
327
|
+
|
328
|
+
"#{full_table_name_prefix}#{contained}#{undecorated_table_name(name)}#{full_table_name_suffix}"
|
341
329
|
else
|
342
330
|
# STI subclasses always use their superclass' table.
|
343
331
|
base.table_name
|
344
332
|
end
|
345
333
|
end
|
334
|
+
|
335
|
+
def raw_default_values
|
336
|
+
columns_hash.transform_values(&:default)
|
337
|
+
end
|
346
338
|
end
|
347
339
|
end
|
348
340
|
end
|
@@ -305,7 +305,7 @@ module ActiveRecord
|
|
305
305
|
options[:reject_if] = REJECT_ALL_BLANK_PROC if options[:reject_if] == :all_blank
|
306
306
|
|
307
307
|
attr_names.each do |association_name|
|
308
|
-
if reflection =
|
308
|
+
if reflection = _reflect_on_association(association_name)
|
309
309
|
reflection.autosave = true
|
310
310
|
add_autosave_association_callbacks(reflection)
|
311
311
|
|
@@ -485,10 +485,10 @@ module ActiveRecord
|
|
485
485
|
end
|
486
486
|
|
487
487
|
# Takes in a limit and checks if the attributes_collection has too many
|
488
|
-
# records.
|
489
|
-
# number-like
|
488
|
+
# records. It accepts limit in the form of symbol, proc, or
|
489
|
+
# number-like object (anything that can be compared with an integer).
|
490
490
|
#
|
491
|
-
#
|
491
|
+
# Raises TooManyRecords error if the attributes_collection is
|
492
492
|
# larger than the limit.
|
493
493
|
def check_record_limit!(limit, attributes_collection)
|
494
494
|
if limit
|
@@ -516,10 +516,10 @@ module ActiveRecord
|
|
516
516
|
|
517
517
|
# Determines if a hash contains a truthy _destroy key.
|
518
518
|
def has_destroy_flag?(hash)
|
519
|
-
|
519
|
+
Type::Boolean.new.type_cast_from_user(hash['_destroy'])
|
520
520
|
end
|
521
521
|
|
522
|
-
# Determines if a new record should be
|
522
|
+
# Determines if a new record should be rejected by checking
|
523
523
|
# has_destroy_flag? or if a <tt>:reject_if</tt> proc exists for this
|
524
524
|
# association and evaluates to +true+.
|
525
525
|
def reject_new_record?(association_name, attributes)
|
@@ -542,7 +542,7 @@ module ActiveRecord
|
|
542
542
|
end
|
543
543
|
|
544
544
|
def raise_nested_attributes_record_not_found!(association_name, record_id)
|
545
|
-
raise RecordNotFound, "Couldn't find #{self.class.
|
545
|
+
raise RecordNotFound, "Couldn't find #{self.class._reflect_on_association(association_name).klass.name} with ID=#{record_id} for #{self.class.name} with ID=#{id}"
|
546
546
|
end
|
547
547
|
end
|
548
548
|
end
|