activerecord 4.2.11.3 → 5.0.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 +5 -5
- data/CHANGELOG.md +1029 -1349
- data/MIT-LICENSE +1 -1
- data/README.rdoc +6 -7
- data/examples/performance.rb +2 -2
- data/lib/active_record.rb +7 -3
- data/lib/active_record/aggregations.rb +35 -25
- data/lib/active_record/association_relation.rb +2 -2
- data/lib/active_record/associations.rb +305 -204
- data/lib/active_record/associations/alias_tracker.rb +19 -16
- data/lib/active_record/associations/association.rb +10 -8
- data/lib/active_record/associations/association_scope.rb +73 -102
- data/lib/active_record/associations/belongs_to_association.rb +20 -32
- data/lib/active_record/associations/builder/association.rb +28 -34
- data/lib/active_record/associations/builder/belongs_to.rb +41 -18
- data/lib/active_record/associations/builder/collection_association.rb +8 -24
- data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +11 -11
- data/lib/active_record/associations/builder/has_many.rb +4 -4
- data/lib/active_record/associations/builder/has_one.rb +10 -5
- data/lib/active_record/associations/builder/singular_association.rb +2 -9
- data/lib/active_record/associations/collection_association.rb +40 -43
- data/lib/active_record/associations/collection_proxy.rb +55 -29
- data/lib/active_record/associations/foreign_association.rb +1 -1
- data/lib/active_record/associations/has_many_association.rb +20 -71
- data/lib/active_record/associations/has_many_through_association.rb +8 -52
- data/lib/active_record/associations/has_one_association.rb +12 -5
- data/lib/active_record/associations/join_dependency.rb +28 -18
- data/lib/active_record/associations/join_dependency/join_association.rb +13 -12
- data/lib/active_record/associations/preloader.rb +13 -4
- data/lib/active_record/associations/preloader/association.rb +45 -51
- data/lib/active_record/associations/preloader/collection_association.rb +0 -6
- data/lib/active_record/associations/preloader/has_many_through.rb +1 -1
- data/lib/active_record/associations/preloader/has_one.rb +0 -8
- data/lib/active_record/associations/preloader/through_association.rb +5 -4
- data/lib/active_record/associations/singular_association.rb +6 -0
- data/lib/active_record/associations/through_association.rb +11 -3
- data/lib/active_record/attribute.rb +61 -17
- data/lib/active_record/attribute/user_provided_default.rb +23 -0
- data/lib/active_record/attribute_assignment.rb +27 -140
- data/lib/active_record/attribute_decorators.rb +6 -5
- data/lib/active_record/attribute_methods.rb +79 -26
- data/lib/active_record/attribute_methods/before_type_cast.rb +1 -1
- data/lib/active_record/attribute_methods/dirty.rb +46 -86
- data/lib/active_record/attribute_methods/primary_key.rb +2 -2
- data/lib/active_record/attribute_methods/query.rb +2 -2
- data/lib/active_record/attribute_methods/read.rb +26 -42
- data/lib/active_record/attribute_methods/serialization.rb +13 -16
- data/lib/active_record/attribute_methods/time_zone_conversion.rb +42 -9
- data/lib/active_record/attribute_methods/write.rb +13 -24
- data/lib/active_record/attribute_mutation_tracker.rb +70 -0
- data/lib/active_record/attribute_set.rb +30 -3
- data/lib/active_record/attribute_set/builder.rb +6 -4
- data/lib/active_record/attributes.rb +194 -81
- data/lib/active_record/autosave_association.rb +33 -15
- data/lib/active_record/base.rb +30 -18
- data/lib/active_record/callbacks.rb +36 -40
- data/lib/active_record/coders/yaml_column.rb +20 -8
- data/lib/active_record/collection_cache_key.rb +31 -0
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +431 -122
- data/lib/active_record/connection_adapters/abstract/database_limits.rb +3 -3
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +40 -22
- data/lib/active_record/connection_adapters/abstract/quoting.rb +62 -8
- data/lib/active_record/connection_adapters/abstract/schema_creation.rb +46 -38
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +229 -185
- data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +52 -13
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +275 -115
- data/lib/active_record/connection_adapters/abstract/transaction.rb +32 -33
- data/lib/active_record/connection_adapters/abstract_adapter.rb +83 -32
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +384 -221
- data/lib/active_record/connection_adapters/column.rb +27 -41
- data/lib/active_record/connection_adapters/connection_specification.rb +2 -21
- data/lib/active_record/connection_adapters/determine_if_preparable_visitor.rb +22 -0
- data/lib/active_record/connection_adapters/mysql/schema_creation.rb +57 -0
- data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +69 -0
- data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +59 -0
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +22 -101
- data/lib/active_record/connection_adapters/postgresql/column.rb +6 -10
- data/lib/active_record/connection_adapters/postgresql/database_statements.rb +3 -3
- data/lib/active_record/connection_adapters/postgresql/oid.rb +1 -6
- data/lib/active_record/connection_adapters/postgresql/oid/array.rb +23 -57
- data/lib/active_record/connection_adapters/postgresql/oid/bit.rb +2 -2
- data/lib/active_record/connection_adapters/postgresql/oid/bytea.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +7 -22
- data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +3 -3
- data/lib/active_record/connection_adapters/postgresql/oid/json.rb +1 -26
- data/lib/active_record/connection_adapters/postgresql/oid/jsonb.rb +2 -2
- data/lib/active_record/connection_adapters/postgresql/oid/money.rb +0 -2
- data/lib/active_record/connection_adapters/postgresql/oid/point.rb +4 -4
- data/lib/active_record/connection_adapters/postgresql/oid/rails_5_1_point.rb +50 -0
- data/lib/active_record/connection_adapters/postgresql/oid/range.rb +23 -16
- data/lib/active_record/connection_adapters/postgresql/oid/specialized_string.rb +0 -4
- data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +2 -2
- data/lib/active_record/connection_adapters/postgresql/oid/vector.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/oid/xml.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/quoting.rb +18 -11
- data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +29 -10
- data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +107 -79
- data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +54 -0
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +174 -128
- data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +35 -0
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +184 -112
- data/lib/active_record/connection_adapters/schema_cache.rb +36 -23
- data/lib/active_record/connection_adapters/sql_type_metadata.rb +32 -0
- data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +15 -0
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +134 -110
- data/lib/active_record/connection_adapters/statement_pool.rb +28 -11
- data/lib/active_record/connection_handling.rb +5 -5
- data/lib/active_record/core.rb +72 -104
- data/lib/active_record/counter_cache.rb +9 -20
- data/lib/active_record/dynamic_matchers.rb +1 -20
- data/lib/active_record/enum.rb +110 -76
- data/lib/active_record/errors.rb +72 -47
- data/lib/active_record/explain_registry.rb +1 -1
- data/lib/active_record/explain_subscriber.rb +1 -1
- data/lib/active_record/fixture_set/file.rb +19 -4
- data/lib/active_record/fixtures.rb +76 -40
- data/lib/active_record/gem_version.rb +4 -4
- data/lib/active_record/inheritance.rb +27 -40
- data/lib/active_record/integration.rb +4 -4
- data/lib/active_record/legacy_yaml_adapter.rb +18 -2
- data/lib/active_record/locale/en.yml +3 -2
- data/lib/active_record/locking/optimistic.rb +10 -14
- data/lib/active_record/locking/pessimistic.rb +1 -1
- data/lib/active_record/log_subscriber.rb +40 -22
- data/lib/active_record/migration.rb +304 -133
- data/lib/active_record/migration/command_recorder.rb +59 -18
- data/lib/active_record/migration/compatibility.rb +90 -0
- data/lib/active_record/model_schema.rb +92 -40
- data/lib/active_record/nested_attributes.rb +45 -34
- data/lib/active_record/null_relation.rb +15 -7
- data/lib/active_record/persistence.rb +112 -72
- data/lib/active_record/querying.rb +6 -5
- data/lib/active_record/railtie.rb +20 -13
- data/lib/active_record/railties/controller_runtime.rb +1 -1
- data/lib/active_record/railties/databases.rake +47 -38
- data/lib/active_record/readonly_attributes.rb +1 -1
- data/lib/active_record/reflection.rb +182 -57
- data/lib/active_record/relation.rb +152 -100
- data/lib/active_record/relation/batches.rb +133 -33
- data/lib/active_record/relation/batches/batch_enumerator.rb +67 -0
- data/lib/active_record/relation/calculations.rb +80 -101
- data/lib/active_record/relation/delegation.rb +6 -19
- data/lib/active_record/relation/finder_methods.rb +58 -46
- data/lib/active_record/relation/from_clause.rb +32 -0
- data/lib/active_record/relation/merger.rb +13 -42
- data/lib/active_record/relation/predicate_builder.rb +99 -105
- data/lib/active_record/relation/predicate_builder/array_handler.rb +11 -16
- data/lib/active_record/relation/predicate_builder/association_query_handler.rb +78 -0
- data/lib/active_record/relation/predicate_builder/base_handler.rb +17 -0
- data/lib/active_record/relation/predicate_builder/basic_object_handler.rb +17 -0
- data/lib/active_record/relation/predicate_builder/class_handler.rb +27 -0
- data/lib/active_record/relation/predicate_builder/range_handler.rb +17 -0
- data/lib/active_record/relation/query_attribute.rb +19 -0
- data/lib/active_record/relation/query_methods.rb +274 -238
- data/lib/active_record/relation/record_fetch_warning.rb +51 -0
- data/lib/active_record/relation/spawn_methods.rb +3 -6
- data/lib/active_record/relation/where_clause.rb +173 -0
- data/lib/active_record/relation/where_clause_factory.rb +37 -0
- data/lib/active_record/result.rb +4 -3
- data/lib/active_record/runtime_registry.rb +1 -1
- data/lib/active_record/sanitization.rb +94 -65
- data/lib/active_record/schema.rb +23 -22
- data/lib/active_record/schema_dumper.rb +33 -22
- data/lib/active_record/schema_migration.rb +10 -4
- data/lib/active_record/scoping.rb +17 -6
- data/lib/active_record/scoping/default.rb +19 -6
- data/lib/active_record/scoping/named.rb +39 -28
- data/lib/active_record/secure_token.rb +38 -0
- data/lib/active_record/serialization.rb +2 -4
- data/lib/active_record/statement_cache.rb +15 -13
- data/lib/active_record/store.rb +8 -3
- data/lib/active_record/suppressor.rb +54 -0
- data/lib/active_record/table_metadata.rb +64 -0
- data/lib/active_record/tasks/database_tasks.rb +30 -40
- data/lib/active_record/tasks/mysql_database_tasks.rb +7 -15
- data/lib/active_record/tasks/postgresql_database_tasks.rb +11 -2
- data/lib/active_record/tasks/sqlite_database_tasks.rb +5 -1
- data/lib/active_record/timestamp.rb +16 -9
- data/lib/active_record/touch_later.rb +58 -0
- data/lib/active_record/transactions.rb +138 -56
- data/lib/active_record/type.rb +66 -17
- data/lib/active_record/type/adapter_specific_registry.rb +130 -0
- data/lib/active_record/type/date.rb +2 -45
- data/lib/active_record/type/date_time.rb +2 -49
- data/lib/active_record/type/internal/abstract_json.rb +33 -0
- data/lib/active_record/type/internal/timezone.rb +15 -0
- data/lib/active_record/type/serialized.rb +9 -14
- data/lib/active_record/type/time.rb +3 -21
- data/lib/active_record/type/type_map.rb +4 -4
- data/lib/active_record/type_caster.rb +7 -0
- data/lib/active_record/type_caster/connection.rb +29 -0
- data/lib/active_record/type_caster/map.rb +19 -0
- data/lib/active_record/validations.rb +33 -32
- data/lib/active_record/validations/absence.rb +24 -0
- data/lib/active_record/validations/associated.rb +10 -3
- data/lib/active_record/validations/length.rb +36 -0
- data/lib/active_record/validations/presence.rb +12 -12
- data/lib/active_record/validations/uniqueness.rb +24 -21
- data/lib/rails/generators/active_record/migration.rb +7 -0
- data/lib/rails/generators/active_record/migration/migration_generator.rb +7 -4
- data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb +8 -3
- data/lib/rails/generators/active_record/migration/templates/migration.rb +4 -1
- data/lib/rails/generators/active_record/model/model_generator.rb +21 -15
- data/lib/rails/generators/active_record/model/templates/model.rb +3 -0
- metadata +50 -35
- data/lib/active_record/connection_adapters/mysql_adapter.rb +0 -498
- data/lib/active_record/connection_adapters/postgresql/array_parser.rb +0 -93
- data/lib/active_record/connection_adapters/postgresql/oid/date.rb +0 -11
- data/lib/active_record/connection_adapters/postgresql/oid/float.rb +0 -21
- data/lib/active_record/connection_adapters/postgresql/oid/infinity.rb +0 -13
- data/lib/active_record/connection_adapters/postgresql/oid/integer.rb +0 -11
- data/lib/active_record/connection_adapters/postgresql/oid/time.rb +0 -11
- data/lib/active_record/serializers/xml_serializer.rb +0 -193
- data/lib/active_record/type/big_integer.rb +0 -13
- data/lib/active_record/type/binary.rb +0 -50
- data/lib/active_record/type/boolean.rb +0 -31
- data/lib/active_record/type/decimal.rb +0 -64
- data/lib/active_record/type/decimal_without_scale.rb +0 -11
- data/lib/active_record/type/decorator.rb +0 -14
- data/lib/active_record/type/float.rb +0 -19
- data/lib/active_record/type/integer.rb +0 -59
- data/lib/active_record/type/mutable.rb +0 -16
- data/lib/active_record/type/numeric.rb +0 -36
- data/lib/active_record/type/string.rb +0 -40
- data/lib/active_record/type/text.rb +0 -11
- data/lib/active_record/type/time_value.rb +0 -38
- data/lib/active_record/type/unsigned_integer.rb +0 -15
- data/lib/active_record/type/value.rb +0 -110
@@ -16,11 +16,11 @@ module ActiveRecord
|
|
16
16
|
config.app_generators.orm :active_record, :migration => true,
|
17
17
|
:timestamps => true
|
18
18
|
|
19
|
-
config.app_middleware.insert_after
|
20
|
-
|
19
|
+
config.app_middleware.insert_after ::ActionDispatch::Callbacks,
|
20
|
+
ActiveRecord::QueryCache
|
21
21
|
|
22
|
-
config.app_middleware.insert_after
|
23
|
-
|
22
|
+
config.app_middleware.insert_after ::ActionDispatch::Callbacks,
|
23
|
+
ActiveRecord::ConnectionAdapters::ConnectionManagement
|
24
24
|
|
25
25
|
config.action_dispatch.rescue_responses.merge!(
|
26
26
|
'ActiveRecord::RecordNotFound' => :not_found,
|
@@ -57,10 +57,8 @@ module ActiveRecord
|
|
57
57
|
console do |app|
|
58
58
|
require "active_record/railties/console_sandbox" if app.sandbox?
|
59
59
|
require "active_record/base"
|
60
|
-
|
61
|
-
|
62
|
-
Rails.logger.extend ActiveSupport::Logger.broadcast console
|
63
|
-
end
|
60
|
+
console = ActiveSupport::Logger.new(STDERR)
|
61
|
+
Rails.logger.extend ActiveSupport::Logger.broadcast console
|
64
62
|
end
|
65
63
|
|
66
64
|
runner do
|
@@ -80,8 +78,8 @@ module ActiveRecord
|
|
80
78
|
|
81
79
|
initializer "active_record.migration_error" do
|
82
80
|
if config.active_record.delete(:migration_error) == :page_load
|
83
|
-
config.app_middleware.insert_after
|
84
|
-
|
81
|
+
config.app_middleware.insert_after ::ActionDispatch::Callbacks,
|
82
|
+
ActiveRecord::Migration::CheckPending
|
85
83
|
end
|
86
84
|
end
|
87
85
|
|
@@ -95,6 +93,7 @@ module ActiveRecord
|
|
95
93
|
cache = Marshal.load File.binread filename
|
96
94
|
if cache.version == ActiveRecord::Migrator.current_version
|
97
95
|
self.connection.schema_cache = cache
|
96
|
+
self.connection_pool.schema_cache = cache.dup
|
98
97
|
else
|
99
98
|
warn "Ignoring db/schema_cache.dump because it has expired. The current schema version is #{ActiveRecord::Migrator.current_version}, but the one in the cache is #{cache.version}."
|
100
99
|
end
|
@@ -104,6 +103,14 @@ module ActiveRecord
|
|
104
103
|
end
|
105
104
|
end
|
106
105
|
|
106
|
+
initializer "active_record.warn_on_records_fetched_greater_than" do
|
107
|
+
if config.active_record.warn_on_records_fetched_greater_than
|
108
|
+
ActiveSupport.on_load(:active_record) do
|
109
|
+
require 'active_record/relation/record_fetch_warning'
|
110
|
+
end
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
107
114
|
initializer "active_record.set_configs" do |app|
|
108
115
|
ActiveSupport.on_load(:active_record) do
|
109
116
|
app.config.active_record.each do |k,v|
|
@@ -114,7 +121,7 @@ module ActiveRecord
|
|
114
121
|
|
115
122
|
# This sets the database configuration from Configuration#database_configuration
|
116
123
|
# and then establishes the connection.
|
117
|
-
initializer "active_record.initialize_database" do
|
124
|
+
initializer "active_record.initialize_database" do
|
118
125
|
ActiveSupport.on_load(:active_record) do
|
119
126
|
self.configurations = Rails.application.config.database_configuration
|
120
127
|
|
@@ -127,8 +134,8 @@ Oops - You have a database configured, but it doesn't exist yet!
|
|
127
134
|
Here's how to get started:
|
128
135
|
|
129
136
|
1. Configure your database in config/database.yml.
|
130
|
-
2. Run `bin/
|
131
|
-
3. Run `bin/
|
137
|
+
2. Run `bin/rails db:create` to create the database.
|
138
|
+
3. Run `bin/rails db:setup` to load your database schema.
|
132
139
|
end_warning
|
133
140
|
raise
|
134
141
|
end
|
@@ -19,7 +19,7 @@ module ActiveRecord
|
|
19
19
|
end
|
20
20
|
|
21
21
|
def cleanup_view_runtime
|
22
|
-
if ActiveRecord::Base.connected?
|
22
|
+
if logger.info? && ActiveRecord::Base.connected?
|
23
23
|
db_rt_before_render = ActiveRecord::LogSubscriber.reset_runtime
|
24
24
|
self.db_runtime = (db_runtime || 0) + db_rt_before_render
|
25
25
|
runtime = super
|
@@ -12,7 +12,7 @@ db_namespace = namespace :db do
|
|
12
12
|
end
|
13
13
|
end
|
14
14
|
|
15
|
-
desc 'Creates the database from DATABASE_URL or config/database.yml for the current RAILS_ENV (use db:create:all to create all databases in the config). Without RAILS_ENV it defaults to creating the development and test databases.'
|
15
|
+
desc 'Creates the database from DATABASE_URL or config/database.yml for the current RAILS_ENV (use db:create:all to create all databases in the config). Without RAILS_ENV, it defaults to creating the development and test databases.'
|
16
16
|
task :create => [:load_config] do
|
17
17
|
ActiveRecord::Tasks::DatabaseTasks.create_current
|
18
18
|
end
|
@@ -23,7 +23,7 @@ db_namespace = namespace :db do
|
|
23
23
|
end
|
24
24
|
end
|
25
25
|
|
26
|
-
desc 'Drops the database from DATABASE_URL or config/database.yml for the current RAILS_ENV (use db:drop:all to drop all databases in the config). Without RAILS_ENV it defaults to dropping the development and test databases.'
|
26
|
+
desc 'Drops the database from DATABASE_URL or config/database.yml for the current RAILS_ENV (use db:drop:all to drop all databases in the config). Without RAILS_ENV, it defaults to dropping the development and test databases.'
|
27
27
|
task :drop => [:load_config] do
|
28
28
|
ActiveRecord::Tasks::DatabaseTasks.drop_current
|
29
29
|
end
|
@@ -34,7 +34,7 @@ db_namespace = namespace :db do
|
|
34
34
|
end
|
35
35
|
end
|
36
36
|
|
37
|
-
# desc "Empty the database from DATABASE_URL or config/database.yml for the current RAILS_ENV (use db:
|
37
|
+
# desc "Empty the database from DATABASE_URL or config/database.yml for the current RAILS_ENV (use db:purge:all to purge all databases in the config). Without RAILS_ENV it defaults to purging the development and test databases."
|
38
38
|
task :purge => [:load_config] do
|
39
39
|
ActiveRecord::Tasks::DatabaseTasks.purge_current
|
40
40
|
end
|
@@ -63,8 +63,6 @@ db_namespace = namespace :db do
|
|
63
63
|
namespace :migrate do
|
64
64
|
# desc 'Rollbacks the database one migration and re migrate up (options: STEP=x, VERSION=x).'
|
65
65
|
task :redo => [:environment, :load_config] do
|
66
|
-
raise "Empty VERSION provided" if ENV["VERSION"] && ENV["VERSION"].empty?
|
67
|
-
|
68
66
|
if ENV['VERSION']
|
69
67
|
db_namespace['migrate:down'].invoke
|
70
68
|
db_namespace['migrate:up'].invoke
|
@@ -79,18 +77,17 @@ db_namespace = namespace :db do
|
|
79
77
|
|
80
78
|
# desc 'Runs the "up" for a given migration VERSION.'
|
81
79
|
task :up => [:environment, :load_config] do
|
82
|
-
raise "VERSION is required" if ENV["VERSION"] && ENV["VERSION"].empty?
|
83
|
-
|
84
80
|
version = ENV['VERSION'] ? ENV['VERSION'].to_i : nil
|
85
|
-
|
81
|
+
raise 'VERSION is required' unless version
|
82
|
+
ActiveRecord::Migrator.run(:up, ActiveRecord::Tasks::DatabaseTasks.migrations_paths, version)
|
86
83
|
db_namespace['_dump'].invoke
|
87
84
|
end
|
88
85
|
|
89
86
|
# desc 'Runs the "down" for a given migration VERSION.'
|
90
87
|
task :down => [:environment, :load_config] do
|
91
|
-
raise "VERSION is required - To go down one migration, use db:rollback" if ENV["VERSION"] && ENV["VERSION"].empty?
|
92
88
|
version = ENV['VERSION'] ? ENV['VERSION'].to_i : nil
|
93
|
-
|
89
|
+
raise 'VERSION is required - To go down one migration, run db:rollback' unless version
|
90
|
+
ActiveRecord::Migrator.run(:down, ActiveRecord::Tasks::DatabaseTasks.migrations_paths, version)
|
94
91
|
db_namespace['_dump'].invoke
|
95
92
|
end
|
96
93
|
|
@@ -99,13 +96,28 @@ db_namespace = namespace :db do
|
|
99
96
|
unless ActiveRecord::SchemaMigration.table_exists?
|
100
97
|
abort 'Schema migrations table does not exist yet.'
|
101
98
|
end
|
99
|
+
db_list = ActiveRecord::SchemaMigration.normalized_versions
|
100
|
+
|
101
|
+
file_list =
|
102
|
+
ActiveRecord::Tasks::DatabaseTasks.migrations_paths.flat_map do |path|
|
103
|
+
Dir.foreach(path).map do |file|
|
104
|
+
next unless ActiveRecord::Migrator.match_to_migration_filename?(file)
|
105
|
+
|
106
|
+
version, name, scope = ActiveRecord::Migrator.parse_migration_filename(file)
|
107
|
+
version = ActiveRecord::SchemaMigration.normalize_migration_number(version)
|
108
|
+
status = db_list.delete(version) ? 'up' : 'down'
|
109
|
+
[status, version, (name + scope).humanize]
|
110
|
+
end.compact
|
111
|
+
end
|
102
112
|
|
113
|
+
db_list.map! do |version|
|
114
|
+
['up', version, '********** NO FILE **********']
|
115
|
+
end
|
103
116
|
# output
|
104
117
|
puts "\ndatabase: #{ActiveRecord::Base.connection_config[:database]}\n\n"
|
105
118
|
puts "#{'Status'.center(8)} #{'Migration ID'.ljust(14)} Migration Name"
|
106
119
|
puts "-" * 50
|
107
|
-
|
108
|
-
ActiveRecord::Migrator.migrations_status(paths).each do |status, version, name|
|
120
|
+
(db_list + file_list).sort_by { |_, version, _| version }.each do |status, version, name|
|
109
121
|
puts "#{status.center(8)} #{version.ljust(14)} #{name}"
|
110
122
|
end
|
111
123
|
puts
|
@@ -115,22 +127,19 @@ db_namespace = namespace :db do
|
|
115
127
|
desc 'Rolls the schema back to the previous version (specify steps w/ STEP=n).'
|
116
128
|
task :rollback => [:environment, :load_config] do
|
117
129
|
step = ENV['STEP'] ? ENV['STEP'].to_i : 1
|
118
|
-
ActiveRecord::Migrator.rollback(ActiveRecord::
|
130
|
+
ActiveRecord::Migrator.rollback(ActiveRecord::Tasks::DatabaseTasks.migrations_paths, step)
|
119
131
|
db_namespace['_dump'].invoke
|
120
132
|
end
|
121
133
|
|
122
134
|
# desc 'Pushes the schema to the next version (specify steps w/ STEP=n).'
|
123
135
|
task :forward => [:environment, :load_config] do
|
124
136
|
step = ENV['STEP'] ? ENV['STEP'].to_i : 1
|
125
|
-
ActiveRecord::Migrator.forward(ActiveRecord::
|
137
|
+
ActiveRecord::Migrator.forward(ActiveRecord::Tasks::DatabaseTasks.migrations_paths, step)
|
126
138
|
db_namespace['_dump'].invoke
|
127
139
|
end
|
128
140
|
|
129
141
|
# desc 'Drops and recreates the database from db/schema.rb for the current environment and loads the seeds.'
|
130
|
-
task :reset => [:
|
131
|
-
db_namespace["drop"].invoke
|
132
|
-
db_namespace["setup"].invoke
|
133
|
-
end
|
142
|
+
task :reset => [ 'db:drop', 'db:setup' ]
|
134
143
|
|
135
144
|
# desc "Retrieves the charset for the current environment's database"
|
136
145
|
task :charset => [:environment, :load_config] do
|
@@ -152,29 +161,29 @@ db_namespace = namespace :db do
|
|
152
161
|
end
|
153
162
|
|
154
163
|
# desc "Raises an error if there are pending migrations"
|
155
|
-
task :abort_if_pending_migrations => :environment do
|
156
|
-
pending_migrations = ActiveRecord::Migrator.open(ActiveRecord::
|
164
|
+
task :abort_if_pending_migrations => [:environment, :load_config] do
|
165
|
+
pending_migrations = ActiveRecord::Migrator.open(ActiveRecord::Tasks::DatabaseTasks.migrations_paths).pending_migrations
|
157
166
|
|
158
167
|
if pending_migrations.any?
|
159
168
|
puts "You have #{pending_migrations.size} pending #{pending_migrations.size > 1 ? 'migrations:' : 'migration:'}"
|
160
169
|
pending_migrations.each do |pending_migration|
|
161
170
|
puts ' %4d %s' % [pending_migration.version, pending_migration.name]
|
162
171
|
end
|
163
|
-
abort %{Run `
|
172
|
+
abort %{Run `rails db:migrate` to update your database then try again.}
|
164
173
|
end
|
165
174
|
end
|
166
175
|
|
167
|
-
desc '
|
176
|
+
desc 'Creates the database, loads the schema, and initializes with the seed data (use db:reset to also drop the database first)'
|
168
177
|
task :setup => ['db:schema:load_if_ruby', 'db:structure:load_if_sql', :seed]
|
169
178
|
|
170
|
-
desc '
|
179
|
+
desc 'Loads the seed data from db/seeds.rb'
|
171
180
|
task :seed do
|
172
181
|
db_namespace['abort_if_pending_migrations'].invoke
|
173
182
|
ActiveRecord::Tasks::DatabaseTasks.load_seed
|
174
183
|
end
|
175
184
|
|
176
185
|
namespace :fixtures do
|
177
|
-
desc "
|
186
|
+
desc "Loads fixtures into the current environment's database. Load specific fixtures using FIXTURES=x,y. Load from subdirectory in test/fixtures using FIXTURES_DIR=z. Specify an alternative path (eg. spec/fixtures) using FIXTURES_PATH=spec/fixtures."
|
178
187
|
task :load => [:environment, :load_config] do
|
179
188
|
require 'active_record/fixtures'
|
180
189
|
|
@@ -222,7 +231,7 @@ db_namespace = namespace :db do
|
|
222
231
|
end
|
223
232
|
|
224
233
|
namespace :schema do
|
225
|
-
desc '
|
234
|
+
desc 'Creates a db/schema.rb file that is portable against any DB supported by Active Record'
|
226
235
|
task :dump => [:environment, :load_config] do
|
227
236
|
require 'active_record/schema_dumper'
|
228
237
|
filename = ENV['SCHEMA'] || File.join(ActiveRecord::Tasks::DatabaseTasks.db_dir, 'schema.rb')
|
@@ -232,7 +241,7 @@ db_namespace = namespace :db do
|
|
232
241
|
db_namespace['schema:dump'].reenable
|
233
242
|
end
|
234
243
|
|
235
|
-
desc '
|
244
|
+
desc 'Loads a schema.rb file into the database'
|
236
245
|
task :load => [:environment, :load_config] do
|
237
246
|
ActiveRecord::Tasks::DatabaseTasks.load_schema_current(:ruby, ENV['SCHEMA'])
|
238
247
|
end
|
@@ -242,17 +251,17 @@ db_namespace = namespace :db do
|
|
242
251
|
end
|
243
252
|
|
244
253
|
namespace :cache do
|
245
|
-
desc '
|
254
|
+
desc 'Creates a db/schema_cache.dump file.'
|
246
255
|
task :dump => [:environment, :load_config] do
|
247
256
|
con = ActiveRecord::Base.connection
|
248
257
|
filename = File.join(ActiveRecord::Tasks::DatabaseTasks.db_dir, "schema_cache.dump")
|
249
258
|
|
250
259
|
con.schema_cache.clear!
|
251
|
-
con.
|
260
|
+
con.data_sources.each { |table| con.schema_cache.add(table) }
|
252
261
|
open(filename, 'wb') { |f| f.write(Marshal.dump(con.schema_cache)) }
|
253
262
|
end
|
254
263
|
|
255
|
-
desc '
|
264
|
+
desc 'Clears a db/schema_cache.dump file.'
|
256
265
|
task :clear => [:environment, :load_config] do
|
257
266
|
filename = File.join(ActiveRecord::Tasks::DatabaseTasks.db_dir, "schema_cache.dump")
|
258
267
|
FileUtils.rm(filename) if File.exist?(filename)
|
@@ -262,9 +271,9 @@ db_namespace = namespace :db do
|
|
262
271
|
end
|
263
272
|
|
264
273
|
namespace :structure do
|
265
|
-
desc '
|
274
|
+
desc 'Dumps the database structure to db/structure.sql. Specify another file with SCHEMA=db/my_structure.sql'
|
266
275
|
task :dump => [:environment, :load_config] do
|
267
|
-
filename = ENV['
|
276
|
+
filename = ENV['SCHEMA'] || File.join(ActiveRecord::Tasks::DatabaseTasks.db_dir, "structure.sql")
|
268
277
|
current_config = ActiveRecord::Tasks::DatabaseTasks.current_config
|
269
278
|
ActiveRecord::Tasks::DatabaseTasks.structure_dump(current_config, filename)
|
270
279
|
|
@@ -278,9 +287,9 @@ db_namespace = namespace :db do
|
|
278
287
|
db_namespace['structure:dump'].reenable
|
279
288
|
end
|
280
289
|
|
281
|
-
desc "
|
290
|
+
desc "Recreates the databases from the structure.sql file"
|
282
291
|
task :load => [:load_config] do
|
283
|
-
ActiveRecord::Tasks::DatabaseTasks.load_schema_current(:sql, ENV['
|
292
|
+
ActiveRecord::Tasks::DatabaseTasks.load_schema_current(:sql, ENV['SCHEMA'])
|
284
293
|
end
|
285
294
|
|
286
295
|
task :load_if_sql => ['db:create', :environment] do
|
@@ -312,7 +321,7 @@ db_namespace = namespace :db do
|
|
312
321
|
begin
|
313
322
|
should_reconnect = ActiveRecord::Base.connection_pool.active_connection?
|
314
323
|
ActiveRecord::Schema.verbose = false
|
315
|
-
ActiveRecord::Tasks::DatabaseTasks.
|
324
|
+
ActiveRecord::Tasks::DatabaseTasks.load_schema ActiveRecord::Base.configurations['test'], :ruby, ENV['SCHEMA']
|
316
325
|
ensure
|
317
326
|
if should_reconnect
|
318
327
|
ActiveRecord::Base.establish_connection(ActiveRecord::Base.configurations[ActiveRecord::Tasks::DatabaseTasks.env])
|
@@ -322,7 +331,7 @@ db_namespace = namespace :db do
|
|
322
331
|
|
323
332
|
# desc "Recreate the test database from an existent structure.sql file"
|
324
333
|
task :load_structure => %w(db:test:purge) do
|
325
|
-
ActiveRecord::Tasks::DatabaseTasks.
|
334
|
+
ActiveRecord::Tasks::DatabaseTasks.load_schema ActiveRecord::Base.configurations['test'], :sql, ENV['SCHEMA']
|
326
335
|
end
|
327
336
|
|
328
337
|
# desc "Recreate the test database from a fresh schema"
|
@@ -346,7 +355,7 @@ db_namespace = namespace :db do
|
|
346
355
|
ActiveRecord::Tasks::DatabaseTasks.purge ActiveRecord::Base.configurations['test']
|
347
356
|
end
|
348
357
|
|
349
|
-
# desc '
|
358
|
+
# desc 'Load the test schema'
|
350
359
|
task :prepare => %w(environment load_config) do
|
351
360
|
unless ActiveRecord::Base.configurations.blank?
|
352
361
|
db_namespace['test:load'].invoke
|
@@ -359,7 +368,7 @@ namespace :railties do
|
|
359
368
|
namespace :install do
|
360
369
|
# desc "Copies missing migrations from Railties (e.g. engines). You can specify Railties to use with FROM=railtie1,railtie2"
|
361
370
|
task :migrations => :'db:load_config' do
|
362
|
-
to_load = ENV['FROM'].blank? ? :all : ENV['FROM'].split(",").map
|
371
|
+
to_load = ENV['FROM'].blank? ? :all : ENV['FROM'].split(",").map(&:strip)
|
363
372
|
railties = {}
|
364
373
|
Rails.application.migration_railties.each do |railtie|
|
365
374
|
next unless to_load == :all || to_load.include?(railtie.railtie_name)
|
@@ -377,7 +386,7 @@ namespace :railties do
|
|
377
386
|
puts "Copied migration #{migration.basename} from #{name}"
|
378
387
|
end
|
379
388
|
|
380
|
-
ActiveRecord::Migration.copy(ActiveRecord::
|
389
|
+
ActiveRecord::Migration.copy(ActiveRecord::Tasks::DatabaseTasks.migrations_paths.first, railties,
|
381
390
|
:on_skip => on_skip, :on_copy => on_copy)
|
382
391
|
end
|
383
392
|
end
|
@@ -11,7 +11,7 @@ module ActiveRecord
|
|
11
11
|
# Attributes listed as readonly will be used to create a new record but update operations will
|
12
12
|
# ignore these fields.
|
13
13
|
def attr_readonly(*attributes)
|
14
|
-
self._attr_readonly = Set.new(attributes.map
|
14
|
+
self._attr_readonly = Set.new(attributes.map(&:to_s)) + (self._attr_readonly || [])
|
15
15
|
end
|
16
16
|
|
17
17
|
# Returns an array of all the attributes that have been specified as readonly.
|
@@ -7,8 +7,8 @@ module ActiveRecord
|
|
7
7
|
extend ActiveSupport::Concern
|
8
8
|
|
9
9
|
included do
|
10
|
-
class_attribute :_reflections
|
11
|
-
class_attribute :aggregate_reflections
|
10
|
+
class_attribute :_reflections
|
11
|
+
class_attribute :aggregate_reflections
|
12
12
|
self._reflections = {}
|
13
13
|
self.aggregate_reflections = {}
|
14
14
|
end
|
@@ -40,9 +40,9 @@ module ActiveRecord
|
|
40
40
|
ar.aggregate_reflections = ar.aggregate_reflections.merge(name.to_s => reflection)
|
41
41
|
end
|
42
42
|
|
43
|
-
# \Reflection enables
|
44
|
-
#
|
45
|
-
#
|
43
|
+
# \Reflection enables the ability to examine the associations and aggregations of
|
44
|
+
# Active Record classes and objects. This information, for example,
|
45
|
+
# can be used in a form builder that takes an Active Record object
|
46
46
|
# and creates input fields for all of the attributes depending on their type
|
47
47
|
# and displays the associations to other objects.
|
48
48
|
#
|
@@ -62,20 +62,20 @@ module ActiveRecord
|
|
62
62
|
aggregate_reflections[aggregation.to_s]
|
63
63
|
end
|
64
64
|
|
65
|
-
# Returns a Hash of name of the reflection as the key and
|
65
|
+
# Returns a Hash of name of the reflection as the key and an AssociationReflection as the value.
|
66
66
|
#
|
67
67
|
# Account.reflections # => {"balance" => AggregateReflection}
|
68
68
|
#
|
69
|
-
# @api public
|
70
69
|
def reflections
|
71
70
|
@__reflections ||= begin
|
72
71
|
ref = {}
|
73
72
|
|
74
73
|
_reflections.each do |name, reflection|
|
75
|
-
|
74
|
+
parent_reflection = reflection.parent_reflection
|
76
75
|
|
77
|
-
if
|
78
|
-
|
76
|
+
if parent_reflection
|
77
|
+
parent_name = parent_reflection.name
|
78
|
+
ref[parent_name.to_s] = parent_reflection
|
79
79
|
else
|
80
80
|
ref[name] = reflection
|
81
81
|
end
|
@@ -95,10 +95,10 @@ module ActiveRecord
|
|
95
95
|
# Account.reflect_on_all_associations # returns an array of all associations
|
96
96
|
# Account.reflect_on_all_associations(:has_many) # returns an array of all has_many associations
|
97
97
|
#
|
98
|
-
# @api public
|
99
98
|
def reflect_on_all_associations(macro = nil)
|
100
99
|
association_reflections = reflections.values
|
101
|
-
|
100
|
+
association_reflections.select! { |reflection| reflection.macro == macro } if macro
|
101
|
+
association_reflections
|
102
102
|
end
|
103
103
|
|
104
104
|
# Returns the AssociationReflection object for the +association+ (use the symbol).
|
@@ -106,24 +106,20 @@ module ActiveRecord
|
|
106
106
|
# Account.reflect_on_association(:owner) # returns the owner AssociationReflection
|
107
107
|
# Invoice.reflect_on_association(:line_items).macro # returns :has_many
|
108
108
|
#
|
109
|
-
# @api public
|
110
109
|
def reflect_on_association(association)
|
111
110
|
reflections[association.to_s]
|
112
111
|
end
|
113
112
|
|
114
|
-
# @api private
|
115
113
|
def _reflect_on_association(association) #:nodoc:
|
116
114
|
_reflections[association.to_s]
|
117
115
|
end
|
118
116
|
|
119
117
|
# Returns an array of AssociationReflection objects for all associations which have <tt>:autosave</tt> enabled.
|
120
|
-
#
|
121
|
-
# @api public
|
122
118
|
def reflect_on_all_autosave_associations
|
123
119
|
reflections.values.select { |reflection| reflection.options[:autosave] }
|
124
120
|
end
|
125
121
|
|
126
|
-
def clear_reflections_cache
|
122
|
+
def clear_reflections_cache # :nodoc:
|
127
123
|
@__reflections = nil
|
128
124
|
end
|
129
125
|
end
|
@@ -159,17 +155,24 @@ module ActiveRecord
|
|
159
155
|
|
160
156
|
JoinKeys = Struct.new(:key, :foreign_key) # :nodoc:
|
161
157
|
|
162
|
-
def join_keys(
|
158
|
+
def join_keys(association_klass)
|
163
159
|
JoinKeys.new(foreign_key, active_record_primary_key)
|
164
160
|
end
|
165
161
|
|
166
|
-
def
|
167
|
-
|
168
|
-
|
169
|
-
without replacement.
|
170
|
-
MSG
|
162
|
+
def constraints
|
163
|
+
scope_chain.flatten
|
164
|
+
end
|
171
165
|
|
172
|
-
|
166
|
+
def counter_cache_column
|
167
|
+
if belongs_to?
|
168
|
+
if options[:counter_cache] == true
|
169
|
+
"#{active_record.name.demodulize.underscore.pluralize}_count"
|
170
|
+
elsif options[:counter_cache]
|
171
|
+
options[:counter_cache].to_s
|
172
|
+
end
|
173
|
+
else
|
174
|
+
options[:counter_cache] ? options[:counter_cache].to_s : "#{name}_count"
|
175
|
+
end
|
173
176
|
end
|
174
177
|
|
175
178
|
def inverse_of
|
@@ -185,13 +188,54 @@ module ActiveRecord
|
|
185
188
|
end
|
186
189
|
end
|
187
190
|
end
|
191
|
+
|
192
|
+
# This shit is nasty. We need to avoid the following situation:
|
193
|
+
#
|
194
|
+
# * An associated record is deleted via record.destroy
|
195
|
+
# * Hence the callbacks run, and they find a belongs_to on the record with a
|
196
|
+
# :counter_cache options which points back at our owner. So they update the
|
197
|
+
# counter cache.
|
198
|
+
# * In which case, we must make sure to *not* update the counter cache, or else
|
199
|
+
# it will be decremented twice.
|
200
|
+
#
|
201
|
+
# Hence this method.
|
202
|
+
def inverse_which_updates_counter_cache
|
203
|
+
return @inverse_which_updates_counter_cache if defined?(@inverse_which_updates_counter_cache)
|
204
|
+
@inverse_which_updates_counter_cache = klass.reflect_on_all_associations(:belongs_to).find do |inverse|
|
205
|
+
inverse.counter_cache_column == counter_cache_column
|
206
|
+
end
|
207
|
+
end
|
208
|
+
alias inverse_updates_counter_cache? inverse_which_updates_counter_cache
|
209
|
+
|
210
|
+
def inverse_updates_counter_in_memory?
|
211
|
+
inverse_of && inverse_which_updates_counter_cache == inverse_of
|
212
|
+
end
|
213
|
+
|
214
|
+
# Returns whether a counter cache should be used for this association.
|
215
|
+
#
|
216
|
+
# The counter_cache option must be given on either the owner or inverse
|
217
|
+
# association, and the column must be present on the owner.
|
218
|
+
def has_cached_counter?
|
219
|
+
options[:counter_cache] ||
|
220
|
+
inverse_which_updates_counter_cache && inverse_which_updates_counter_cache.options[:counter_cache] &&
|
221
|
+
!!active_record.columns_hash[counter_cache_column]
|
222
|
+
end
|
223
|
+
|
224
|
+
def counter_must_be_updated_by_has_many?
|
225
|
+
!inverse_updates_counter_in_memory? && has_cached_counter?
|
226
|
+
end
|
227
|
+
|
228
|
+
def alias_candidate(name)
|
229
|
+
"#{plural_name}_#{name}"
|
230
|
+
end
|
188
231
|
end
|
232
|
+
|
189
233
|
# Base class for AggregateReflection and AssociationReflection. Objects of
|
190
234
|
# AggregateReflection and AssociationReflection are returned by the Reflection::ClassMethods.
|
191
235
|
#
|
192
236
|
# MacroReflection
|
237
|
+
# AggregateReflection
|
193
238
|
# AssociationReflection
|
194
|
-
# AggregateReflection
|
195
239
|
# HasManyReflection
|
196
240
|
# HasOneReflection
|
197
241
|
# BelongsToReflection
|
@@ -228,7 +272,7 @@ module ActiveRecord
|
|
228
272
|
def autosave=(autosave)
|
229
273
|
@automatic_inverse_of = false
|
230
274
|
@options[:autosave] = autosave
|
231
|
-
|
275
|
+
parent_reflection = self.parent_reflection
|
232
276
|
if parent_reflection
|
233
277
|
parent_reflection.autosave = autosave
|
234
278
|
end
|
@@ -296,7 +340,7 @@ module ActiveRecord
|
|
296
340
|
end
|
297
341
|
|
298
342
|
attr_reader :type, :foreign_type
|
299
|
-
attr_accessor :parent_reflection #
|
343
|
+
attr_accessor :parent_reflection # Reflection
|
300
344
|
|
301
345
|
def initialize(name, scope, options, active_record)
|
302
346
|
super
|
@@ -343,14 +387,6 @@ module ActiveRecord
|
|
343
387
|
@active_record_primary_key ||= options[:primary_key] || primary_key(active_record)
|
344
388
|
end
|
345
389
|
|
346
|
-
def counter_cache_column
|
347
|
-
if options[:counter_cache] == true
|
348
|
-
"#{active_record.name.demodulize.underscore.pluralize}_count"
|
349
|
-
elsif options[:counter_cache]
|
350
|
-
options[:counter_cache].to_s
|
351
|
-
end
|
352
|
-
end
|
353
|
-
|
354
390
|
def check_validity!
|
355
391
|
check_validity_of_inverse!
|
356
392
|
end
|
@@ -359,13 +395,10 @@ module ActiveRecord
|
|
359
395
|
return unless scope
|
360
396
|
|
361
397
|
if scope.arity > 0
|
362
|
-
|
398
|
+
raise ArgumentError, <<-MSG.squish
|
363
399
|
The association scope '#{name}' is instance dependent (the scope
|
364
|
-
block takes an argument). Preloading
|
365
|
-
|
366
|
-
passed to the association scope. This will most likely result in
|
367
|
-
broken or incorrect behavior. Joining, Preloading and eager loading
|
368
|
-
of these associations is deprecated and will be removed in the future.
|
400
|
+
block takes an argument). Preloading instance dependent scopes is
|
401
|
+
not supported.
|
369
402
|
MSG
|
370
403
|
end
|
371
404
|
end
|
@@ -389,6 +422,12 @@ module ActiveRecord
|
|
389
422
|
[self]
|
390
423
|
end
|
391
424
|
|
425
|
+
# This is for clearing cache on the reflection. Useful for tests that need to compare
|
426
|
+
# SQL queries on associations.
|
427
|
+
def clear_association_scope_cache # :nodoc:
|
428
|
+
@association_scope_cache.clear
|
429
|
+
end
|
430
|
+
|
392
431
|
def nested?
|
393
432
|
false
|
394
433
|
end
|
@@ -611,8 +650,8 @@ module ActiveRecord
|
|
611
650
|
|
612
651
|
def belongs_to?; true; end
|
613
652
|
|
614
|
-
def join_keys(
|
615
|
-
key = polymorphic? ? association_primary_key(
|
653
|
+
def join_keys(association_klass)
|
654
|
+
key = polymorphic? ? association_primary_key(association_klass) : association_primary_key
|
616
655
|
JoinKeys.new(key, foreign_key)
|
617
656
|
end
|
618
657
|
|
@@ -707,13 +746,27 @@ module ActiveRecord
|
|
707
746
|
def chain
|
708
747
|
@chain ||= begin
|
709
748
|
a = source_reflection.chain
|
710
|
-
b = through_reflection.chain
|
749
|
+
b = through_reflection.chain.map(&:dup)
|
750
|
+
|
751
|
+
if options[:source_type]
|
752
|
+
b[0] = PolymorphicReflection.new(b[0], self)
|
753
|
+
end
|
754
|
+
|
711
755
|
chain = a + b
|
712
756
|
chain[0] = self # Use self so we don't lose the information from :source_type
|
713
757
|
chain
|
714
758
|
end
|
715
759
|
end
|
716
760
|
|
761
|
+
# This is for clearing cache on the reflection. Useful for tests that need to compare
|
762
|
+
# SQL queries on associations.
|
763
|
+
def clear_association_scope_cache # :nodoc:
|
764
|
+
@chain = nil
|
765
|
+
delegate_reflection.clear_association_scope_cache
|
766
|
+
source_reflection.clear_association_scope_cache
|
767
|
+
through_reflection.clear_association_scope_cache
|
768
|
+
end
|
769
|
+
|
717
770
|
# Consider the following example:
|
718
771
|
#
|
719
772
|
# class Person
|
@@ -755,18 +808,8 @@ module ActiveRecord
|
|
755
808
|
end
|
756
809
|
end
|
757
810
|
|
758
|
-
def join_keys(
|
759
|
-
source_reflection.join_keys(
|
760
|
-
end
|
761
|
-
|
762
|
-
# The macro used by the source association
|
763
|
-
def source_macro
|
764
|
-
ActiveSupport::Deprecation.warn(<<-MSG.squish)
|
765
|
-
ActiveRecord::Base.source_macro is deprecated and will be removed
|
766
|
-
without replacement.
|
767
|
-
MSG
|
768
|
-
|
769
|
-
source_reflection.source_macro
|
811
|
+
def join_keys(association_klass)
|
812
|
+
source_reflection.join_keys(association_klass)
|
770
813
|
end
|
771
814
|
|
772
815
|
# A through association is nested if there would be more than one join table
|
@@ -801,7 +844,7 @@ module ActiveRecord
|
|
801
844
|
def source_reflection_name # :nodoc:
|
802
845
|
return @source_reflection_name if @source_reflection_name
|
803
846
|
|
804
|
-
names = [name.to_s.singularize, name].collect
|
847
|
+
names = [name.to_s.singularize, name].collect(&:to_sym).uniq
|
805
848
|
names = names.find_all { |n|
|
806
849
|
through_reflection.klass._reflect_on_association(n)
|
807
850
|
}
|
@@ -865,6 +908,12 @@ module ActiveRecord
|
|
865
908
|
check_validity_of_inverse!
|
866
909
|
end
|
867
910
|
|
911
|
+
def constraints
|
912
|
+
scope_chain = source_reflection.constraints
|
913
|
+
scope_chain << scope if scope
|
914
|
+
scope_chain
|
915
|
+
end
|
916
|
+
|
868
917
|
protected
|
869
918
|
|
870
919
|
def actual_source_reflection # FIXME: this is a horrible name
|
@@ -889,5 +938,81 @@ module ActiveRecord
|
|
889
938
|
delegate(*delegate_methods, to: :delegate_reflection)
|
890
939
|
|
891
940
|
end
|
941
|
+
|
942
|
+
class PolymorphicReflection < ThroughReflection # :nodoc:
|
943
|
+
def initialize(reflection, previous_reflection)
|
944
|
+
@reflection = reflection
|
945
|
+
@previous_reflection = previous_reflection
|
946
|
+
end
|
947
|
+
|
948
|
+
def klass
|
949
|
+
@reflection.klass
|
950
|
+
end
|
951
|
+
|
952
|
+
def scope
|
953
|
+
@reflection.scope
|
954
|
+
end
|
955
|
+
|
956
|
+
def table_name
|
957
|
+
@reflection.table_name
|
958
|
+
end
|
959
|
+
|
960
|
+
def plural_name
|
961
|
+
@reflection.plural_name
|
962
|
+
end
|
963
|
+
|
964
|
+
def join_keys(association_klass)
|
965
|
+
@reflection.join_keys(association_klass)
|
966
|
+
end
|
967
|
+
|
968
|
+
def type
|
969
|
+
@reflection.type
|
970
|
+
end
|
971
|
+
|
972
|
+
def constraints
|
973
|
+
[source_type_info]
|
974
|
+
end
|
975
|
+
|
976
|
+
def source_type_info
|
977
|
+
type = @previous_reflection.foreign_type
|
978
|
+
source_type = @previous_reflection.options[:source_type]
|
979
|
+
lambda { |object| where(type => source_type) }
|
980
|
+
end
|
981
|
+
end
|
982
|
+
|
983
|
+
class RuntimeReflection < PolymorphicReflection # :nodoc:
|
984
|
+
attr_accessor :next
|
985
|
+
|
986
|
+
def initialize(reflection, association)
|
987
|
+
@reflection = reflection
|
988
|
+
@association = association
|
989
|
+
end
|
990
|
+
|
991
|
+
def klass
|
992
|
+
@association.klass
|
993
|
+
end
|
994
|
+
|
995
|
+
def table_name
|
996
|
+
klass.table_name
|
997
|
+
end
|
998
|
+
|
999
|
+
def constraints
|
1000
|
+
@reflection.constraints
|
1001
|
+
end
|
1002
|
+
|
1003
|
+
def source_type_info
|
1004
|
+
@reflection.source_type_info
|
1005
|
+
end
|
1006
|
+
|
1007
|
+
def alias_candidate(name)
|
1008
|
+
"#{plural_name}_#{name}_join"
|
1009
|
+
end
|
1010
|
+
|
1011
|
+
def alias_name
|
1012
|
+
Arel::Table.new(table_name)
|
1013
|
+
end
|
1014
|
+
|
1015
|
+
def all_includes; yield; end
|
1016
|
+
end
|
892
1017
|
end
|
893
1018
|
end
|