activerecord 4.1.16 → 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 -2185
- data/README.rdoc +15 -10
- data/lib/active_record.rb +2 -1
- data/lib/active_record/aggregations.rb +12 -8
- data/lib/active_record/associations.rb +58 -33
- 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.rb +7 -9
- data/lib/active_record/associations/join_dependency/join_association.rb +18 -14
- data/lib/active_record/associations/preloader.rb +2 -2
- 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/singular_association.rb +16 -1
- data/lib/active_record/associations/through_association.rb +6 -22
- 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.rb +53 -90
- 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_set.rb +77 -0
- data/lib/active_record/attribute_set/builder.rb +32 -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.rb +29 -388
- 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/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.rb +22 -32
- 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 +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.rb +35 -11
- 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.rb +1 -22
- 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/query_methods.rb +98 -62
- data/lib/active_record/relation/spawn_methods.rb +6 -7
- 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 +10 -16
- 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.rb +20 -0
- 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/validations.rb +21 -16
- data/lib/active_record/validations/uniqueness.rb +9 -23
- 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
@@ -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
|
@@ -195,7 +195,7 @@ module ActiveRecord
|
|
195
195
|
# == Database support
|
196
196
|
#
|
197
197
|
# Migrations are currently supported in MySQL, PostgreSQL, SQLite,
|
198
|
-
# SQL Server,
|
198
|
+
# SQL Server, and Oracle (all supported databases except DB2).
|
199
199
|
#
|
200
200
|
# == More examples
|
201
201
|
#
|
@@ -372,13 +372,21 @@ module ActiveRecord
|
|
372
372
|
end
|
373
373
|
|
374
374
|
def call(env)
|
375
|
-
|
376
|
-
|
377
|
-
|
378
|
-
|
375
|
+
if connection.supports_migrations?
|
376
|
+
mtime = ActiveRecord::Migrator.last_migration.mtime.to_i
|
377
|
+
if @last_check < mtime
|
378
|
+
ActiveRecord::Migration.check_pending!(connection)
|
379
|
+
@last_check = mtime
|
380
|
+
end
|
379
381
|
end
|
380
382
|
@app.call(env)
|
381
383
|
end
|
384
|
+
|
385
|
+
private
|
386
|
+
|
387
|
+
def connection
|
388
|
+
ActiveRecord::Base.connection
|
389
|
+
end
|
382
390
|
end
|
383
391
|
|
384
392
|
class << self
|
@@ -391,14 +399,7 @@ module ActiveRecord
|
|
391
399
|
|
392
400
|
def load_schema_if_pending!
|
393
401
|
if ActiveRecord::Migrator.needs_migration?
|
394
|
-
|
395
|
-
FileUtils.cd Rails.root do
|
396
|
-
current_config = Base.connection_config
|
397
|
-
Base.clear_all_connections!
|
398
|
-
system("bin/rake db:test:prepare")
|
399
|
-
# Establish a new connection, the old database may be gone (db:test:prepare uses purge)
|
400
|
-
Base.establish_connection(current_config)
|
401
|
-
end
|
402
|
+
ActiveRecord::Tasks::DatabaseTasks.load_schema_current
|
402
403
|
check_pending!
|
403
404
|
end
|
404
405
|
end
|
@@ -649,7 +650,9 @@ module ActiveRecord
|
|
649
650
|
unless @connection.respond_to? :revert
|
650
651
|
unless arguments.empty? || [:execute, :enable_extension, :disable_extension].include?(method)
|
651
652
|
arguments[0] = proper_table_name(arguments.first, table_name_options)
|
652
|
-
|
653
|
+
if [:rename_table, :add_foreign_key].include?(method)
|
654
|
+
arguments[1] = proper_table_name(arguments.second, table_name_options)
|
655
|
+
end
|
653
656
|
end
|
654
657
|
end
|
655
658
|
return super unless connection.respond_to?(method)
|
@@ -811,22 +814,22 @@ module ActiveRecord
|
|
811
814
|
migrations = migrations(migrations_paths)
|
812
815
|
migrations.select! { |m| yield m } if block_given?
|
813
816
|
|
814
|
-
|
817
|
+
new(:up, migrations, target_version).migrate
|
815
818
|
end
|
816
819
|
|
817
820
|
def down(migrations_paths, target_version = nil, &block)
|
818
821
|
migrations = migrations(migrations_paths)
|
819
822
|
migrations.select! { |m| yield m } if block_given?
|
820
823
|
|
821
|
-
|
824
|
+
new(:down, migrations, target_version).migrate
|
822
825
|
end
|
823
826
|
|
824
827
|
def run(direction, migrations_paths, target_version)
|
825
|
-
|
828
|
+
new(direction, migrations(migrations_paths), target_version).run
|
826
829
|
end
|
827
830
|
|
828
831
|
def open(migrations_paths)
|
829
|
-
|
832
|
+
new(:up, migrations(migrations_paths), nil)
|
830
833
|
end
|
831
834
|
|
832
835
|
def schema_migrations_table_name
|
@@ -857,19 +860,6 @@ module ActiveRecord
|
|
857
860
|
migrations(migrations_paths).last || NullMigration.new
|
858
861
|
end
|
859
862
|
|
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
863
|
def migrations_paths
|
874
864
|
@migrations_paths ||= ['db/migrate']
|
875
865
|
# just to not break things if someone uses: migration_path = some_string
|
@@ -901,7 +891,7 @@ module ActiveRecord
|
|
901
891
|
private
|
902
892
|
|
903
893
|
def move(direction, migrations_paths, steps)
|
904
|
-
migrator =
|
894
|
+
migrator = new(direction, migrations(migrations_paths))
|
905
895
|
start_index = migrator.migrations.index(migrator.current_migration)
|
906
896
|
|
907
897
|
if start_index
|
@@ -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)
|
@@ -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').gsub("\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)
|
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
|
+
columns_hash.transform_values(&:default))
|
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
|
@@ -298,27 +298,17 @@ module ActiveRecord
|
|
298
298
|
connection.schema_cache.clear_table_cache!(table_name) if table_exists?
|
299
299
|
|
300
300
|
@arel_engine = nil
|
301
|
-
@column_defaults = nil
|
302
301
|
@column_names = nil
|
303
|
-
@columns = nil
|
304
|
-
@columns_hash = nil
|
305
302
|
@column_types = nil
|
306
303
|
@content_columns = nil
|
304
|
+
@default_attributes = nil
|
307
305
|
@dynamic_methods_hash = nil
|
308
306
|
@inheritance_column = nil unless defined?(@explicit_inheritance_column) && @explicit_inheritance_column
|
309
307
|
@relation = nil
|
310
|
-
@serialized_column_names = nil
|
311
308
|
@time_zone_column_names = nil
|
312
309
|
@cached_time_zone = nil
|
313
310
|
end
|
314
311
|
|
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
|
320
|
-
end
|
321
|
-
|
322
312
|
private
|
323
313
|
|
324
314
|
# Guesses the table name, but does not decorate it with prefix and suffix information.
|
@@ -337,7 +327,8 @@ module ActiveRecord
|
|
337
327
|
contained = contained.singularize if parent.pluralize_table_names
|
338
328
|
contained += '_'
|
339
329
|
end
|
340
|
-
|
330
|
+
|
331
|
+
"#{full_table_name_prefix}#{contained}#{undecorated_table_name(name)}#{full_table_name_suffix}"
|
341
332
|
else
|
342
333
|
# STI subclasses always use their superclass' table.
|
343
334
|
base.table_name
|