activerecord 3.1.10 → 4.2.11
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of activerecord might be problematic. Click here for more details.
- checksums.yaml +6 -6
- data/CHANGELOG.md +1837 -338
- data/MIT-LICENSE +1 -1
- data/README.rdoc +39 -43
- data/examples/performance.rb +51 -20
- data/examples/simple.rb +4 -4
- data/lib/active_record/aggregations.rb +57 -43
- data/lib/active_record/association_relation.rb +35 -0
- data/lib/active_record/associations/alias_tracker.rb +47 -39
- data/lib/active_record/associations/association.rb +71 -85
- data/lib/active_record/associations/association_scope.rb +138 -89
- data/lib/active_record/associations/belongs_to_association.rb +65 -25
- data/lib/active_record/associations/belongs_to_polymorphic_association.rb +9 -3
- data/lib/active_record/associations/builder/association.rb +125 -29
- data/lib/active_record/associations/builder/belongs_to.rb +91 -60
- data/lib/active_record/associations/builder/collection_association.rb +69 -49
- data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +113 -42
- data/lib/active_record/associations/builder/has_many.rb +8 -64
- data/lib/active_record/associations/builder/has_one.rb +12 -52
- data/lib/active_record/associations/builder/singular_association.rb +22 -29
- data/lib/active_record/associations/collection_association.rb +294 -187
- data/lib/active_record/associations/collection_proxy.rb +961 -94
- data/lib/active_record/associations/foreign_association.rb +11 -0
- data/lib/active_record/associations/has_many_association.rb +118 -23
- data/lib/active_record/associations/has_many_through_association.rb +115 -45
- data/lib/active_record/associations/has_one_association.rb +57 -24
- data/lib/active_record/associations/has_one_through_association.rb +1 -1
- data/lib/active_record/associations/join_dependency/join_association.rb +76 -102
- data/lib/active_record/associations/join_dependency/join_base.rb +7 -9
- data/lib/active_record/associations/join_dependency/join_part.rb +30 -37
- data/lib/active_record/associations/join_dependency.rb +230 -156
- data/lib/active_record/associations/preloader/association.rb +96 -55
- data/lib/active_record/associations/preloader/collection_association.rb +3 -3
- data/lib/active_record/associations/preloader/has_many_through.rb +7 -3
- data/lib/active_record/associations/preloader/has_one.rb +1 -1
- data/lib/active_record/associations/preloader/singular_association.rb +3 -3
- data/lib/active_record/associations/preloader/through_association.rb +61 -32
- data/lib/active_record/associations/preloader.rb +113 -87
- data/lib/active_record/associations/singular_association.rb +29 -13
- data/lib/active_record/associations/through_association.rb +37 -19
- data/lib/active_record/associations.rb +505 -371
- data/lib/active_record/attribute.rb +163 -0
- data/lib/active_record/attribute_assignment.rb +212 -0
- data/lib/active_record/attribute_decorators.rb +66 -0
- data/lib/active_record/attribute_methods/before_type_cast.rb +52 -7
- data/lib/active_record/attribute_methods/dirty.rb +141 -51
- data/lib/active_record/attribute_methods/primary_key.rb +87 -36
- data/lib/active_record/attribute_methods/query.rb +5 -4
- data/lib/active_record/attribute_methods/read.rb +74 -117
- data/lib/active_record/attribute_methods/serialization.rb +70 -0
- data/lib/active_record/attribute_methods/time_zone_conversion.rb +49 -47
- data/lib/active_record/attribute_methods/write.rb +60 -21
- data/lib/active_record/attribute_methods.rb +409 -48
- data/lib/active_record/attribute_set/builder.rb +106 -0
- data/lib/active_record/attribute_set.rb +81 -0
- data/lib/active_record/attributes.rb +147 -0
- data/lib/active_record/autosave_association.rb +279 -232
- data/lib/active_record/base.rb +84 -1969
- data/lib/active_record/callbacks.rb +66 -28
- data/lib/active_record/coders/json.rb +13 -0
- data/lib/active_record/coders/yaml_column.rb +18 -21
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +422 -243
- data/lib/active_record/connection_adapters/abstract/database_limits.rb +9 -0
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +170 -194
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +32 -19
- data/lib/active_record/connection_adapters/abstract/quoting.rb +79 -57
- data/lib/active_record/connection_adapters/abstract/savepoints.rb +21 -0
- data/lib/active_record/connection_adapters/abstract/schema_creation.rb +125 -0
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +273 -170
- data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +50 -0
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +731 -254
- data/lib/active_record/connection_adapters/abstract/transaction.rb +215 -0
- data/lib/active_record/connection_adapters/abstract_adapter.rb +339 -95
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +946 -0
- data/lib/active_record/connection_adapters/column.rb +33 -221
- data/lib/active_record/connection_adapters/connection_specification.rb +275 -0
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +140 -602
- data/lib/active_record/connection_adapters/mysql_adapter.rb +254 -756
- data/lib/active_record/connection_adapters/postgresql/array_parser.rb +93 -0
- data/lib/active_record/connection_adapters/postgresql/column.rb +20 -0
- data/lib/active_record/connection_adapters/postgresql/database_statements.rb +232 -0
- 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/oid.rb +36 -0
- data/lib/active_record/connection_adapters/postgresql/quoting.rb +108 -0
- data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +30 -0
- data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +152 -0
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +596 -0
- data/lib/active_record/connection_adapters/postgresql/utils.rb +77 -0
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +445 -902
- data/lib/active_record/connection_adapters/schema_cache.rb +94 -0
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +578 -25
- data/lib/active_record/connection_handling.rb +132 -0
- data/lib/active_record/core.rb +579 -0
- data/lib/active_record/counter_cache.rb +159 -102
- data/lib/active_record/dynamic_matchers.rb +140 -0
- data/lib/active_record/enum.rb +197 -0
- data/lib/active_record/errors.rb +102 -34
- data/lib/active_record/explain.rb +38 -0
- data/lib/active_record/explain_registry.rb +30 -0
- data/lib/active_record/explain_subscriber.rb +29 -0
- data/lib/active_record/fixture_set/file.rb +56 -0
- data/lib/active_record/fixtures.rb +318 -260
- data/lib/active_record/gem_version.rb +15 -0
- data/lib/active_record/inheritance.rb +247 -0
- data/lib/active_record/integration.rb +113 -0
- data/lib/active_record/legacy_yaml_adapter.rb +30 -0
- data/lib/active_record/locale/en.yml +8 -1
- data/lib/active_record/locking/optimistic.rb +80 -52
- data/lib/active_record/locking/pessimistic.rb +27 -5
- data/lib/active_record/log_subscriber.rb +25 -18
- data/lib/active_record/migration/command_recorder.rb +130 -38
- data/lib/active_record/migration/join_table.rb +15 -0
- data/lib/active_record/migration.rb +532 -201
- data/lib/active_record/model_schema.rb +342 -0
- data/lib/active_record/nested_attributes.rb +229 -139
- data/lib/active_record/no_touching.rb +52 -0
- data/lib/active_record/null_relation.rb +81 -0
- data/lib/active_record/persistence.rb +304 -99
- data/lib/active_record/query_cache.rb +25 -43
- data/lib/active_record/querying.rb +68 -0
- data/lib/active_record/railtie.rb +86 -45
- data/lib/active_record/railties/console_sandbox.rb +3 -4
- data/lib/active_record/railties/controller_runtime.rb +7 -4
- data/lib/active_record/railties/databases.rake +198 -377
- data/lib/active_record/railties/jdbcmysql_error.rb +2 -2
- data/lib/active_record/readonly_attributes.rb +23 -0
- data/lib/active_record/reflection.rb +516 -165
- data/lib/active_record/relation/batches.rb +96 -45
- data/lib/active_record/relation/calculations.rb +221 -144
- data/lib/active_record/relation/delegation.rb +140 -0
- data/lib/active_record/relation/finder_methods.rb +362 -243
- data/lib/active_record/relation/merger.rb +193 -0
- data/lib/active_record/relation/predicate_builder/array_handler.rb +48 -0
- data/lib/active_record/relation/predicate_builder/relation_handler.rb +13 -0
- data/lib/active_record/relation/predicate_builder.rb +135 -41
- data/lib/active_record/relation/query_methods.rb +982 -155
- data/lib/active_record/relation/spawn_methods.rb +50 -110
- data/lib/active_record/relation.rb +371 -180
- data/lib/active_record/result.rb +109 -12
- data/lib/active_record/runtime_registry.rb +22 -0
- data/lib/active_record/sanitization.rb +191 -0
- data/lib/active_record/schema.rb +19 -13
- data/lib/active_record/schema_dumper.rb +111 -61
- data/lib/active_record/schema_migration.rb +53 -0
- data/lib/active_record/scoping/default.rb +135 -0
- data/lib/active_record/scoping/named.rb +164 -0
- data/lib/active_record/scoping.rb +87 -0
- data/lib/active_record/serialization.rb +7 -45
- data/lib/active_record/serializers/xml_serializer.rb +14 -65
- data/lib/active_record/statement_cache.rb +111 -0
- data/lib/active_record/store.rb +205 -0
- data/lib/active_record/tasks/database_tasks.rb +299 -0
- data/lib/active_record/tasks/mysql_database_tasks.rb +159 -0
- data/lib/active_record/tasks/postgresql_database_tasks.rb +101 -0
- data/lib/active_record/tasks/sqlite_database_tasks.rb +55 -0
- data/lib/active_record/timestamp.rb +35 -14
- data/lib/active_record/transactions.rb +141 -74
- data/lib/active_record/translation.rb +22 -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/type.rb +23 -0
- data/lib/active_record/validations/associated.rb +27 -18
- data/lib/active_record/validations/presence.rb +67 -0
- data/lib/active_record/validations/uniqueness.rb +125 -66
- data/lib/active_record/validations.rb +37 -30
- data/lib/active_record/version.rb +5 -7
- data/lib/active_record.rb +80 -25
- data/lib/rails/generators/active_record/migration/migration_generator.rb +54 -9
- data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb +19 -0
- data/lib/rails/generators/active_record/migration/templates/migration.rb +25 -11
- data/lib/rails/generators/active_record/migration.rb +11 -8
- data/lib/rails/generators/active_record/model/model_generator.rb +17 -4
- data/lib/rails/generators/active_record/model/templates/model.rb +5 -2
- data/lib/rails/generators/active_record/model/templates/module.rb +1 -1
- data/lib/rails/generators/active_record.rb +3 -11
- metadata +132 -53
- data/examples/associations.png +0 -0
- data/lib/active_record/associations/has_and_belongs_to_many_association.rb +0 -62
- data/lib/active_record/associations/join_helper.rb +0 -55
- data/lib/active_record/associations/preloader/has_and_belongs_to_many.rb +0 -60
- data/lib/active_record/connection_adapters/abstract/connection_specification.rb +0 -135
- data/lib/active_record/connection_adapters/sqlite_adapter.rb +0 -556
- data/lib/active_record/dynamic_finder_match.rb +0 -56
- data/lib/active_record/dynamic_scope_match.rb +0 -23
- data/lib/active_record/identity_map.rb +0 -163
- data/lib/active_record/named_scope.rb +0 -200
- data/lib/active_record/observer.rb +0 -121
- data/lib/active_record/session_store.rb +0 -358
- data/lib/active_record/test_case.rb +0 -69
- data/lib/rails/generators/active_record/model/templates/migration.rb +0 -17
- data/lib/rails/generators/active_record/observer/observer_generator.rb +0 -15
- data/lib/rails/generators/active_record/observer/templates/observer.rb +0 -4
- data/lib/rails/generators/active_record/session_migration/session_migration_generator.rb +0 -25
- data/lib/rails/generators/active_record/session_migration/templates/migration.rb +0 -16
@@ -3,18 +3,18 @@ module ActiveRecord
|
|
3
3
|
# Locking::Pessimistic provides support for row-level locking using
|
4
4
|
# SELECT ... FOR UPDATE and other lock types.
|
5
5
|
#
|
6
|
-
#
|
6
|
+
# Chain <tt>ActiveRecord::Base#find</tt> to <tt>ActiveRecord::QueryMethods#lock</tt> to obtain an exclusive
|
7
7
|
# lock on the selected rows:
|
8
8
|
# # select * from accounts where id=1 for update
|
9
|
-
# Account.find(1
|
9
|
+
# Account.lock.find(1)
|
10
10
|
#
|
11
|
-
#
|
11
|
+
# Call <tt>lock('some locking clause')</tt> to use a database-specific locking clause
|
12
12
|
# of your own such as 'LOCK IN SHARE MODE' or 'FOR UPDATE NOWAIT'. Example:
|
13
13
|
#
|
14
14
|
# Account.transaction do
|
15
15
|
# # select * from accounts where name = 'shugo' limit 1 for update
|
16
16
|
# shugo = Account.where("name = 'shugo'").lock(true).first
|
17
|
-
# yuko = Account.where("name = '
|
17
|
+
# yuko = Account.where("name = 'yuko'").lock(true).first
|
18
18
|
# shugo.balance -= 100
|
19
19
|
# shugo.save!
|
20
20
|
# yuko.balance += 100
|
@@ -26,7 +26,7 @@ module ActiveRecord
|
|
26
26
|
#
|
27
27
|
# Account.transaction do
|
28
28
|
# # select * from accounts where ...
|
29
|
-
# accounts = Account.where(...)
|
29
|
+
# accounts = Account.where(...)
|
30
30
|
# account1 = accounts.detect { |account| ... }
|
31
31
|
# account2 = accounts.detect { |account| ... }
|
32
32
|
# # select * from accounts where id=? for update
|
@@ -38,6 +38,18 @@ module ActiveRecord
|
|
38
38
|
# account2.save!
|
39
39
|
# end
|
40
40
|
#
|
41
|
+
# You can start a transaction and acquire the lock in one go by calling
|
42
|
+
# <tt>with_lock</tt> with a block. The block is called from within
|
43
|
+
# a transaction, the object is already locked. Example:
|
44
|
+
#
|
45
|
+
# account = Account.first
|
46
|
+
# account.with_lock do
|
47
|
+
# # This block is called within a transaction,
|
48
|
+
# # account is already locked.
|
49
|
+
# account.balance -= 100
|
50
|
+
# account.save!
|
51
|
+
# end
|
52
|
+
#
|
41
53
|
# Database-specific information on row locking:
|
42
54
|
# MySQL: http://dev.mysql.com/doc/refman/5.1/en/innodb-locking-reads.html
|
43
55
|
# PostgreSQL: http://www.postgresql.org/docs/current/interactive/sql-select.html#SQL-FOR-UPDATE-SHARE
|
@@ -50,6 +62,16 @@ module ActiveRecord
|
|
50
62
|
reload(:lock => lock) if persisted?
|
51
63
|
self
|
52
64
|
end
|
65
|
+
|
66
|
+
# Wraps the passed block in a transaction, locking the object
|
67
|
+
# before yielding. You can pass the SQL locking clause
|
68
|
+
# as argument (see <tt>lock!</tt>).
|
69
|
+
def with_lock(lock = true)
|
70
|
+
transaction do
|
71
|
+
lock!(lock)
|
72
|
+
yield
|
73
|
+
end
|
74
|
+
end
|
53
75
|
end
|
54
76
|
end
|
55
77
|
end
|
@@ -1,11 +1,13 @@
|
|
1
1
|
module ActiveRecord
|
2
2
|
class LogSubscriber < ActiveSupport::LogSubscriber
|
3
|
+
IGNORE_PAYLOAD_NAMES = ["SCHEMA", "EXPLAIN"]
|
4
|
+
|
3
5
|
def self.runtime=(value)
|
4
|
-
|
6
|
+
ActiveRecord::RuntimeRegistry.sql_runtime = value
|
5
7
|
end
|
6
8
|
|
7
9
|
def self.runtime
|
8
|
-
|
10
|
+
ActiveRecord::RuntimeRegistry.sql_runtime ||= 0
|
9
11
|
end
|
10
12
|
|
11
13
|
def self.reset_runtime
|
@@ -15,7 +17,21 @@ module ActiveRecord
|
|
15
17
|
|
16
18
|
def initialize
|
17
19
|
super
|
18
|
-
@
|
20
|
+
@odd = false
|
21
|
+
end
|
22
|
+
|
23
|
+
def render_bind(column, value)
|
24
|
+
if column
|
25
|
+
if column.binary?
|
26
|
+
# This specifically deals with the PG adapter that casts bytea columns into a Hash.
|
27
|
+
value = value[:value] if value.is_a?(Hash)
|
28
|
+
value = value ? "<#{value.bytesize} bytes of binary data>" : "<NULL binary data>"
|
29
|
+
end
|
30
|
+
|
31
|
+
[column.name, value]
|
32
|
+
else
|
33
|
+
[nil, value]
|
34
|
+
end
|
19
35
|
end
|
20
36
|
|
21
37
|
def sql(event)
|
@@ -24,15 +40,15 @@ module ActiveRecord
|
|
24
40
|
|
25
41
|
payload = event.payload
|
26
42
|
|
27
|
-
return if
|
43
|
+
return if IGNORE_PAYLOAD_NAMES.include?(payload[:name])
|
28
44
|
|
29
|
-
name
|
30
|
-
sql
|
31
|
-
binds
|
45
|
+
name = "#{payload[:name]} (#{event.duration.round(1)}ms)"
|
46
|
+
sql = payload[:sql]
|
47
|
+
binds = nil
|
32
48
|
|
33
49
|
unless (payload[:binds] || []).empty?
|
34
50
|
binds = " " + payload[:binds].map { |col,v|
|
35
|
-
|
51
|
+
render_bind(col, v)
|
36
52
|
}.inspect
|
37
53
|
end
|
38
54
|
|
@@ -46,17 +62,8 @@ module ActiveRecord
|
|
46
62
|
debug " #{name} #{sql}#{binds}"
|
47
63
|
end
|
48
64
|
|
49
|
-
def identity(event)
|
50
|
-
return unless logger.debug?
|
51
|
-
|
52
|
-
name = color(event.payload[:name], odd? ? CYAN : MAGENTA, true)
|
53
|
-
line = odd? ? color(event.payload[:line], nil, true) : event.payload[:line]
|
54
|
-
|
55
|
-
debug " #{name} #{line}"
|
56
|
-
end
|
57
|
-
|
58
65
|
def odd?
|
59
|
-
@
|
66
|
+
@odd = !@odd
|
60
67
|
end
|
61
68
|
|
62
69
|
def logger
|
@@ -1,73 +1,135 @@
|
|
1
1
|
module ActiveRecord
|
2
2
|
class Migration
|
3
|
-
# ActiveRecord::Migration::CommandRecorder records commands done during
|
4
|
-
# a migration and knows how to reverse those commands.
|
3
|
+
# <tt>ActiveRecord::Migration::CommandRecorder</tt> records commands done during
|
4
|
+
# a migration and knows how to reverse those commands. The CommandRecorder
|
5
5
|
# knows how to invert the following commands:
|
6
6
|
#
|
7
7
|
# * add_column
|
8
8
|
# * add_index
|
9
|
-
# *
|
9
|
+
# * add_timestamps
|
10
10
|
# * create_table
|
11
|
+
# * create_join_table
|
11
12
|
# * remove_timestamps
|
12
13
|
# * rename_column
|
13
14
|
# * rename_index
|
14
15
|
# * rename_table
|
15
16
|
class CommandRecorder
|
16
|
-
|
17
|
+
include JoinTable
|
18
|
+
|
19
|
+
attr_accessor :commands, :delegate, :reverting
|
17
20
|
|
18
21
|
def initialize(delegate = nil)
|
19
22
|
@commands = []
|
20
23
|
@delegate = delegate
|
24
|
+
@reverting = false
|
25
|
+
end
|
26
|
+
|
27
|
+
# While executing the given block, the recorded will be in reverting mode.
|
28
|
+
# All commands recorded will end up being recorded reverted
|
29
|
+
# and in reverse order.
|
30
|
+
# For example:
|
31
|
+
#
|
32
|
+
# recorder.revert{ recorder.record(:rename_table, [:old, :new]) }
|
33
|
+
# # same effect as recorder.record(:rename_table, [:new, :old])
|
34
|
+
def revert
|
35
|
+
@reverting = !@reverting
|
36
|
+
previous = @commands
|
37
|
+
@commands = []
|
38
|
+
yield
|
39
|
+
ensure
|
40
|
+
@commands = previous.concat(@commands.reverse)
|
41
|
+
@reverting = !@reverting
|
21
42
|
end
|
22
43
|
|
23
|
-
# record +command+.
|
44
|
+
# record +command+. +command+ should be a method name and arguments.
|
24
45
|
# For example:
|
25
46
|
#
|
26
|
-
# recorder.record(:method_name, [:arg1, arg2])
|
27
|
-
def record(*command)
|
28
|
-
@
|
47
|
+
# recorder.record(:method_name, [:arg1, :arg2])
|
48
|
+
def record(*command, &block)
|
49
|
+
if @reverting
|
50
|
+
@commands << inverse_of(*command, &block)
|
51
|
+
else
|
52
|
+
@commands << (command << block)
|
53
|
+
end
|
29
54
|
end
|
30
55
|
|
31
|
-
# Returns
|
32
|
-
# commands stored in +commands+. For example:
|
56
|
+
# Returns the inverse of the given command. For example:
|
33
57
|
#
|
34
|
-
# recorder.
|
35
|
-
#
|
58
|
+
# recorder.inverse_of(:rename_table, [:old, :new])
|
59
|
+
# # => [:rename_table, [:new, :old]]
|
36
60
|
#
|
37
|
-
# This method will raise an IrreversibleMigration exception if it cannot
|
38
|
-
# invert the +
|
39
|
-
def
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
send(method, args)
|
44
|
-
}
|
61
|
+
# This method will raise an +IrreversibleMigration+ exception if it cannot
|
62
|
+
# invert the +command+.
|
63
|
+
def inverse_of(command, args, &block)
|
64
|
+
method = :"invert_#{command}"
|
65
|
+
raise IrreversibleMigration unless respond_to?(method, true)
|
66
|
+
send(method, args, &block)
|
45
67
|
end
|
46
68
|
|
47
69
|
def respond_to?(*args) # :nodoc:
|
48
70
|
super || delegate.respond_to?(*args)
|
49
71
|
end
|
50
72
|
|
51
|
-
[:create_table, :
|
73
|
+
[:create_table, :create_join_table, :rename_table, :add_column, :remove_column,
|
74
|
+
:rename_index, :rename_column, :add_index, :remove_index, :add_timestamps, :remove_timestamps,
|
75
|
+
:change_column_default, :add_reference, :remove_reference, :transaction,
|
76
|
+
:drop_join_table, :drop_table, :execute_block, :enable_extension,
|
77
|
+
:change_column, :execute, :remove_columns, :change_column_null,
|
78
|
+
:add_foreign_key, :remove_foreign_key
|
79
|
+
# irreversible methods need to be here too
|
80
|
+
].each do |method|
|
52
81
|
class_eval <<-EOV, __FILE__, __LINE__ + 1
|
53
|
-
def #{method}(*args) # def create_table(*args)
|
54
|
-
record(:"#{method}", args) # record(:create_table, args)
|
55
|
-
end
|
82
|
+
def #{method}(*args, &block) # def create_table(*args, &block)
|
83
|
+
record(:"#{method}", args, &block) # record(:create_table, args, &block)
|
84
|
+
end # end
|
56
85
|
EOV
|
57
86
|
end
|
87
|
+
alias :add_belongs_to :add_reference
|
88
|
+
alias :remove_belongs_to :remove_reference
|
89
|
+
|
90
|
+
def change_table(table_name, options = {}) # :nodoc:
|
91
|
+
yield delegate.update_table_definition(table_name, self)
|
92
|
+
end
|
58
93
|
|
59
94
|
private
|
60
95
|
|
61
|
-
|
62
|
-
|
96
|
+
module StraightReversions
|
97
|
+
private
|
98
|
+
{ transaction: :transaction,
|
99
|
+
execute_block: :execute_block,
|
100
|
+
create_table: :drop_table,
|
101
|
+
create_join_table: :drop_join_table,
|
102
|
+
add_column: :remove_column,
|
103
|
+
add_timestamps: :remove_timestamps,
|
104
|
+
add_reference: :remove_reference,
|
105
|
+
enable_extension: :disable_extension
|
106
|
+
}.each do |cmd, inv|
|
107
|
+
[[inv, cmd], [cmd, inv]].uniq.each do |method, inverse|
|
108
|
+
class_eval <<-EOV, __FILE__, __LINE__ + 1
|
109
|
+
def invert_#{method}(args, &block) # def invert_create_table(args, &block)
|
110
|
+
[:#{inverse}, args, block] # [:drop_table, args, block]
|
111
|
+
end # end
|
112
|
+
EOV
|
113
|
+
end
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
117
|
+
include StraightReversions
|
118
|
+
|
119
|
+
def invert_drop_table(args, &block)
|
120
|
+
if args.size == 1 && block == nil
|
121
|
+
raise ActiveRecord::IrreversibleMigration, "To avoid mistakes, drop_table is only reversible if given options or a block (can be empty)."
|
122
|
+
end
|
123
|
+
super
|
63
124
|
end
|
64
125
|
|
65
126
|
def invert_rename_table(args)
|
66
127
|
[:rename_table, args.reverse]
|
67
128
|
end
|
68
129
|
|
69
|
-
def
|
70
|
-
|
130
|
+
def invert_remove_column(args)
|
131
|
+
raise ActiveRecord::IrreversibleMigration, "remove_column is only reversible if given a type." if args.size <= 2
|
132
|
+
super
|
71
133
|
end
|
72
134
|
|
73
135
|
def invert_rename_index(args)
|
@@ -80,26 +142,56 @@ module ActiveRecord
|
|
80
142
|
|
81
143
|
def invert_add_index(args)
|
82
144
|
table, columns, options = *args
|
83
|
-
|
84
|
-
|
145
|
+
options ||= {}
|
146
|
+
|
147
|
+
index_name = options[:name]
|
148
|
+
options_hash = index_name ? { name: index_name } : { column: columns }
|
149
|
+
|
85
150
|
[:remove_index, [table, options_hash]]
|
86
151
|
end
|
87
152
|
|
88
|
-
def
|
89
|
-
|
153
|
+
def invert_remove_index(args)
|
154
|
+
table, options = *args
|
155
|
+
|
156
|
+
unless options && options.is_a?(Hash) && options[:column]
|
157
|
+
raise ActiveRecord::IrreversibleMigration, "remove_index is only reversible if given a :column option."
|
158
|
+
end
|
159
|
+
|
160
|
+
options = options.dup
|
161
|
+
[:add_index, [table, options.delete(:column), options]]
|
162
|
+
end
|
163
|
+
|
164
|
+
alias :invert_add_belongs_to :invert_add_reference
|
165
|
+
alias :invert_remove_belongs_to :invert_remove_reference
|
166
|
+
|
167
|
+
def invert_change_column_null(args)
|
168
|
+
args[2] = !args[2]
|
169
|
+
[:change_column_null, args]
|
90
170
|
end
|
91
171
|
|
92
|
-
def
|
93
|
-
|
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]]
|
94
185
|
end
|
95
186
|
|
96
187
|
# Forwards any missing method call to the \target.
|
97
188
|
def method_missing(method, *args, &block)
|
98
|
-
@delegate.
|
99
|
-
|
100
|
-
|
189
|
+
if @delegate.respond_to?(method)
|
190
|
+
@delegate.send(method, *args, &block)
|
191
|
+
else
|
192
|
+
super
|
193
|
+
end
|
101
194
|
end
|
102
|
-
|
103
195
|
end
|
104
196
|
end
|
105
197
|
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
module ActiveRecord
|
2
|
+
class Migration
|
3
|
+
module JoinTable #:nodoc:
|
4
|
+
private
|
5
|
+
|
6
|
+
def find_join_table_name(table_1, table_2, options = {})
|
7
|
+
options.delete(:table_name) || join_table_name(table_1, table_2)
|
8
|
+
end
|
9
|
+
|
10
|
+
def join_table_name(table_1, table_2)
|
11
|
+
ModelSchema.derive_join_table_name(table_1, table_2).to_sym
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|