activerecord 2.3.18 → 3.2.22
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 +7 -0
- data/CHANGELOG.md +1014 -0
- data/MIT-LICENSE +20 -0
- data/README.rdoc +222 -0
- data/examples/performance.rb +100 -126
- data/examples/simple.rb +14 -0
- data/lib/active_record/aggregations.rb +93 -99
- data/lib/active_record/associations/alias_tracker.rb +76 -0
- data/lib/active_record/associations/association.rb +247 -0
- data/lib/active_record/associations/association_scope.rb +134 -0
- data/lib/active_record/associations/belongs_to_association.rb +54 -61
- data/lib/active_record/associations/belongs_to_polymorphic_association.rb +17 -59
- data/lib/active_record/associations/builder/association.rb +55 -0
- data/lib/active_record/associations/builder/belongs_to.rb +88 -0
- data/lib/active_record/associations/builder/collection_association.rb +75 -0
- data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +57 -0
- data/lib/active_record/associations/builder/has_many.rb +71 -0
- data/lib/active_record/associations/builder/has_one.rb +62 -0
- data/lib/active_record/associations/builder/singular_association.rb +32 -0
- data/lib/active_record/associations/collection_association.rb +580 -0
- data/lib/active_record/associations/collection_proxy.rb +133 -0
- data/lib/active_record/associations/has_and_belongs_to_many_association.rb +39 -119
- data/lib/active_record/associations/has_many_association.rb +60 -79
- data/lib/active_record/associations/has_many_through_association.rb +127 -206
- data/lib/active_record/associations/has_one_association.rb +55 -114
- data/lib/active_record/associations/has_one_through_association.rb +25 -26
- data/lib/active_record/associations/join_dependency/join_association.rb +159 -0
- data/lib/active_record/associations/join_dependency/join_base.rb +24 -0
- data/lib/active_record/associations/join_dependency/join_part.rb +78 -0
- data/lib/active_record/associations/join_dependency.rb +214 -0
- data/lib/active_record/associations/join_helper.rb +55 -0
- data/lib/active_record/associations/preloader/association.rb +125 -0
- data/lib/active_record/associations/preloader/belongs_to.rb +17 -0
- data/lib/active_record/associations/preloader/collection_association.rb +24 -0
- data/lib/active_record/associations/preloader/has_and_belongs_to_many.rb +60 -0
- data/lib/active_record/associations/preloader/has_many.rb +17 -0
- data/lib/active_record/associations/preloader/has_many_through.rb +15 -0
- data/lib/active_record/associations/preloader/has_one.rb +23 -0
- data/lib/active_record/associations/preloader/has_one_through.rb +9 -0
- data/lib/active_record/associations/preloader/singular_association.rb +21 -0
- data/lib/active_record/associations/preloader/through_association.rb +67 -0
- data/lib/active_record/associations/preloader.rb +181 -0
- data/lib/active_record/associations/singular_association.rb +64 -0
- data/lib/active_record/associations/through_association.rb +87 -0
- data/lib/active_record/associations.rb +693 -1337
- data/lib/active_record/attribute_assignment.rb +221 -0
- data/lib/active_record/attribute_methods/before_type_cast.rb +31 -0
- data/lib/active_record/attribute_methods/deprecated_underscore_read.rb +32 -0
- data/lib/active_record/attribute_methods/dirty.rb +111 -0
- data/lib/active_record/attribute_methods/primary_key.rb +114 -0
- data/lib/active_record/attribute_methods/query.rb +39 -0
- data/lib/active_record/attribute_methods/read.rb +136 -0
- data/lib/active_record/attribute_methods/serialization.rb +120 -0
- data/lib/active_record/attribute_methods/time_zone_conversion.rb +65 -0
- data/lib/active_record/attribute_methods/write.rb +70 -0
- data/lib/active_record/attribute_methods.rb +211 -339
- data/lib/active_record/autosave_association.rb +179 -149
- data/lib/active_record/base.rb +401 -2907
- data/lib/active_record/callbacks.rb +91 -176
- data/lib/active_record/coders/yaml_column.rb +41 -0
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +236 -119
- data/lib/active_record/connection_adapters/abstract/connection_specification.rb +110 -58
- data/lib/active_record/connection_adapters/abstract/database_limits.rb +12 -11
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +175 -74
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +31 -35
- data/lib/active_record/connection_adapters/abstract/quoting.rb +71 -21
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +81 -311
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +194 -78
- data/lib/active_record/connection_adapters/abstract_adapter.rb +130 -83
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +676 -0
- data/lib/active_record/connection_adapters/column.rb +296 -0
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +280 -0
- data/lib/active_record/connection_adapters/mysql_adapter.rb +272 -493
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +650 -405
- data/lib/active_record/connection_adapters/schema_cache.rb +69 -0
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +30 -9
- data/lib/active_record/connection_adapters/sqlite_adapter.rb +276 -147
- data/lib/active_record/connection_adapters/statement_pool.rb +40 -0
- data/lib/active_record/counter_cache.rb +123 -0
- data/lib/active_record/dynamic_finder_match.rb +41 -14
- data/lib/active_record/dynamic_matchers.rb +84 -0
- data/lib/active_record/dynamic_scope_match.rb +13 -15
- data/lib/active_record/errors.rb +195 -0
- data/lib/active_record/explain.rb +86 -0
- data/lib/active_record/explain_subscriber.rb +25 -0
- data/lib/active_record/fixtures/file.rb +65 -0
- data/lib/active_record/fixtures.rb +695 -770
- data/lib/active_record/identity_map.rb +162 -0
- data/lib/active_record/inheritance.rb +174 -0
- data/lib/active_record/integration.rb +60 -0
- data/lib/active_record/locale/en.yml +9 -27
- data/lib/active_record/locking/optimistic.rb +76 -73
- data/lib/active_record/locking/pessimistic.rb +32 -10
- data/lib/active_record/log_subscriber.rb +72 -0
- data/lib/active_record/migration/command_recorder.rb +105 -0
- data/lib/active_record/migration.rb +415 -205
- data/lib/active_record/model_schema.rb +368 -0
- data/lib/active_record/nested_attributes.rb +153 -63
- data/lib/active_record/observer.rb +27 -103
- data/lib/active_record/persistence.rb +376 -0
- data/lib/active_record/query_cache.rb +49 -8
- data/lib/active_record/querying.rb +58 -0
- data/lib/active_record/railtie.rb +131 -0
- data/lib/active_record/railties/console_sandbox.rb +6 -0
- data/lib/active_record/railties/controller_runtime.rb +49 -0
- data/lib/active_record/railties/databases.rake +659 -0
- data/lib/active_record/railties/jdbcmysql_error.rb +16 -0
- data/lib/active_record/readonly_attributes.rb +26 -0
- data/lib/active_record/reflection.rb +269 -120
- data/lib/active_record/relation/batches.rb +90 -0
- data/lib/active_record/relation/calculations.rb +372 -0
- data/lib/active_record/relation/delegation.rb +49 -0
- data/lib/active_record/relation/finder_methods.rb +402 -0
- data/lib/active_record/relation/predicate_builder.rb +63 -0
- data/lib/active_record/relation/query_methods.rb +417 -0
- data/lib/active_record/relation/spawn_methods.rb +180 -0
- data/lib/active_record/relation.rb +537 -0
- data/lib/active_record/result.rb +40 -0
- data/lib/active_record/sanitization.rb +194 -0
- data/lib/active_record/schema.rb +9 -6
- data/lib/active_record/schema_dumper.rb +55 -32
- data/lib/active_record/scoping/default.rb +142 -0
- data/lib/active_record/scoping/named.rb +200 -0
- data/lib/active_record/scoping.rb +152 -0
- data/lib/active_record/serialization.rb +8 -91
- data/lib/active_record/serializers/xml_serializer.rb +43 -197
- data/lib/active_record/session_store.rb +129 -103
- data/lib/active_record/store.rb +52 -0
- data/lib/active_record/test_case.rb +30 -23
- data/lib/active_record/timestamp.rb +95 -52
- data/lib/active_record/transactions.rb +212 -66
- data/lib/active_record/translation.rb +22 -0
- data/lib/active_record/validations/associated.rb +43 -0
- data/lib/active_record/validations/uniqueness.rb +180 -0
- data/lib/active_record/validations.rb +43 -1106
- data/lib/active_record/version.rb +5 -4
- data/lib/active_record.rb +121 -48
- data/lib/rails/generators/active_record/migration/migration_generator.rb +25 -0
- data/lib/rails/generators/active_record/migration/templates/migration.rb +34 -0
- data/lib/rails/generators/active_record/migration.rb +15 -0
- data/lib/rails/generators/active_record/model/model_generator.rb +47 -0
- data/lib/rails/generators/active_record/model/templates/migration.rb +15 -0
- data/lib/rails/generators/active_record/model/templates/model.rb +12 -0
- data/lib/rails/generators/active_record/model/templates/module.rb +7 -0
- data/lib/rails/generators/active_record/observer/observer_generator.rb +15 -0
- data/lib/rails/generators/active_record/observer/templates/observer.rb +4 -0
- data/lib/rails/generators/active_record/session_migration/session_migration_generator.rb +25 -0
- data/lib/rails/generators/active_record/session_migration/templates/migration.rb +12 -0
- data/lib/rails/generators/active_record.rb +25 -0
- metadata +187 -363
- data/CHANGELOG +0 -5904
- data/README +0 -351
- data/RUNNING_UNIT_TESTS +0 -36
- data/Rakefile +0 -268
- data/install.rb +0 -30
- data/lib/active_record/association_preload.rb +0 -406
- data/lib/active_record/associations/association_collection.rb +0 -533
- data/lib/active_record/associations/association_proxy.rb +0 -288
- data/lib/active_record/batches.rb +0 -85
- data/lib/active_record/calculations.rb +0 -321
- data/lib/active_record/dirty.rb +0 -183
- data/lib/active_record/named_scope.rb +0 -197
- data/lib/active_record/serializers/json_serializer.rb +0 -91
- data/lib/activerecord.rb +0 -2
- data/test/assets/example.log +0 -1
- data/test/assets/flowers.jpg +0 -0
- data/test/cases/aaa_create_tables_test.rb +0 -24
- data/test/cases/active_schema_test_mysql.rb +0 -122
- data/test/cases/active_schema_test_postgresql.rb +0 -24
- data/test/cases/adapter_test.rb +0 -144
- data/test/cases/aggregations_test.rb +0 -167
- data/test/cases/ar_schema_test.rb +0 -32
- data/test/cases/associations/belongs_to_associations_test.rb +0 -438
- data/test/cases/associations/callbacks_test.rb +0 -161
- data/test/cases/associations/cascaded_eager_loading_test.rb +0 -131
- data/test/cases/associations/eager_load_includes_full_sti_class_test.rb +0 -36
- data/test/cases/associations/eager_load_nested_include_test.rb +0 -131
- data/test/cases/associations/eager_load_nested_polymorphic_include.rb +0 -19
- data/test/cases/associations/eager_singularization_test.rb +0 -145
- data/test/cases/associations/eager_test.rb +0 -852
- data/test/cases/associations/extension_test.rb +0 -62
- data/test/cases/associations/habtm_join_table_test.rb +0 -56
- data/test/cases/associations/has_and_belongs_to_many_associations_test.rb +0 -827
- data/test/cases/associations/has_many_associations_test.rb +0 -1273
- data/test/cases/associations/has_many_through_associations_test.rb +0 -360
- data/test/cases/associations/has_one_associations_test.rb +0 -330
- data/test/cases/associations/has_one_through_associations_test.rb +0 -209
- data/test/cases/associations/inner_join_association_test.rb +0 -93
- data/test/cases/associations/inverse_associations_test.rb +0 -566
- data/test/cases/associations/join_model_test.rb +0 -712
- data/test/cases/associations_test.rb +0 -282
- data/test/cases/attribute_methods_test.rb +0 -305
- data/test/cases/autosave_association_test.rb +0 -1218
- data/test/cases/base_test.rb +0 -2166
- data/test/cases/batches_test.rb +0 -81
- data/test/cases/binary_test.rb +0 -30
- data/test/cases/calculations_test.rb +0 -360
- data/test/cases/callbacks_observers_test.rb +0 -38
- data/test/cases/callbacks_test.rb +0 -438
- data/test/cases/class_inheritable_attributes_test.rb +0 -32
- data/test/cases/column_alias_test.rb +0 -17
- data/test/cases/column_definition_test.rb +0 -70
- data/test/cases/connection_pool_test.rb +0 -25
- data/test/cases/connection_test_firebird.rb +0 -8
- data/test/cases/connection_test_mysql.rb +0 -65
- data/test/cases/copy_table_test_sqlite.rb +0 -80
- data/test/cases/counter_cache_test.rb +0 -84
- data/test/cases/database_statements_test.rb +0 -12
- data/test/cases/datatype_test_postgresql.rb +0 -204
- data/test/cases/date_time_test.rb +0 -37
- data/test/cases/default_test_firebird.rb +0 -16
- data/test/cases/defaults_test.rb +0 -111
- data/test/cases/deprecated_finder_test.rb +0 -30
- data/test/cases/dirty_test.rb +0 -316
- data/test/cases/finder_respond_to_test.rb +0 -76
- data/test/cases/finder_test.rb +0 -1098
- data/test/cases/fixtures_test.rb +0 -661
- data/test/cases/helper.rb +0 -68
- data/test/cases/i18n_test.rb +0 -46
- data/test/cases/inheritance_test.rb +0 -262
- data/test/cases/invalid_date_test.rb +0 -24
- data/test/cases/json_serialization_test.rb +0 -219
- data/test/cases/lifecycle_test.rb +0 -193
- data/test/cases/locking_test.rb +0 -350
- data/test/cases/method_scoping_test.rb +0 -704
- data/test/cases/migration_test.rb +0 -1649
- data/test/cases/migration_test_firebird.rb +0 -124
- data/test/cases/mixin_test.rb +0 -96
- data/test/cases/modules_test.rb +0 -109
- data/test/cases/multiple_db_test.rb +0 -85
- data/test/cases/named_scope_test.rb +0 -372
- data/test/cases/nested_attributes_test.rb +0 -840
- data/test/cases/pk_test.rb +0 -119
- data/test/cases/pooled_connections_test.rb +0 -103
- data/test/cases/query_cache_test.rb +0 -129
- data/test/cases/readonly_test.rb +0 -107
- data/test/cases/reflection_test.rb +0 -234
- data/test/cases/reload_models_test.rb +0 -22
- data/test/cases/repair_helper.rb +0 -50
- data/test/cases/reserved_word_test_mysql.rb +0 -176
- data/test/cases/sanitize_test.rb +0 -25
- data/test/cases/schema_authorization_test_postgresql.rb +0 -75
- data/test/cases/schema_dumper_test.rb +0 -211
- data/test/cases/schema_test_postgresql.rb +0 -178
- data/test/cases/serialization_test.rb +0 -47
- data/test/cases/sp_test_mysql.rb +0 -16
- data/test/cases/synonym_test_oracle.rb +0 -17
- data/test/cases/timestamp_test.rb +0 -75
- data/test/cases/transactions_test.rb +0 -543
- data/test/cases/unconnected_test.rb +0 -32
- data/test/cases/validations_i18n_test.rb +0 -925
- data/test/cases/validations_test.rb +0 -1684
- data/test/cases/xml_serialization_test.rb +0 -240
- data/test/cases/yaml_serialization_test.rb +0 -11
- data/test/config.rb +0 -5
- data/test/connections/jdbc_jdbcderby/connection.rb +0 -18
- data/test/connections/jdbc_jdbch2/connection.rb +0 -18
- data/test/connections/jdbc_jdbchsqldb/connection.rb +0 -18
- data/test/connections/jdbc_jdbcmysql/connection.rb +0 -26
- data/test/connections/jdbc_jdbcpostgresql/connection.rb +0 -26
- data/test/connections/jdbc_jdbcsqlite3/connection.rb +0 -25
- data/test/connections/native_db2/connection.rb +0 -25
- data/test/connections/native_firebird/connection.rb +0 -26
- data/test/connections/native_frontbase/connection.rb +0 -27
- data/test/connections/native_mysql/connection.rb +0 -25
- data/test/connections/native_openbase/connection.rb +0 -21
- data/test/connections/native_oracle/connection.rb +0 -27
- data/test/connections/native_postgresql/connection.rb +0 -21
- data/test/connections/native_sqlite/connection.rb +0 -25
- data/test/connections/native_sqlite3/connection.rb +0 -25
- data/test/connections/native_sqlite3/in_memory_connection.rb +0 -18
- data/test/connections/native_sybase/connection.rb +0 -23
- data/test/fixtures/accounts.yml +0 -29
- data/test/fixtures/all/developers.yml +0 -0
- data/test/fixtures/all/people.csv +0 -0
- data/test/fixtures/all/tasks.yml +0 -0
- data/test/fixtures/author_addresses.yml +0 -5
- data/test/fixtures/author_favorites.yml +0 -4
- data/test/fixtures/authors.yml +0 -9
- data/test/fixtures/binaries.yml +0 -132
- data/test/fixtures/books.yml +0 -7
- data/test/fixtures/categories/special_categories.yml +0 -9
- data/test/fixtures/categories/subsubdir/arbitrary_filename.yml +0 -4
- data/test/fixtures/categories.yml +0 -14
- data/test/fixtures/categories_ordered.yml +0 -7
- data/test/fixtures/categories_posts.yml +0 -23
- data/test/fixtures/categorizations.yml +0 -17
- data/test/fixtures/clubs.yml +0 -6
- data/test/fixtures/comments.yml +0 -59
- data/test/fixtures/companies.yml +0 -56
- data/test/fixtures/computers.yml +0 -4
- data/test/fixtures/courses.yml +0 -7
- data/test/fixtures/customers.yml +0 -26
- data/test/fixtures/developers.yml +0 -21
- data/test/fixtures/developers_projects.yml +0 -17
- data/test/fixtures/edges.yml +0 -6
- data/test/fixtures/entrants.yml +0 -14
- data/test/fixtures/faces.yml +0 -11
- data/test/fixtures/fk_test_has_fk.yml +0 -3
- data/test/fixtures/fk_test_has_pk.yml +0 -2
- data/test/fixtures/funny_jokes.yml +0 -10
- data/test/fixtures/interests.yml +0 -33
- data/test/fixtures/items.yml +0 -4
- data/test/fixtures/jobs.yml +0 -7
- data/test/fixtures/legacy_things.yml +0 -3
- data/test/fixtures/mateys.yml +0 -4
- data/test/fixtures/member_types.yml +0 -6
- data/test/fixtures/members.yml +0 -6
- data/test/fixtures/memberships.yml +0 -20
- data/test/fixtures/men.yml +0 -5
- data/test/fixtures/minimalistics.yml +0 -2
- data/test/fixtures/mixed_case_monkeys.yml +0 -6
- data/test/fixtures/mixins.yml +0 -29
- data/test/fixtures/movies.yml +0 -7
- data/test/fixtures/naked/csv/accounts.csv +0 -1
- data/test/fixtures/naked/yml/accounts.yml +0 -1
- data/test/fixtures/naked/yml/companies.yml +0 -1
- data/test/fixtures/naked/yml/courses.yml +0 -1
- data/test/fixtures/organizations.yml +0 -5
- data/test/fixtures/owners.yml +0 -7
- data/test/fixtures/parrots.yml +0 -27
- data/test/fixtures/parrots_pirates.yml +0 -7
- data/test/fixtures/people.yml +0 -15
- data/test/fixtures/pets.yml +0 -14
- data/test/fixtures/pirates.yml +0 -9
- data/test/fixtures/polymorphic_designs.yml +0 -19
- data/test/fixtures/polymorphic_prices.yml +0 -19
- data/test/fixtures/posts.yml +0 -52
- data/test/fixtures/price_estimates.yml +0 -7
- data/test/fixtures/projects.yml +0 -7
- data/test/fixtures/readers.yml +0 -9
- data/test/fixtures/references.yml +0 -17
- data/test/fixtures/reserved_words/distinct.yml +0 -5
- data/test/fixtures/reserved_words/distincts_selects.yml +0 -11
- data/test/fixtures/reserved_words/group.yml +0 -14
- data/test/fixtures/reserved_words/select.yml +0 -8
- data/test/fixtures/reserved_words/values.yml +0 -7
- data/test/fixtures/ships.yml +0 -5
- data/test/fixtures/sponsors.yml +0 -9
- data/test/fixtures/subscribers.yml +0 -7
- data/test/fixtures/subscriptions.yml +0 -12
- data/test/fixtures/taggings.yml +0 -28
- data/test/fixtures/tags.yml +0 -7
- data/test/fixtures/tasks.yml +0 -7
- data/test/fixtures/tees.yml +0 -4
- data/test/fixtures/ties.yml +0 -4
- data/test/fixtures/topics.yml +0 -42
- data/test/fixtures/toys.yml +0 -4
- data/test/fixtures/treasures.yml +0 -10
- data/test/fixtures/vertices.yml +0 -4
- data/test/fixtures/warehouse-things.yml +0 -3
- data/test/fixtures/zines.yml +0 -5
- data/test/migrations/broken/100_migration_that_raises_exception.rb +0 -10
- data/test/migrations/decimal/1_give_me_big_numbers.rb +0 -15
- data/test/migrations/duplicate/1_people_have_last_names.rb +0 -9
- data/test/migrations/duplicate/2_we_need_reminders.rb +0 -12
- data/test/migrations/duplicate/3_foo.rb +0 -7
- data/test/migrations/duplicate/3_innocent_jointable.rb +0 -12
- data/test/migrations/duplicate_names/20080507052938_chunky.rb +0 -7
- data/test/migrations/duplicate_names/20080507053028_chunky.rb +0 -7
- data/test/migrations/interleaved/pass_1/3_innocent_jointable.rb +0 -12
- data/test/migrations/interleaved/pass_2/1_people_have_last_names.rb +0 -9
- data/test/migrations/interleaved/pass_2/3_innocent_jointable.rb +0 -12
- data/test/migrations/interleaved/pass_3/1_people_have_last_names.rb +0 -9
- data/test/migrations/interleaved/pass_3/2_i_raise_on_down.rb +0 -8
- data/test/migrations/interleaved/pass_3/3_innocent_jointable.rb +0 -12
- data/test/migrations/missing/1000_people_have_middle_names.rb +0 -9
- data/test/migrations/missing/1_people_have_last_names.rb +0 -9
- data/test/migrations/missing/3_we_need_reminders.rb +0 -12
- data/test/migrations/missing/4_innocent_jointable.rb +0 -12
- data/test/migrations/valid/1_people_have_last_names.rb +0 -9
- data/test/migrations/valid/2_we_need_reminders.rb +0 -12
- data/test/migrations/valid/3_innocent_jointable.rb +0 -12
- data/test/models/author.rb +0 -151
- data/test/models/auto_id.rb +0 -4
- data/test/models/binary.rb +0 -2
- data/test/models/bird.rb +0 -9
- data/test/models/book.rb +0 -4
- data/test/models/categorization.rb +0 -5
- data/test/models/category.rb +0 -34
- data/test/models/citation.rb +0 -6
- data/test/models/club.rb +0 -13
- data/test/models/column_name.rb +0 -3
- data/test/models/comment.rb +0 -29
- data/test/models/company.rb +0 -173
- data/test/models/company_in_module.rb +0 -78
- data/test/models/computer.rb +0 -3
- data/test/models/contact.rb +0 -16
- data/test/models/contract.rb +0 -5
- data/test/models/course.rb +0 -3
- data/test/models/customer.rb +0 -73
- data/test/models/default.rb +0 -2
- data/test/models/developer.rb +0 -101
- data/test/models/edge.rb +0 -5
- data/test/models/entrant.rb +0 -3
- data/test/models/essay.rb +0 -3
- data/test/models/event.rb +0 -3
- data/test/models/event_author.rb +0 -8
- data/test/models/face.rb +0 -7
- data/test/models/guid.rb +0 -2
- data/test/models/interest.rb +0 -5
- data/test/models/invoice.rb +0 -4
- data/test/models/item.rb +0 -7
- data/test/models/job.rb +0 -5
- data/test/models/joke.rb +0 -3
- data/test/models/keyboard.rb +0 -3
- data/test/models/legacy_thing.rb +0 -3
- data/test/models/line_item.rb +0 -3
- data/test/models/man.rb +0 -9
- data/test/models/matey.rb +0 -4
- data/test/models/member.rb +0 -12
- data/test/models/member_detail.rb +0 -5
- data/test/models/member_type.rb +0 -3
- data/test/models/membership.rb +0 -9
- data/test/models/minimalistic.rb +0 -2
- data/test/models/mixed_case_monkey.rb +0 -3
- data/test/models/movie.rb +0 -5
- data/test/models/order.rb +0 -4
- data/test/models/organization.rb +0 -6
- data/test/models/owner.rb +0 -5
- data/test/models/parrot.rb +0 -22
- data/test/models/person.rb +0 -16
- data/test/models/pet.rb +0 -5
- data/test/models/pirate.rb +0 -80
- data/test/models/polymorphic_design.rb +0 -3
- data/test/models/polymorphic_price.rb +0 -3
- data/test/models/post.rb +0 -102
- data/test/models/price_estimate.rb +0 -3
- data/test/models/project.rb +0 -30
- data/test/models/reader.rb +0 -4
- data/test/models/reference.rb +0 -4
- data/test/models/reply.rb +0 -46
- data/test/models/ship.rb +0 -19
- data/test/models/ship_part.rb +0 -7
- data/test/models/sponsor.rb +0 -4
- data/test/models/subject.rb +0 -4
- data/test/models/subscriber.rb +0 -8
- data/test/models/subscription.rb +0 -4
- data/test/models/tag.rb +0 -7
- data/test/models/tagging.rb +0 -10
- data/test/models/task.rb +0 -3
- data/test/models/tee.rb +0 -4
- data/test/models/tie.rb +0 -4
- data/test/models/topic.rb +0 -80
- data/test/models/toy.rb +0 -6
- data/test/models/treasure.rb +0 -8
- data/test/models/vertex.rb +0 -9
- data/test/models/warehouse_thing.rb +0 -5
- data/test/models/zine.rb +0 -3
- data/test/schema/mysql_specific_schema.rb +0 -31
- data/test/schema/postgresql_specific_schema.rb +0 -114
- data/test/schema/schema.rb +0 -550
- data/test/schema/schema2.rb +0 -6
- data/test/schema/sqlite_specific_schema.rb +0 -25
@@ -0,0 +1,26 @@
|
|
1
|
+
require 'active_support/concern'
|
2
|
+
require 'active_support/core_ext/class/attribute'
|
3
|
+
|
4
|
+
module ActiveRecord
|
5
|
+
module ReadonlyAttributes
|
6
|
+
extend ActiveSupport::Concern
|
7
|
+
|
8
|
+
included do
|
9
|
+
class_attribute :_attr_readonly, :instance_writer => false
|
10
|
+
self._attr_readonly = []
|
11
|
+
end
|
12
|
+
|
13
|
+
module ClassMethods
|
14
|
+
# Attributes listed as readonly will be used to create a new record but update operations will
|
15
|
+
# ignore these fields.
|
16
|
+
def attr_readonly(*attributes)
|
17
|
+
self._attr_readonly = Set.new(attributes.map { |a| a.to_s }) + (self._attr_readonly || [])
|
18
|
+
end
|
19
|
+
|
20
|
+
# Returns an array of all the attributes that have been specified as readonly.
|
21
|
+
def readonly_attributes
|
22
|
+
self._attr_readonly
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -1,14 +1,24 @@
|
|
1
|
+
require 'active_support/core_ext/class/attribute'
|
2
|
+
require 'active_support/core_ext/object/inclusion'
|
3
|
+
|
1
4
|
module ActiveRecord
|
5
|
+
# = Active Record Reflection
|
2
6
|
module Reflection # :nodoc:
|
3
|
-
|
4
|
-
|
7
|
+
extend ActiveSupport::Concern
|
8
|
+
|
9
|
+
included do
|
10
|
+
class_attribute :reflections
|
11
|
+
self.reflections = {}
|
5
12
|
end
|
6
13
|
|
7
|
-
# Reflection
|
8
|
-
#
|
9
|
-
#
|
14
|
+
# Reflection enables to interrogate Active Record classes and objects
|
15
|
+
# about their associations and aggregations. This information can,
|
16
|
+
# for example, be used in a form builder that takes an Active Record object
|
17
|
+
# and creates input fields for all of the attributes depending on their type
|
18
|
+
# and displays the associations to other objects.
|
10
19
|
#
|
11
|
-
#
|
20
|
+
# MacroReflection class has info for AggregateReflection and AssociationReflection
|
21
|
+
# classes.
|
12
22
|
module ClassMethods
|
13
23
|
def create_reflection(macro, name, options, active_record)
|
14
24
|
case macro
|
@@ -18,48 +28,42 @@ module ActiveRecord
|
|
18
28
|
when :composed_of
|
19
29
|
reflection = AggregateReflection.new(macro, name, options, active_record)
|
20
30
|
end
|
21
|
-
write_inheritable_hiwa :reflections, name => reflection
|
22
|
-
reflection
|
23
|
-
end
|
24
31
|
|
25
|
-
|
26
|
-
|
27
|
-
#
|
28
|
-
# Invoice.reflections
|
29
|
-
# Account.reflections
|
30
|
-
#
|
31
|
-
def reflections
|
32
|
-
read_inheritable_attribute(:reflections) || write_inheritable_attribute(:reflections, {})
|
32
|
+
self.reflections = self.reflections.merge(name => reflection)
|
33
|
+
reflection
|
33
34
|
end
|
34
35
|
|
35
36
|
# Returns an array of AggregateReflection objects for all the aggregations in the class.
|
36
37
|
def reflect_on_all_aggregations
|
37
|
-
reflections.values.
|
38
|
+
reflections.values.grep(AggregateReflection)
|
38
39
|
end
|
39
40
|
|
40
|
-
# Returns the AggregateReflection object for the named +aggregation+ (use the symbol).
|
41
|
+
# Returns the AggregateReflection object for the named +aggregation+ (use the symbol).
|
41
42
|
#
|
42
|
-
# Account.reflect_on_aggregation(:balance) #
|
43
|
+
# Account.reflect_on_aggregation(:balance) # => the balance AggregateReflection
|
43
44
|
#
|
44
45
|
def reflect_on_aggregation(aggregation)
|
45
46
|
reflections[aggregation].is_a?(AggregateReflection) ? reflections[aggregation] : nil
|
46
47
|
end
|
47
48
|
|
48
|
-
# Returns an array of AssociationReflection objects for all the
|
49
|
-
#
|
49
|
+
# Returns an array of AssociationReflection objects for all the
|
50
|
+
# associations in the class. If you only want to reflect on a certain
|
51
|
+
# association type, pass in the symbol (<tt>:has_many</tt>, <tt>:has_one</tt>,
|
52
|
+
# <tt>:belongs_to</tt>) as the first parameter.
|
53
|
+
#
|
50
54
|
# Example:
|
51
55
|
#
|
52
56
|
# Account.reflect_on_all_associations # returns an array of all associations
|
53
57
|
# Account.reflect_on_all_associations(:has_many) # returns an array of all has_many associations
|
54
58
|
#
|
55
59
|
def reflect_on_all_associations(macro = nil)
|
56
|
-
association_reflections = reflections.values.
|
60
|
+
association_reflections = reflections.values.grep(AssociationReflection)
|
57
61
|
macro ? association_reflections.select { |reflection| reflection.macro == macro } : association_reflections
|
58
62
|
end
|
59
63
|
|
60
|
-
# Returns the AssociationReflection object for the
|
64
|
+
# Returns the AssociationReflection object for the +association+ (use the symbol).
|
61
65
|
#
|
62
|
-
# Account.reflect_on_association(:owner)
|
66
|
+
# Account.reflect_on_association(:owner) # returns the owner AssociationReflection
|
63
67
|
# Invoice.reflect_on_association(:line_items).macro # returns :has_many
|
64
68
|
#
|
65
69
|
def reflect_on_association(association)
|
@@ -73,60 +77,70 @@ module ActiveRecord
|
|
73
77
|
end
|
74
78
|
|
75
79
|
|
76
|
-
# Abstract base class for AggregateReflection and AssociationReflection
|
77
|
-
#
|
80
|
+
# Abstract base class for AggregateReflection and AssociationReflection. Objects of
|
81
|
+
# AggregateReflection and AssociationReflection are returned by the Reflection::ClassMethods.
|
78
82
|
class MacroReflection
|
79
|
-
|
83
|
+
# Returns the name of the macro.
|
84
|
+
#
|
85
|
+
# <tt>composed_of :balance, :class_name => 'Money'</tt> returns <tt>:balance</tt>
|
86
|
+
# <tt>has_many :clients</tt> returns <tt>:clients</tt>
|
87
|
+
attr_reader :name
|
80
88
|
|
81
|
-
|
82
|
-
|
83
|
-
|
89
|
+
# Returns the macro type.
|
90
|
+
#
|
91
|
+
# <tt>composed_of :balance, :class_name => 'Money'</tt> returns <tt>:composed_of</tt>
|
92
|
+
# <tt>has_many :clients</tt> returns <tt>:has_many</tt>
|
93
|
+
attr_reader :macro
|
84
94
|
|
85
|
-
# Returns the
|
86
|
-
#
|
87
|
-
|
88
|
-
|
89
|
-
|
95
|
+
# Returns the hash of options used for the macro.
|
96
|
+
#
|
97
|
+
# <tt>composed_of :balance, :class_name => 'Money'</tt> returns <tt>{ :class_name => "Money" }</tt>
|
98
|
+
# <tt>has_many :clients</tt> returns +{}+
|
99
|
+
attr_reader :options
|
90
100
|
|
91
|
-
|
92
|
-
# or for <tt>has_many :clients</tt> will return <tt>:has_many</tt>.
|
93
|
-
def macro
|
94
|
-
@macro
|
95
|
-
end
|
101
|
+
attr_reader :active_record
|
96
102
|
|
97
|
-
|
98
|
-
|
99
|
-
def options
|
100
|
-
@
|
103
|
+
attr_reader :plural_name # :nodoc:
|
104
|
+
|
105
|
+
def initialize(macro, name, options, active_record)
|
106
|
+
@macro = macro
|
107
|
+
@name = name
|
108
|
+
@options = options
|
109
|
+
@active_record = active_record
|
110
|
+
@plural_name = active_record.pluralize_table_names ?
|
111
|
+
name.to_s.pluralize : name.to_s
|
101
112
|
end
|
102
113
|
|
103
|
-
# Returns the class for the macro.
|
104
|
-
#
|
114
|
+
# Returns the class for the macro.
|
115
|
+
#
|
116
|
+
# <tt>composed_of :balance, :class_name => 'Money'</tt> returns the Money class
|
117
|
+
# <tt>has_many :clients</tt> returns the Client class
|
105
118
|
def klass
|
106
119
|
@klass ||= class_name.constantize
|
107
120
|
end
|
108
121
|
|
109
|
-
# Returns the class name for the macro.
|
110
|
-
#
|
122
|
+
# Returns the class name for the macro.
|
123
|
+
#
|
124
|
+
# <tt>composed_of :balance, :class_name => 'Money'</tt> returns <tt>'Money'</tt>
|
125
|
+
# <tt>has_many :clients</tt> returns <tt>'Client'</tt>
|
111
126
|
def class_name
|
112
|
-
@class_name ||= options[:class_name] || derive_class_name
|
127
|
+
@class_name ||= (options[:class_name] || derive_class_name).to_s
|
113
128
|
end
|
114
129
|
|
115
130
|
# Returns +true+ if +self+ and +other_aggregation+ have the same +name+ attribute, +active_record+ attribute,
|
116
131
|
# and +other_aggregation+ has an options hash assigned to it.
|
117
132
|
def ==(other_aggregation)
|
118
|
-
|
133
|
+
super ||
|
134
|
+
other_aggregation.kind_of?(self.class) &&
|
135
|
+
name == other_aggregation.name &&
|
136
|
+
other_aggregation.options &&
|
137
|
+
active_record == other_aggregation.active_record
|
119
138
|
end
|
120
139
|
|
121
140
|
def sanitized_conditions #:nodoc:
|
122
141
|
@sanitized_conditions ||= klass.send(:sanitize_sql, options[:conditions]) if options[:conditions]
|
123
142
|
end
|
124
143
|
|
125
|
-
# Returns +true+ if +self+ is a +belongs_to+ reflection.
|
126
|
-
def belongs_to?
|
127
|
-
macro == :belongs_to
|
128
|
-
end
|
129
|
-
|
130
144
|
private
|
131
145
|
def derive_class_name
|
132
146
|
name.to_s.camelize
|
@@ -134,13 +148,15 @@ module ActiveRecord
|
|
134
148
|
end
|
135
149
|
|
136
150
|
|
137
|
-
# Holds all the meta-data about an aggregation as it was specified in the
|
151
|
+
# Holds all the meta-data about an aggregation as it was specified in the
|
152
|
+
# Active Record class.
|
138
153
|
class AggregateReflection < MacroReflection #:nodoc:
|
139
154
|
end
|
140
155
|
|
141
|
-
# Holds all the meta-data about an association as it was specified in the
|
156
|
+
# Holds all the meta-data about an association as it was specified in the
|
157
|
+
# Active Record class.
|
142
158
|
class AssociationReflection < MacroReflection #:nodoc:
|
143
|
-
# Returns the target association's class
|
159
|
+
# Returns the target association's class.
|
144
160
|
#
|
145
161
|
# class Author < ActiveRecord::Base
|
146
162
|
# has_many :books
|
@@ -149,34 +165,22 @@ module ActiveRecord
|
|
149
165
|
# Author.reflect_on_association(:books).klass
|
150
166
|
# # => Book
|
151
167
|
#
|
152
|
-
# <b>Note:</b>
|
168
|
+
# <b>Note:</b> Do not call +klass.new+ or +klass.create+ to instantiate
|
153
169
|
# a new association object. Use +build_association+ or +create_association+
|
154
170
|
# instead. This allows plugins to hook into association object creation.
|
155
171
|
def klass
|
156
172
|
@klass ||= active_record.send(:compute_type, class_name)
|
157
173
|
end
|
158
174
|
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
klass.new(*options)
|
163
|
-
end
|
164
|
-
|
165
|
-
# Creates a new instance of the associated class, and immediates saves it
|
166
|
-
# with ActiveRecord::Base#save. +options+ will be passed to the class's
|
167
|
-
# creation method. Returns the newly created object.
|
168
|
-
def create_association(*options)
|
169
|
-
klass.create(*options)
|
175
|
+
def initialize(macro, name, options, active_record)
|
176
|
+
super
|
177
|
+
@collection = macro.in?([:has_many, :has_and_belongs_to_many])
|
170
178
|
end
|
171
179
|
|
172
|
-
#
|
173
|
-
#
|
174
|
-
|
175
|
-
|
176
|
-
#
|
177
|
-
# Returns the newly created object.
|
178
|
-
def create_association!(*options)
|
179
|
-
klass.create!(*options)
|
180
|
+
# Returns a new, unsaved instance of the associated class. +options+ will
|
181
|
+
# be passed to the class's constructor.
|
182
|
+
def build_association(*options, &block)
|
183
|
+
klass.new(*options, &block)
|
180
184
|
end
|
181
185
|
|
182
186
|
def table_name
|
@@ -187,19 +191,40 @@ module ActiveRecord
|
|
187
191
|
@quoted_table_name ||= klass.quoted_table_name
|
188
192
|
end
|
189
193
|
|
190
|
-
def
|
191
|
-
@
|
194
|
+
def foreign_key
|
195
|
+
@foreign_key ||= options[:foreign_key] || derive_foreign_key
|
196
|
+
end
|
197
|
+
|
198
|
+
def foreign_type
|
199
|
+
@foreign_type ||= options[:foreign_type] || "#{name}_type"
|
200
|
+
end
|
201
|
+
|
202
|
+
def type
|
203
|
+
@type ||= options[:as] && "#{options[:as]}_type"
|
204
|
+
end
|
205
|
+
|
206
|
+
def primary_key_column
|
207
|
+
@primary_key_column ||= klass.columns.find { |c| c.name == klass.primary_key }
|
192
208
|
end
|
193
209
|
|
194
210
|
def association_foreign_key
|
195
|
-
@association_foreign_key ||=
|
211
|
+
@association_foreign_key ||= options[:association_foreign_key] || class_name.foreign_key
|
212
|
+
end
|
213
|
+
|
214
|
+
# klass option is necessary to support loading polymorphic associations
|
215
|
+
def association_primary_key(klass = nil)
|
216
|
+
options[:primary_key] || primary_key(klass || self.klass)
|
217
|
+
end
|
218
|
+
|
219
|
+
def active_record_primary_key
|
220
|
+
@active_record_primary_key ||= options[:primary_key] || primary_key(active_record)
|
196
221
|
end
|
197
222
|
|
198
223
|
def counter_cache_column
|
199
224
|
if options[:counter_cache] == true
|
200
225
|
"#{active_record.name.demodulize.underscore.pluralize}_count"
|
201
226
|
elsif options[:counter_cache]
|
202
|
-
options[:counter_cache]
|
227
|
+
options[:counter_cache].to_s
|
203
228
|
end
|
204
229
|
end
|
205
230
|
|
@@ -224,18 +249,34 @@ module ActiveRecord
|
|
224
249
|
end
|
225
250
|
|
226
251
|
def through_reflection
|
227
|
-
|
228
|
-
end
|
229
|
-
|
230
|
-
def through_reflection_primary_key_name
|
252
|
+
nil
|
231
253
|
end
|
232
254
|
|
233
255
|
def source_reflection
|
234
256
|
nil
|
235
257
|
end
|
236
258
|
|
259
|
+
# A chain of reflections from this one back to the owner. For more see the explanation in
|
260
|
+
# ThroughReflection.
|
261
|
+
def chain
|
262
|
+
[self]
|
263
|
+
end
|
264
|
+
|
265
|
+
def nested?
|
266
|
+
false
|
267
|
+
end
|
268
|
+
|
269
|
+
# An array of arrays of conditions. Each item in the outside array corresponds to a reflection
|
270
|
+
# in the #chain. The inside arrays are simply conditions (and each condition may itself be
|
271
|
+
# a hash, array, arel predicate, etc...)
|
272
|
+
def conditions
|
273
|
+
[[options[:conditions]].compact]
|
274
|
+
end
|
275
|
+
|
276
|
+
alias :source_macro :macro
|
277
|
+
|
237
278
|
def has_inverse?
|
238
|
-
|
279
|
+
@options[:inverse_of]
|
239
280
|
end
|
240
281
|
|
241
282
|
def inverse_of
|
@@ -255,37 +296,53 @@ module ActiveRecord
|
|
255
296
|
end
|
256
297
|
|
257
298
|
# Returns whether or not this association reflection is for a collection
|
258
|
-
# association. Returns +true+ if the +macro+ is
|
299
|
+
# association. Returns +true+ if the +macro+ is either +has_many+ or
|
259
300
|
# +has_and_belongs_to_many+, +false+ otherwise.
|
260
301
|
def collection?
|
261
|
-
if @collection.nil?
|
262
|
-
@collection = [:has_many, :has_and_belongs_to_many].include?(macro)
|
263
|
-
end
|
264
302
|
@collection
|
265
303
|
end
|
266
304
|
|
267
305
|
# Returns whether or not the association should be validated as part of
|
268
306
|
# the parent's validation.
|
269
307
|
#
|
270
|
-
# Unless you
|
271
|
-
# <tt>:validate => false</tt>,
|
308
|
+
# Unless you explicitly disable validation with
|
309
|
+
# <tt>:validate => false</tt>, validation will take place when:
|
272
310
|
#
|
273
|
-
# * you
|
311
|
+
# * you explicitly enable validation; <tt>:validate => true</tt>
|
274
312
|
# * you use autosave; <tt>:autosave => true</tt>
|
275
313
|
# * the association is a +has_many+ association
|
276
314
|
def validate?
|
277
315
|
!options[:validate].nil? ? options[:validate] : (options[:autosave] == true || macro == :has_many)
|
278
316
|
end
|
279
317
|
|
280
|
-
|
281
|
-
|
282
|
-
|
283
|
-
|
284
|
-
|
285
|
-
|
286
|
-
|
287
|
-
|
288
|
-
|
318
|
+
# Returns +true+ if +self+ is a +belongs_to+ reflection.
|
319
|
+
def belongs_to?
|
320
|
+
macro == :belongs_to
|
321
|
+
end
|
322
|
+
|
323
|
+
def association_class
|
324
|
+
case macro
|
325
|
+
when :belongs_to
|
326
|
+
if options[:polymorphic]
|
327
|
+
Associations::BelongsToPolymorphicAssociation
|
328
|
+
else
|
329
|
+
Associations::BelongsToAssociation
|
330
|
+
end
|
331
|
+
when :has_and_belongs_to_many
|
332
|
+
Associations::HasAndBelongsToManyAssociation
|
333
|
+
when :has_many
|
334
|
+
if options[:through]
|
335
|
+
Associations::HasManyThroughAssociation
|
336
|
+
else
|
337
|
+
Associations::HasManyAssociation
|
338
|
+
end
|
339
|
+
when :has_one
|
340
|
+
if options[:through]
|
341
|
+
Associations::HasOneThroughAssociation
|
342
|
+
else
|
343
|
+
Associations::HasOneAssociation
|
344
|
+
end
|
345
|
+
end
|
289
346
|
end
|
290
347
|
|
291
348
|
private
|
@@ -295,7 +352,7 @@ module ActiveRecord
|
|
295
352
|
class_name
|
296
353
|
end
|
297
354
|
|
298
|
-
def
|
355
|
+
def derive_foreign_key
|
299
356
|
if belongs_to?
|
300
357
|
"#{name}_id"
|
301
358
|
elsif options[:as]
|
@@ -304,12 +361,20 @@ module ActiveRecord
|
|
304
361
|
active_record.name.foreign_key
|
305
362
|
end
|
306
363
|
end
|
364
|
+
|
365
|
+
def primary_key(klass)
|
366
|
+
klass.primary_key || raise(UnknownPrimaryKey.new(klass))
|
367
|
+
end
|
307
368
|
end
|
308
369
|
|
309
|
-
# Holds all the meta-data about a :through association as it was specified
|
370
|
+
# Holds all the meta-data about a :through association as it was specified
|
371
|
+
# in the Active Record class.
|
310
372
|
class ThroughReflection < AssociationReflection #:nodoc:
|
311
|
-
|
312
|
-
|
373
|
+
delegate :foreign_key, :foreign_type, :association_foreign_key,
|
374
|
+
:active_record_primary_key, :type, :to => :source_reflection
|
375
|
+
|
376
|
+
# Gets the source of the through reflection. It checks both a singularized
|
377
|
+
# and pluralized form for <tt>:belongs_to</tt> or <tt>:has_many</tt>.
|
313
378
|
#
|
314
379
|
# class Post < ActiveRecord::Base
|
315
380
|
# has_many :taggings
|
@@ -321,7 +386,7 @@ module ActiveRecord
|
|
321
386
|
end
|
322
387
|
|
323
388
|
# Returns the AssociationReflection object specified in the <tt>:through</tt> option
|
324
|
-
# of a HasManyThrough or HasOneThrough association.
|
389
|
+
# of a HasManyThrough or HasOneThrough association.
|
325
390
|
#
|
326
391
|
# class Post < ActiveRecord::Base
|
327
392
|
# has_many :taggings
|
@@ -335,6 +400,86 @@ module ActiveRecord
|
|
335
400
|
@through_reflection ||= active_record.reflect_on_association(options[:through])
|
336
401
|
end
|
337
402
|
|
403
|
+
# Returns an array of reflections which are involved in this association. Each item in the
|
404
|
+
# array corresponds to a table which will be part of the query for this association.
|
405
|
+
#
|
406
|
+
# The chain is built by recursively calling #chain on the source reflection and the through
|
407
|
+
# reflection. The base case for the recursion is a normal association, which just returns
|
408
|
+
# [self] as its #chain.
|
409
|
+
def chain
|
410
|
+
@chain ||= begin
|
411
|
+
chain = source_reflection.chain + through_reflection.chain
|
412
|
+
chain[0] = self # Use self so we don't lose the information from :source_type
|
413
|
+
chain
|
414
|
+
end
|
415
|
+
end
|
416
|
+
|
417
|
+
# Consider the following example:
|
418
|
+
#
|
419
|
+
# class Person
|
420
|
+
# has_many :articles
|
421
|
+
# has_many :comment_tags, :through => :articles
|
422
|
+
# end
|
423
|
+
#
|
424
|
+
# class Article
|
425
|
+
# has_many :comments
|
426
|
+
# has_many :comment_tags, :through => :comments, :source => :tags
|
427
|
+
# end
|
428
|
+
#
|
429
|
+
# class Comment
|
430
|
+
# has_many :tags
|
431
|
+
# end
|
432
|
+
#
|
433
|
+
# There may be conditions on Person.comment_tags, Article.comment_tags and/or Comment.tags,
|
434
|
+
# but only Comment.tags will be represented in the #chain. So this method creates an array
|
435
|
+
# of conditions corresponding to the chain. Each item in the #conditions array corresponds
|
436
|
+
# to an item in the #chain, and is itself an array of conditions from an arbitrary number
|
437
|
+
# of relevant reflections, plus any :source_type or polymorphic :as constraints.
|
438
|
+
def conditions
|
439
|
+
@conditions ||= begin
|
440
|
+
conditions = source_reflection.conditions.map { |c| c.dup }
|
441
|
+
|
442
|
+
# Add to it the conditions from this reflection if necessary.
|
443
|
+
conditions.first << options[:conditions] if options[:conditions]
|
444
|
+
|
445
|
+
through_conditions = through_reflection.conditions
|
446
|
+
|
447
|
+
if options[:source_type]
|
448
|
+
through_conditions.first << { foreign_type => options[:source_type] }
|
449
|
+
end
|
450
|
+
|
451
|
+
# Recursively fill out the rest of the array from the through reflection
|
452
|
+
conditions += through_conditions
|
453
|
+
|
454
|
+
# And return
|
455
|
+
conditions
|
456
|
+
end
|
457
|
+
end
|
458
|
+
|
459
|
+
# The macro used by the source association
|
460
|
+
def source_macro
|
461
|
+
source_reflection.source_macro
|
462
|
+
end
|
463
|
+
|
464
|
+
# A through association is nested if there would be more than one join table
|
465
|
+
def nested?
|
466
|
+
chain.length > 2 || through_reflection.macro == :has_and_belongs_to_many
|
467
|
+
end
|
468
|
+
|
469
|
+
# We want to use the klass from this reflection, rather than just delegate straight to
|
470
|
+
# the source_reflection, because the source_reflection may be polymorphic. We still
|
471
|
+
# need to respect the source_reflection's :primary_key option, though.
|
472
|
+
def association_primary_key(klass = nil)
|
473
|
+
# Get the "actual" source reflection if the immediate source reflection has a
|
474
|
+
# source reflection itself
|
475
|
+
source_reflection = self.source_reflection
|
476
|
+
while source_reflection.source_reflection
|
477
|
+
source_reflection = source_reflection.source_reflection
|
478
|
+
end
|
479
|
+
|
480
|
+
source_reflection.options[:primary_key] || primary_key(klass || self.klass)
|
481
|
+
end
|
482
|
+
|
338
483
|
# Gets an array of possible <tt>:through</tt> source reflection names:
|
339
484
|
#
|
340
485
|
# [:singularized, :pluralized]
|
@@ -343,11 +488,23 @@ module ActiveRecord
|
|
343
488
|
@source_reflection_names ||= (options[:source] ? [options[:source]] : [name.to_s.singularize, name]).collect { |n| n.to_sym }
|
344
489
|
end
|
345
490
|
|
491
|
+
def source_options
|
492
|
+
source_reflection.options
|
493
|
+
end
|
494
|
+
|
495
|
+
def through_options
|
496
|
+
through_reflection.options
|
497
|
+
end
|
498
|
+
|
346
499
|
def check_validity!
|
347
500
|
if through_reflection.nil?
|
348
501
|
raise HasManyThroughAssociationNotFoundError.new(active_record.name, self)
|
349
502
|
end
|
350
503
|
|
504
|
+
if through_reflection.options[:polymorphic]
|
505
|
+
raise HasManyThroughAssociationPolymorphicThroughError.new(active_record.name, self)
|
506
|
+
end
|
507
|
+
|
351
508
|
if source_reflection.nil?
|
352
509
|
raise HasManyThroughSourceAssociationNotFoundError.new(self)
|
353
510
|
end
|
@@ -357,24 +514,16 @@ module ActiveRecord
|
|
357
514
|
end
|
358
515
|
|
359
516
|
if source_reflection.options[:polymorphic] && options[:source_type].nil?
|
360
|
-
raise
|
517
|
+
raise HasManyThroughAssociationPolymorphicSourceError.new(active_record.name, self, source_reflection)
|
361
518
|
end
|
362
519
|
|
363
|
-
|
364
|
-
raise
|
520
|
+
if macro == :has_one && through_reflection.collection?
|
521
|
+
raise HasOneThroughCantAssociateThroughCollection.new(active_record.name, self, through_reflection)
|
365
522
|
end
|
366
523
|
|
367
524
|
check_validity_of_inverse!
|
368
525
|
end
|
369
526
|
|
370
|
-
def through_reflection_primary_key
|
371
|
-
through_reflection.belongs_to? ? through_reflection.klass.primary_key : through_reflection.primary_key_name
|
372
|
-
end
|
373
|
-
|
374
|
-
def through_reflection_primary_key_name
|
375
|
-
through_reflection.primary_key_name if through_reflection.belongs_to?
|
376
|
-
end
|
377
|
-
|
378
527
|
private
|
379
528
|
def derive_class_name
|
380
529
|
# get the class_name of the belongs_to association of the through reflection
|