activerecord 6.1.7 → 7.2.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +616 -1290
- data/MIT-LICENSE +1 -1
- data/README.rdoc +31 -31
- data/examples/performance.rb +2 -2
- data/lib/active_record/aggregations.rb +17 -14
- data/lib/active_record/association_relation.rb +2 -12
- data/lib/active_record/associations/alias_tracker.rb +25 -19
- data/lib/active_record/associations/association.rb +60 -21
- data/lib/active_record/associations/association_scope.rb +17 -12
- data/lib/active_record/associations/belongs_to_association.rb +37 -11
- data/lib/active_record/associations/belongs_to_polymorphic_association.rb +13 -4
- data/lib/active_record/associations/builder/association.rb +11 -5
- data/lib/active_record/associations/builder/belongs_to.rb +41 -14
- data/lib/active_record/associations/builder/collection_association.rb +10 -3
- data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +3 -7
- data/lib/active_record/associations/builder/has_many.rb +4 -4
- data/lib/active_record/associations/builder/has_one.rb +4 -4
- data/lib/active_record/associations/builder/singular_association.rb +6 -2
- data/lib/active_record/associations/collection_association.rb +46 -36
- data/lib/active_record/associations/collection_proxy.rb +44 -16
- data/lib/active_record/associations/disable_joins_association_scope.rb +59 -0
- data/lib/active_record/associations/errors.rb +265 -0
- data/lib/active_record/associations/foreign_association.rb +10 -3
- data/lib/active_record/associations/has_many_association.rb +29 -19
- data/lib/active_record/associations/has_many_through_association.rb +19 -8
- data/lib/active_record/associations/has_one_association.rb +20 -10
- data/lib/active_record/associations/has_one_through_association.rb +1 -1
- data/lib/active_record/associations/join_dependency/join_association.rb +30 -27
- data/lib/active_record/associations/join_dependency.rb +28 -20
- data/lib/active_record/associations/nested_error.rb +47 -0
- data/lib/active_record/associations/preloader/association.rb +212 -53
- data/lib/active_record/associations/preloader/batch.rb +48 -0
- data/lib/active_record/associations/preloader/branch.rb +153 -0
- data/lib/active_record/associations/preloader/through_association.rb +50 -16
- data/lib/active_record/associations/preloader.rb +50 -121
- data/lib/active_record/associations/singular_association.rb +15 -3
- data/lib/active_record/associations/through_association.rb +25 -14
- data/lib/active_record/associations.rb +429 -522
- data/lib/active_record/asynchronous_queries_tracker.rb +60 -0
- data/lib/active_record/attribute_assignment.rb +1 -5
- data/lib/active_record/attribute_methods/before_type_cast.rb +24 -2
- data/lib/active_record/attribute_methods/composite_primary_key.rb +84 -0
- data/lib/active_record/attribute_methods/dirty.rb +73 -22
- data/lib/active_record/attribute_methods/primary_key.rb +47 -27
- data/lib/active_record/attribute_methods/query.rb +31 -19
- data/lib/active_record/attribute_methods/read.rb +14 -11
- data/lib/active_record/attribute_methods/serialization.rb +174 -37
- data/lib/active_record/attribute_methods/time_zone_conversion.rb +15 -9
- data/lib/active_record/attribute_methods/write.rb +12 -15
- data/lib/active_record/attribute_methods.rb +164 -52
- data/lib/active_record/attributes.rb +57 -54
- data/lib/active_record/autosave_association.rb +74 -57
- data/lib/active_record/base.rb +27 -5
- data/lib/active_record/callbacks.rb +19 -35
- data/lib/active_record/coders/column_serializer.rb +61 -0
- data/lib/active_record/coders/json.rb +1 -1
- data/lib/active_record/coders/yaml_column.rb +70 -46
- data/lib/active_record/connection_adapters/abstract/connection_handler.rb +284 -0
- data/lib/active_record/connection_adapters/abstract/connection_pool/queue.rb +211 -0
- data/lib/active_record/connection_adapters/abstract/connection_pool/reaper.rb +79 -0
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +325 -604
- data/lib/active_record/connection_adapters/abstract/database_limits.rb +5 -17
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +199 -60
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +230 -64
- data/lib/active_record/connection_adapters/abstract/quoting.rb +119 -131
- data/lib/active_record/connection_adapters/abstract/savepoints.rb +4 -3
- data/lib/active_record/connection_adapters/abstract/schema_creation.rb +21 -20
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +186 -31
- data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +14 -1
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +378 -143
- data/lib/active_record/connection_adapters/abstract/transaction.rb +361 -76
- data/lib/active_record/connection_adapters/abstract_adapter.rb +624 -163
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +348 -165
- data/lib/active_record/connection_adapters/column.rb +13 -0
- data/lib/active_record/connection_adapters/mysql/column.rb +1 -0
- data/lib/active_record/connection_adapters/mysql/database_statements.rb +29 -130
- data/lib/active_record/connection_adapters/mysql/quoting.rb +81 -55
- data/lib/active_record/connection_adapters/mysql/schema_creation.rb +9 -0
- data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +10 -1
- data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +8 -2
- data/lib/active_record/connection_adapters/mysql/schema_statements.rb +45 -14
- data/lib/active_record/connection_adapters/mysql2/database_statements.rb +152 -0
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +107 -68
- data/lib/active_record/connection_adapters/pool_config.rb +26 -16
- data/lib/active_record/connection_adapters/pool_manager.rb +19 -9
- data/lib/active_record/connection_adapters/postgresql/column.rb +30 -1
- data/lib/active_record/connection_adapters/postgresql/database_statements.rb +114 -54
- data/lib/active_record/connection_adapters/postgresql/oid/array.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +6 -0
- data/lib/active_record/connection_adapters/postgresql/oid/date.rb +8 -0
- data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +5 -0
- data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +53 -14
- data/lib/active_record/connection_adapters/postgresql/oid/interval.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/oid/money.rb +3 -2
- data/lib/active_record/connection_adapters/postgresql/oid/range.rb +12 -3
- data/lib/active_record/connection_adapters/postgresql/oid/timestamp.rb +15 -0
- data/lib/active_record/connection_adapters/postgresql/oid/timestamp_with_time_zone.rb +30 -0
- data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +18 -6
- data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +14 -4
- data/lib/active_record/connection_adapters/postgresql/oid.rb +2 -0
- data/lib/active_record/connection_adapters/postgresql/quoting.rb +137 -104
- data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +28 -0
- data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +92 -2
- data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +173 -3
- data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +78 -0
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +403 -77
- data/lib/active_record/connection_adapters/postgresql/utils.rb +9 -10
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +520 -253
- data/lib/active_record/connection_adapters/schema_cache.rb +326 -102
- data/lib/active_record/connection_adapters/sqlite3/column.rb +62 -0
- data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +78 -55
- data/lib/active_record/connection_adapters/sqlite3/quoting.rb +68 -54
- data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +22 -0
- data/lib/active_record/connection_adapters/sqlite3/schema_definitions.rb +20 -0
- data/lib/active_record/connection_adapters/sqlite3/schema_dumper.rb +16 -0
- data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +66 -22
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +372 -130
- data/lib/active_record/connection_adapters/statement_pool.rb +7 -0
- data/lib/active_record/connection_adapters/trilogy/database_statements.rb +99 -0
- data/lib/active_record/connection_adapters/trilogy_adapter.rb +229 -0
- data/lib/active_record/connection_adapters.rb +130 -6
- data/lib/active_record/connection_handling.rb +132 -146
- data/lib/active_record/core.rb +310 -253
- data/lib/active_record/counter_cache.rb +68 -34
- data/lib/active_record/database_configurations/connection_url_resolver.rb +10 -4
- data/lib/active_record/database_configurations/database_config.rb +34 -10
- data/lib/active_record/database_configurations/hash_config.rb +107 -31
- data/lib/active_record/database_configurations/url_config.rb +38 -13
- data/lib/active_record/database_configurations.rb +96 -60
- data/lib/active_record/delegated_type.rb +90 -20
- data/lib/active_record/deprecator.rb +7 -0
- data/lib/active_record/destroy_association_async_job.rb +4 -2
- data/lib/active_record/disable_joins_association_relation.rb +39 -0
- data/lib/active_record/dynamic_matchers.rb +3 -3
- data/lib/active_record/encryption/auto_filtered_parameters.rb +66 -0
- data/lib/active_record/encryption/cipher/aes256_gcm.rb +101 -0
- data/lib/active_record/encryption/cipher.rb +53 -0
- data/lib/active_record/encryption/config.rb +68 -0
- data/lib/active_record/encryption/configurable.rb +60 -0
- data/lib/active_record/encryption/context.rb +42 -0
- data/lib/active_record/encryption/contexts.rb +76 -0
- data/lib/active_record/encryption/derived_secret_key_provider.rb +18 -0
- data/lib/active_record/encryption/deterministic_key_provider.rb +14 -0
- data/lib/active_record/encryption/encryptable_record.rb +230 -0
- data/lib/active_record/encryption/encrypted_attribute_type.rb +175 -0
- data/lib/active_record/encryption/encrypted_fixtures.rb +38 -0
- data/lib/active_record/encryption/encrypting_only_encryptor.rb +12 -0
- data/lib/active_record/encryption/encryptor.rb +170 -0
- data/lib/active_record/encryption/envelope_encryption_key_provider.rb +55 -0
- data/lib/active_record/encryption/errors.rb +15 -0
- data/lib/active_record/encryption/extended_deterministic_queries.rb +157 -0
- data/lib/active_record/encryption/extended_deterministic_uniqueness_validator.rb +28 -0
- data/lib/active_record/encryption/key.rb +28 -0
- data/lib/active_record/encryption/key_generator.rb +53 -0
- data/lib/active_record/encryption/key_provider.rb +46 -0
- data/lib/active_record/encryption/message.rb +33 -0
- data/lib/active_record/encryption/message_pack_message_serializer.rb +76 -0
- data/lib/active_record/encryption/message_serializer.rb +96 -0
- data/lib/active_record/encryption/null_encryptor.rb +25 -0
- data/lib/active_record/encryption/properties.rb +76 -0
- data/lib/active_record/encryption/read_only_null_encryptor.rb +28 -0
- data/lib/active_record/encryption/scheme.rb +100 -0
- data/lib/active_record/encryption.rb +58 -0
- data/lib/active_record/enum.rb +170 -62
- data/lib/active_record/errors.rb +210 -27
- data/lib/active_record/explain.rb +21 -12
- data/lib/active_record/explain_registry.rb +11 -6
- data/lib/active_record/explain_subscriber.rb +1 -1
- data/lib/active_record/fixture_set/file.rb +15 -1
- data/lib/active_record/fixture_set/model_metadata.rb +14 -4
- data/lib/active_record/fixture_set/render_context.rb +2 -0
- data/lib/active_record/fixture_set/table_row.rb +70 -14
- data/lib/active_record/fixture_set/table_rows.rb +4 -4
- data/lib/active_record/fixtures.rb +179 -112
- data/lib/active_record/future_result.rb +178 -0
- data/lib/active_record/gem_version.rb +4 -4
- data/lib/active_record/inheritance.rb +85 -31
- data/lib/active_record/insert_all.rb +148 -32
- data/lib/active_record/integration.rb +14 -10
- data/lib/active_record/internal_metadata.rb +123 -23
- data/lib/active_record/legacy_yaml_adapter.rb +2 -39
- data/lib/active_record/locking/optimistic.rb +43 -27
- data/lib/active_record/locking/pessimistic.rb +15 -6
- data/lib/active_record/log_subscriber.rb +41 -29
- data/lib/active_record/marshalling.rb +59 -0
- data/lib/active_record/message_pack.rb +124 -0
- data/lib/active_record/middleware/database_selector/resolver.rb +10 -10
- data/lib/active_record/middleware/database_selector.rb +23 -13
- data/lib/active_record/middleware/shard_selector.rb +62 -0
- data/lib/active_record/migration/command_recorder.rb +113 -16
- data/lib/active_record/migration/compatibility.rb +235 -46
- data/lib/active_record/migration/default_strategy.rb +22 -0
- data/lib/active_record/migration/execution_strategy.rb +19 -0
- data/lib/active_record/migration/join_table.rb +1 -1
- data/lib/active_record/migration/pending_migration_connection.rb +21 -0
- data/lib/active_record/migration.rb +374 -177
- data/lib/active_record/model_schema.rb +145 -158
- data/lib/active_record/nested_attributes.rb +61 -23
- data/lib/active_record/no_touching.rb +3 -3
- data/lib/active_record/normalization.rb +163 -0
- data/lib/active_record/persistence.rb +282 -283
- data/lib/active_record/promise.rb +84 -0
- data/lib/active_record/query_cache.rb +18 -25
- data/lib/active_record/query_logs.rb +189 -0
- data/lib/active_record/query_logs_formatter.rb +41 -0
- data/lib/active_record/querying.rb +44 -9
- data/lib/active_record/railtie.rb +229 -71
- data/lib/active_record/railties/controller_runtime.rb +25 -11
- data/lib/active_record/railties/databases.rake +189 -256
- data/lib/active_record/railties/job_runtime.rb +23 -0
- data/lib/active_record/readonly_attributes.rb +41 -3
- data/lib/active_record/reflection.rb +332 -103
- data/lib/active_record/relation/batches/batch_enumerator.rb +38 -9
- data/lib/active_record/relation/batches.rb +200 -65
- data/lib/active_record/relation/calculations.rb +301 -112
- data/lib/active_record/relation/delegation.rb +33 -22
- data/lib/active_record/relation/finder_methods.rb +123 -52
- data/lib/active_record/relation/merger.rb +26 -19
- data/lib/active_record/relation/predicate_builder/array_handler.rb +2 -2
- data/lib/active_record/relation/predicate_builder/association_query_value.rb +38 -4
- data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +10 -7
- data/lib/active_record/relation/predicate_builder/relation_handler.rb +5 -1
- data/lib/active_record/relation/predicate_builder.rb +29 -22
- data/lib/active_record/relation/query_attribute.rb +30 -12
- data/lib/active_record/relation/query_methods.rb +870 -163
- data/lib/active_record/relation/record_fetch_warning.rb +10 -9
- data/lib/active_record/relation/spawn_methods.rb +7 -6
- data/lib/active_record/relation/where_clause.rb +15 -36
- data/lib/active_record/relation.rb +736 -145
- data/lib/active_record/result.rb +67 -54
- data/lib/active_record/runtime_registry.rb +71 -13
- data/lib/active_record/sanitization.rb +84 -34
- data/lib/active_record/schema.rb +39 -23
- data/lib/active_record/schema_dumper.rb +90 -31
- data/lib/active_record/schema_migration.rb +74 -23
- data/lib/active_record/scoping/default.rb +72 -15
- data/lib/active_record/scoping/named.rb +6 -13
- data/lib/active_record/scoping.rb +65 -34
- data/lib/active_record/secure_password.rb +60 -0
- data/lib/active_record/secure_token.rb +21 -3
- data/lib/active_record/serialization.rb +6 -1
- data/lib/active_record/signed_id.rb +30 -9
- data/lib/active_record/statement_cache.rb +7 -7
- data/lib/active_record/store.rb +10 -10
- data/lib/active_record/suppressor.rb +13 -15
- data/lib/active_record/table_metadata.rb +7 -3
- data/lib/active_record/tasks/database_tasks.rb +288 -149
- data/lib/active_record/tasks/mysql_database_tasks.rb +16 -7
- data/lib/active_record/tasks/postgresql_database_tasks.rb +35 -26
- data/lib/active_record/tasks/sqlite_database_tasks.rb +16 -7
- data/lib/active_record/test_databases.rb +1 -1
- data/lib/active_record/test_fixtures.rb +173 -155
- data/lib/active_record/testing/query_assertions.rb +121 -0
- data/lib/active_record/timestamp.rb +32 -19
- data/lib/active_record/token_for.rb +123 -0
- data/lib/active_record/touch_later.rb +12 -7
- data/lib/active_record/transaction.rb +132 -0
- data/lib/active_record/transactions.rb +118 -41
- data/lib/active_record/translation.rb +3 -5
- data/lib/active_record/type/adapter_specific_registry.rb +32 -14
- data/lib/active_record/type/hash_lookup_type_map.rb +34 -1
- data/lib/active_record/type/internal/timezone.rb +7 -2
- data/lib/active_record/type/serialized.rb +9 -7
- data/lib/active_record/type/time.rb +4 -0
- data/lib/active_record/type/type_map.rb +17 -20
- data/lib/active_record/type.rb +1 -2
- data/lib/active_record/type_caster/connection.rb +4 -4
- data/lib/active_record/validations/absence.rb +1 -1
- data/lib/active_record/validations/associated.rb +13 -7
- data/lib/active_record/validations/numericality.rb +5 -4
- data/lib/active_record/validations/presence.rb +5 -28
- data/lib/active_record/validations/uniqueness.rb +65 -15
- data/lib/active_record/validations.rb +12 -5
- data/lib/active_record/version.rb +1 -1
- data/lib/active_record.rb +444 -32
- data/lib/arel/alias_predication.rb +1 -1
- data/lib/arel/attributes/attribute.rb +0 -8
- data/lib/arel/collectors/bind.rb +2 -0
- data/lib/arel/collectors/composite.rb +7 -0
- data/lib/arel/collectors/sql_string.rb +1 -1
- data/lib/arel/collectors/substitute_binds.rb +1 -1
- data/lib/arel/crud.rb +28 -22
- data/lib/arel/delete_manager.rb +18 -4
- data/lib/arel/errors.rb +10 -0
- data/lib/arel/factory_methods.rb +4 -0
- data/lib/arel/filter_predications.rb +9 -0
- data/lib/arel/insert_manager.rb +2 -3
- data/lib/arel/nodes/binary.rb +6 -7
- data/lib/arel/nodes/bound_sql_literal.rb +65 -0
- data/lib/arel/nodes/casted.rb +1 -1
- data/lib/arel/nodes/cte.rb +36 -0
- data/lib/arel/nodes/delete_statement.rb +12 -13
- data/lib/arel/nodes/filter.rb +10 -0
- data/lib/arel/nodes/fragments.rb +35 -0
- data/lib/arel/nodes/function.rb +1 -0
- data/lib/arel/nodes/homogeneous_in.rb +1 -9
- data/lib/arel/nodes/insert_statement.rb +2 -2
- data/lib/arel/nodes/leading_join.rb +8 -0
- data/lib/arel/nodes/{and.rb → nary.rb} +9 -2
- data/lib/arel/nodes/node.rb +115 -5
- data/lib/arel/nodes/select_core.rb +2 -2
- data/lib/arel/nodes/select_statement.rb +2 -2
- data/lib/arel/nodes/sql_literal.rb +13 -0
- data/lib/arel/nodes/table_alias.rb +4 -0
- data/lib/arel/nodes/update_statement.rb +8 -3
- data/lib/arel/nodes.rb +7 -2
- data/lib/arel/predications.rb +14 -4
- data/lib/arel/select_manager.rb +11 -5
- data/lib/arel/table.rb +9 -6
- data/lib/arel/tree_manager.rb +8 -15
- data/lib/arel/update_manager.rb +20 -5
- data/lib/arel/visitors/dot.rb +81 -90
- data/lib/arel/visitors/mysql.rb +23 -5
- data/lib/arel/visitors/postgresql.rb +1 -22
- data/lib/arel/visitors/sqlite.rb +25 -0
- data/lib/arel/visitors/to_sql.rb +170 -36
- data/lib/arel/visitors/visitor.rb +2 -2
- data/lib/arel.rb +23 -4
- data/lib/rails/generators/active_record/application_record/USAGE +8 -0
- data/lib/rails/generators/active_record/application_record/templates/application_record.rb.tt +1 -1
- data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb.tt +4 -1
- data/lib/rails/generators/active_record/migration.rb +3 -1
- data/lib/rails/generators/active_record/model/USAGE +113 -0
- data/lib/rails/generators/active_record/model/model_generator.rb +15 -6
- data/lib/rails/generators/active_record/model/templates/abstract_base_class.rb.tt +1 -1
- data/lib/rails/generators/active_record/model/templates/model.rb.tt +1 -1
- data/lib/rails/generators/active_record/model/templates/module.rb.tt +2 -2
- data/lib/rails/generators/active_record/multi_db/multi_db_generator.rb +16 -0
- data/lib/rails/generators/active_record/multi_db/templates/multi_db.rb.tt +44 -0
- metadata +103 -17
- data/lib/active_record/connection_adapters/legacy_pool_manager.rb +0 -35
- data/lib/active_record/null_relation.rb +0 -67
data/lib/arel/visitors/to_sql.rb
CHANGED
@@ -20,6 +20,7 @@ module Arel # :nodoc: all
|
|
20
20
|
|
21
21
|
private
|
22
22
|
def visit_Arel_Nodes_DeleteStatement(o, collector)
|
23
|
+
collector.retryable = false
|
23
24
|
o = prepare_delete_statement(o)
|
24
25
|
|
25
26
|
if has_join_sources?(o)
|
@@ -37,6 +38,7 @@ module Arel # :nodoc: all
|
|
37
38
|
end
|
38
39
|
|
39
40
|
def visit_Arel_Nodes_UpdateStatement(o, collector)
|
41
|
+
collector.retryable = false
|
40
42
|
o = prepare_update_statement(o)
|
41
43
|
|
42
44
|
collector << "UPDATE "
|
@@ -49,6 +51,7 @@ module Arel # :nodoc: all
|
|
49
51
|
end
|
50
52
|
|
51
53
|
def visit_Arel_Nodes_InsertStatement(o, collector)
|
54
|
+
collector.retryable = false
|
52
55
|
collector << "INSERT INTO "
|
53
56
|
collector = visit o.relation, collector
|
54
57
|
|
@@ -103,7 +106,7 @@ module Arel # :nodoc: all
|
|
103
106
|
row.each_with_index do |value, k|
|
104
107
|
collector << ", " unless k == 0
|
105
108
|
case value
|
106
|
-
when Nodes::SqlLiteral, Nodes::BindParam
|
109
|
+
when Nodes::SqlLiteral, Nodes::BindParam, ActiveModel::Attribute
|
107
110
|
collector = visit(value, collector)
|
108
111
|
else
|
109
112
|
collector << quote(value).to_s
|
@@ -135,6 +138,8 @@ module Arel # :nodoc: all
|
|
135
138
|
visit_Arel_Nodes_SelectOptions(o, collector)
|
136
139
|
end
|
137
140
|
|
141
|
+
# The Oracle enhanced adapter uses this private method,
|
142
|
+
# see https://github.com/rsim/oracle-enhanced/issues/2186
|
138
143
|
def visit_Arel_Nodes_SelectOptions(o, collector)
|
139
144
|
collector = maybe_visit o.limit, collector
|
140
145
|
collector = maybe_visit o.offset, collector
|
@@ -243,6 +248,13 @@ module Arel # :nodoc: all
|
|
243
248
|
collector << ")"
|
244
249
|
end
|
245
250
|
|
251
|
+
def visit_Arel_Nodes_Filter(o, collector)
|
252
|
+
visit o.left, collector
|
253
|
+
collector << " FILTER (WHERE "
|
254
|
+
visit o.right, collector
|
255
|
+
collector << ")"
|
256
|
+
end
|
257
|
+
|
246
258
|
def visit_Arel_Nodes_Rows(o, collector)
|
247
259
|
if o.expr
|
248
260
|
collector << "ROWS "
|
@@ -324,7 +336,7 @@ module Arel # :nodoc: all
|
|
324
336
|
def visit_Arel_Nodes_HomogeneousIn(o, collector)
|
325
337
|
collector.preparable = false
|
326
338
|
|
327
|
-
|
339
|
+
visit o.left, collector
|
328
340
|
|
329
341
|
if o.type == :in
|
330
342
|
collector << " IN ("
|
@@ -341,7 +353,6 @@ module Arel # :nodoc: all
|
|
341
353
|
end
|
342
354
|
|
343
355
|
collector << ")"
|
344
|
-
collector
|
345
356
|
end
|
346
357
|
|
347
358
|
def visit_Arel_SelectManager(o, collector)
|
@@ -357,11 +368,23 @@ module Arel # :nodoc: all
|
|
357
368
|
visit(o.expr, collector) << " DESC"
|
358
369
|
end
|
359
370
|
|
371
|
+
# NullsFirst is available on all but MySQL, where it is redefined.
|
372
|
+
def visit_Arel_Nodes_NullsFirst(o, collector)
|
373
|
+
visit o.expr, collector
|
374
|
+
collector << " NULLS FIRST"
|
375
|
+
end
|
376
|
+
|
377
|
+
def visit_Arel_Nodes_NullsLast(o, collector)
|
378
|
+
visit o.expr, collector
|
379
|
+
collector << " NULLS LAST"
|
380
|
+
end
|
381
|
+
|
360
382
|
def visit_Arel_Nodes_Group(o, collector)
|
361
383
|
visit o.expr, collector
|
362
384
|
end
|
363
385
|
|
364
386
|
def visit_Arel_Nodes_NamedFunction(o, collector)
|
387
|
+
collector.retryable = false
|
365
388
|
collector << o.name
|
366
389
|
collector << "("
|
367
390
|
collector << "DISTINCT " if o.distinct
|
@@ -412,24 +435,48 @@ module Arel # :nodoc: all
|
|
412
435
|
end
|
413
436
|
|
414
437
|
def visit_Arel_Nodes_GreaterThanOrEqual(o, collector)
|
438
|
+
case unboundable?(o.right)
|
439
|
+
when 1
|
440
|
+
return collector << "1=0"
|
441
|
+
when -1
|
442
|
+
return collector << "1=1"
|
443
|
+
end
|
415
444
|
collector = visit o.left, collector
|
416
445
|
collector << " >= "
|
417
446
|
visit o.right, collector
|
418
447
|
end
|
419
448
|
|
420
449
|
def visit_Arel_Nodes_GreaterThan(o, collector)
|
450
|
+
case unboundable?(o.right)
|
451
|
+
when 1
|
452
|
+
return collector << "1=0"
|
453
|
+
when -1
|
454
|
+
return collector << "1=1"
|
455
|
+
end
|
421
456
|
collector = visit o.left, collector
|
422
457
|
collector << " > "
|
423
458
|
visit o.right, collector
|
424
459
|
end
|
425
460
|
|
426
461
|
def visit_Arel_Nodes_LessThanOrEqual(o, collector)
|
462
|
+
case unboundable?(o.right)
|
463
|
+
when 1
|
464
|
+
return collector << "1=1"
|
465
|
+
when -1
|
466
|
+
return collector << "1=0"
|
467
|
+
end
|
427
468
|
collector = visit o.left, collector
|
428
469
|
collector << " <= "
|
429
470
|
visit o.right, collector
|
430
471
|
end
|
431
472
|
|
432
473
|
def visit_Arel_Nodes_LessThan(o, collector)
|
474
|
+
case unboundable?(o.right)
|
475
|
+
when 1
|
476
|
+
return collector << "1=1"
|
477
|
+
when -1
|
478
|
+
return collector << "1=0"
|
479
|
+
end
|
433
480
|
collector = visit o.left, collector
|
434
481
|
collector << " < "
|
435
482
|
visit o.right, collector
|
@@ -525,18 +572,25 @@ module Arel # :nodoc: all
|
|
525
572
|
end
|
526
573
|
|
527
574
|
def visit_Arel_Table(o, collector)
|
528
|
-
if o.
|
529
|
-
|
575
|
+
if Arel::Nodes::Node === o.name
|
576
|
+
visit o.name, collector
|
530
577
|
else
|
531
578
|
collector << quote_table_name(o.name)
|
532
579
|
end
|
580
|
+
|
581
|
+
if o.table_alias
|
582
|
+
collector << " " << quote_table_name(o.table_alias)
|
583
|
+
end
|
584
|
+
|
585
|
+
collector
|
533
586
|
end
|
534
587
|
|
535
588
|
def visit_Arel_Nodes_In(o, collector)
|
536
|
-
collector.preparable = false
|
537
589
|
attr, values = o.left, o.right
|
538
590
|
|
539
591
|
if Array === values
|
592
|
+
collector.preparable = false
|
593
|
+
|
540
594
|
unless values.empty?
|
541
595
|
values.delete_if { |value| unboundable?(value) }
|
542
596
|
end
|
@@ -549,10 +603,11 @@ module Arel # :nodoc: all
|
|
549
603
|
end
|
550
604
|
|
551
605
|
def visit_Arel_Nodes_NotIn(o, collector)
|
552
|
-
collector.preparable = false
|
553
606
|
attr, values = o.left, o.right
|
554
607
|
|
555
608
|
if Array === values
|
609
|
+
collector.preparable = false
|
610
|
+
|
556
611
|
unless values.empty?
|
557
612
|
values.delete_if { |value| unboundable?(value) }
|
558
613
|
end
|
@@ -569,23 +624,12 @@ module Arel # :nodoc: all
|
|
569
624
|
end
|
570
625
|
|
571
626
|
def visit_Arel_Nodes_Or(o, collector)
|
572
|
-
|
573
|
-
|
574
|
-
while o = stack.pop
|
575
|
-
if o.is_a?(Arel::Nodes::Or)
|
576
|
-
stack.push o.right, o.left
|
577
|
-
else
|
578
|
-
visit o, collector
|
579
|
-
collector << " OR " unless stack.empty?
|
580
|
-
end
|
581
|
-
end
|
582
|
-
|
583
|
-
collector
|
627
|
+
inject_join o.children, collector, " OR "
|
584
628
|
end
|
585
629
|
|
586
630
|
def visit_Arel_Nodes_Assignment(o, collector)
|
587
631
|
case o.right
|
588
|
-
when Arel::Nodes::Node, Arel::Attributes::Attribute
|
632
|
+
when Arel::Nodes::Node, Arel::Attributes::Attribute, ActiveModel::Attribute
|
589
633
|
collector = visit o.left, collector
|
590
634
|
collector << " = "
|
591
635
|
visit o.right, collector
|
@@ -685,6 +729,20 @@ module Arel # :nodoc: all
|
|
685
729
|
collector << quote_column_name(o.name)
|
686
730
|
end
|
687
731
|
|
732
|
+
def visit_Arel_Nodes_Cte(o, collector)
|
733
|
+
collector << quote_table_name(o.name)
|
734
|
+
collector << " AS "
|
735
|
+
|
736
|
+
case o.materialized
|
737
|
+
when true
|
738
|
+
collector << "MATERIALIZED "
|
739
|
+
when false
|
740
|
+
collector << "NOT MATERIALIZED "
|
741
|
+
end
|
742
|
+
|
743
|
+
visit o.relation, collector
|
744
|
+
end
|
745
|
+
|
688
746
|
def visit_Arel_Attributes_Attribute(o, collector)
|
689
747
|
join_name = o.relation.table_alias || o.relation.name
|
690
748
|
collector << quote_table_name(join_name) << "." << quote_column_name(o.name)
|
@@ -695,15 +753,74 @@ module Arel # :nodoc: all
|
|
695
753
|
|
696
754
|
def bind_block; BIND_BLOCK; end
|
697
755
|
|
756
|
+
def visit_ActiveModel_Attribute(o, collector)
|
757
|
+
collector.add_bind(o, &bind_block)
|
758
|
+
end
|
759
|
+
|
698
760
|
def visit_Arel_Nodes_BindParam(o, collector)
|
699
761
|
collector.add_bind(o.value, &bind_block)
|
700
762
|
end
|
701
763
|
|
702
764
|
def visit_Arel_Nodes_SqlLiteral(o, collector)
|
703
765
|
collector.preparable = false
|
766
|
+
collector.retryable = o.retryable
|
704
767
|
collector << o.to_s
|
705
768
|
end
|
706
769
|
|
770
|
+
def visit_Arel_Nodes_BoundSqlLiteral(o, collector)
|
771
|
+
collector.retryable = false
|
772
|
+
bind_index = 0
|
773
|
+
|
774
|
+
new_bind = lambda do |value|
|
775
|
+
if Arel.arel_node?(value)
|
776
|
+
visit value, collector
|
777
|
+
elsif value.is_a?(Array)
|
778
|
+
if value.empty?
|
779
|
+
collector << @connection.quote(nil)
|
780
|
+
else
|
781
|
+
if value.none? { |v| Arel.arel_node?(v) }
|
782
|
+
collector.add_binds(value.map { |v| @connection.cast_bound_value(v) }, &bind_block)
|
783
|
+
else
|
784
|
+
value.each_with_index do |v, i|
|
785
|
+
collector << ", " unless i == 0
|
786
|
+
if Arel.arel_node?(v)
|
787
|
+
visit v, collector
|
788
|
+
else
|
789
|
+
collector.add_bind(@connection.cast_bound_value(v), &bind_block)
|
790
|
+
end
|
791
|
+
end
|
792
|
+
end
|
793
|
+
end
|
794
|
+
else
|
795
|
+
collector.add_bind(@connection.cast_bound_value(value), &bind_block)
|
796
|
+
end
|
797
|
+
end
|
798
|
+
|
799
|
+
if o.positional_binds
|
800
|
+
o.sql_with_placeholders.scan(/\?|([^?]+)/) do
|
801
|
+
if $1
|
802
|
+
collector << $1
|
803
|
+
else
|
804
|
+
value = o.positional_binds[bind_index]
|
805
|
+
bind_index += 1
|
806
|
+
|
807
|
+
new_bind.call(value)
|
808
|
+
end
|
809
|
+
end
|
810
|
+
else
|
811
|
+
o.sql_with_placeholders.scan(/:(?<!::)([a-zA-Z]\w*)|([^:]+|.)/) do
|
812
|
+
if $2
|
813
|
+
collector << $2
|
814
|
+
else
|
815
|
+
value = o.named_binds[$1.to_sym]
|
816
|
+
new_bind.call(value)
|
817
|
+
end
|
818
|
+
end
|
819
|
+
end
|
820
|
+
|
821
|
+
collector
|
822
|
+
end
|
823
|
+
|
707
824
|
def visit_Integer(o, collector)
|
708
825
|
collector << o.to_s
|
709
826
|
end
|
@@ -743,6 +860,10 @@ module Arel # :nodoc: all
|
|
743
860
|
end
|
744
861
|
alias :visit_Set :visit_Array
|
745
862
|
|
863
|
+
def visit_Arel_Nodes_Fragments(o, collector)
|
864
|
+
inject_join o.values, collector, " "
|
865
|
+
end
|
866
|
+
|
746
867
|
def quote(value)
|
747
868
|
return value if Arel::Nodes::SqlLiteral === value
|
748
869
|
@connection.quote value
|
@@ -793,6 +914,10 @@ module Arel # :nodoc: all
|
|
793
914
|
o.limit || o.offset || !o.orders.empty?
|
794
915
|
end
|
795
916
|
|
917
|
+
def has_group_by_and_having?(o)
|
918
|
+
!o.groups.empty? && !o.havings.empty?
|
919
|
+
end
|
920
|
+
|
796
921
|
# The default strategy for an UPDATE with joins is to use a subquery. This doesn't work
|
797
922
|
# on MySQL (even when aliasing the tables), but MySQL allows using JOIN directly in
|
798
923
|
# an UPDATE statement, so in the MySQL visitor we redefine this to do that.
|
@@ -802,8 +927,11 @@ module Arel # :nodoc: all
|
|
802
927
|
stmt.limit = nil
|
803
928
|
stmt.offset = nil
|
804
929
|
stmt.orders = []
|
805
|
-
|
930
|
+
columns = Arel::Nodes::Grouping.new(o.key)
|
931
|
+
stmt.wheres = [Nodes::In.new(columns, [build_subselect(o.key, o)])]
|
806
932
|
stmt.relation = o.relation.left if has_join_sources?(o)
|
933
|
+
stmt.groups = o.groups unless o.groups.empty?
|
934
|
+
stmt.havings = o.havings unless o.havings.empty?
|
807
935
|
stmt
|
808
936
|
else
|
809
937
|
o
|
@@ -818,6 +946,8 @@ module Arel # :nodoc: all
|
|
818
946
|
core.froms = o.relation
|
819
947
|
core.wheres = o.wheres
|
820
948
|
core.projections = [key]
|
949
|
+
core.groups = o.groups unless o.groups.empty?
|
950
|
+
core.havings = o.havings unless o.havings.empty?
|
821
951
|
stmt.limit = o.limit
|
822
952
|
stmt.offset = o.offset
|
823
953
|
stmt.orders = o.orders
|
@@ -835,18 +965,34 @@ module Arel # :nodoc: all
|
|
835
965
|
collector = if o.left.class == o.class
|
836
966
|
infix_value_with_paren(o.left, collector, value, true)
|
837
967
|
else
|
838
|
-
|
968
|
+
grouping_parentheses o.left, collector, false
|
839
969
|
end
|
840
970
|
collector << value
|
841
971
|
collector = if o.right.class == o.class
|
842
972
|
infix_value_with_paren(o.right, collector, value, true)
|
843
973
|
else
|
844
|
-
|
974
|
+
grouping_parentheses o.right, collector, false
|
845
975
|
end
|
846
976
|
collector << " )" unless suppress_parens
|
847
977
|
collector
|
848
978
|
end
|
849
979
|
|
980
|
+
# Used by some visitors to enclose select queries in parentheses
|
981
|
+
def grouping_parentheses(o, collector, always_wrap_selects = true)
|
982
|
+
if o.is_a?(Nodes::SelectStatement) && (always_wrap_selects || require_parentheses?(o))
|
983
|
+
collector << "("
|
984
|
+
visit o, collector
|
985
|
+
collector << ")"
|
986
|
+
collector
|
987
|
+
else
|
988
|
+
visit o, collector
|
989
|
+
end
|
990
|
+
end
|
991
|
+
|
992
|
+
def require_parentheses?(o)
|
993
|
+
!o.orders.empty? || o.limit || o.offset
|
994
|
+
end
|
995
|
+
|
850
996
|
def aggregate(name, o, collector)
|
851
997
|
collector << "#{name}("
|
852
998
|
if o.distinct
|
@@ -877,19 +1023,7 @@ module Arel # :nodoc: all
|
|
877
1023
|
def collect_ctes(children, collector)
|
878
1024
|
children.each_with_index do |child, i|
|
879
1025
|
collector << ", " unless i == 0
|
880
|
-
|
881
|
-
case child
|
882
|
-
when Arel::Nodes::As
|
883
|
-
name = child.left.name
|
884
|
-
relation = child.right
|
885
|
-
when Arel::Nodes::TableAlias
|
886
|
-
name = child.name
|
887
|
-
relation = child.relation
|
888
|
-
end
|
889
|
-
|
890
|
-
collector << quote_table_name(name)
|
891
|
-
collector << " AS "
|
892
|
-
visit relation, collector
|
1026
|
+
visit child.to_cte, collector
|
893
1027
|
end
|
894
1028
|
|
895
1029
|
collector
|
@@ -16,8 +16,8 @@ module Arel # :nodoc: all
|
|
16
16
|
|
17
17
|
def self.dispatch_cache
|
18
18
|
@dispatch_cache ||= Hash.new do |hash, klass|
|
19
|
-
hash[klass] = "visit_#{(klass.name ||
|
20
|
-
end
|
19
|
+
hash[klass] = :"visit_#{(klass.name || "").gsub("::", "_")}"
|
20
|
+
end.compare_by_identity
|
21
21
|
end
|
22
22
|
|
23
23
|
def get_dispatch_cache
|
data/lib/arel.rb
CHANGED
@@ -7,6 +7,7 @@ require "arel/factory_methods"
|
|
7
7
|
|
8
8
|
require "arel/expressions"
|
9
9
|
require "arel/predications"
|
10
|
+
require "arel/filter_predications"
|
10
11
|
require "arel/window_predications"
|
11
12
|
require "arel/math"
|
12
13
|
require "arel/alias_predication"
|
@@ -29,17 +30,35 @@ module Arel
|
|
29
30
|
|
30
31
|
# Wrap a known-safe SQL string for passing to query methods, e.g.
|
31
32
|
#
|
32
|
-
# Post.order(Arel.sql("
|
33
|
+
# Post.order(Arel.sql("REPLACE(title, 'misc', 'zzzz') asc")).pluck(:id)
|
33
34
|
#
|
34
35
|
# Great caution should be taken to avoid SQL injection vulnerabilities.
|
35
36
|
# This method should not be used with unsafe values such as request
|
36
37
|
# parameters or model attributes.
|
37
|
-
|
38
|
-
|
38
|
+
#
|
39
|
+
# Take a look at the {security guide}[https://guides.rubyonrails.org/security.html#sql-injection]
|
40
|
+
# for more information.
|
41
|
+
#
|
42
|
+
# To construct a more complex query fragment, including the possible
|
43
|
+
# use of user-provided values, the +sql_string+ may contain <tt>?</tt> and
|
44
|
+
# +:key+ placeholders, corresponding to the additional arguments. Note
|
45
|
+
# that this behavior only applies when bind value parameters are
|
46
|
+
# supplied in the call; without them, the placeholder tokens have no
|
47
|
+
# special meaning, and will be passed through to the query as-is.
|
48
|
+
#
|
49
|
+
# The +:retryable+ option can be used to mark the SQL as safe to retry.
|
50
|
+
# Use this option only if the SQL is idempotent, as it could be executed
|
51
|
+
# more than once.
|
52
|
+
def self.sql(sql_string, *positional_binds, retryable: false, **named_binds)
|
53
|
+
if positional_binds.empty? && named_binds.empty?
|
54
|
+
Arel::Nodes::SqlLiteral.new(sql_string, retryable: retryable)
|
55
|
+
else
|
56
|
+
Arel::Nodes::BoundSqlLiteral.new sql_string, positional_binds, named_binds
|
57
|
+
end
|
39
58
|
end
|
40
59
|
|
41
60
|
def self.star # :nodoc:
|
42
|
-
sql
|
61
|
+
sql("*", retryable: true)
|
43
62
|
end
|
44
63
|
|
45
64
|
def self.arel_node?(value) # :nodoc:
|
@@ -0,0 +1,8 @@
|
|
1
|
+
Description:
|
2
|
+
Generates an `ApplicationRecord` base class for other models to inherit from.
|
3
|
+
|
4
|
+
Example:
|
5
|
+
`bin/rails generate application_record`
|
6
|
+
|
7
|
+
This generates the base class. A test is not generated because no
|
8
|
+
behaviour is included in `ApplicationRecord` by default.
|
@@ -12,7 +12,10 @@ class <%= migration_class_name %> < ActiveRecord::Migration[<%= ActiveRecord::Mi
|
|
12
12
|
t.<%= attribute.type %> :<%= attribute.name %><%= attribute.inject_options %>
|
13
13
|
<% end -%>
|
14
14
|
<% end -%>
|
15
|
-
<%
|
15
|
+
<% unless attributes.empty? -%>
|
16
|
+
|
17
|
+
<% end -%>
|
18
|
+
<% if options[:timestamps] -%>
|
16
19
|
t.timestamps
|
17
20
|
<% end -%>
|
18
21
|
end
|
@@ -41,11 +41,13 @@ module ActiveRecord
|
|
41
41
|
|
42
42
|
def configured_migrate_path
|
43
43
|
return unless database = options[:database]
|
44
|
+
|
44
45
|
config = ActiveRecord::Base.configurations.configs_for(
|
45
46
|
env_name: Rails.env,
|
46
47
|
name: database
|
47
48
|
)
|
48
|
-
|
49
|
+
|
50
|
+
Array(config&.migrations_paths).first
|
49
51
|
end
|
50
52
|
end
|
51
53
|
end
|
@@ -0,0 +1,113 @@
|
|
1
|
+
Description:
|
2
|
+
Generates a new model. Pass the model name, either CamelCased or
|
3
|
+
under_scored, and an optional list of attribute pairs as arguments.
|
4
|
+
|
5
|
+
Attribute pairs are field:type arguments specifying the
|
6
|
+
model's attributes. Timestamps are added by default, so you don't have to
|
7
|
+
specify them by hand as 'created_at:datetime updated_at:datetime'.
|
8
|
+
|
9
|
+
As a special case, specifying 'password:digest' will generate a
|
10
|
+
password_digest field of string type, and configure your generated model and
|
11
|
+
tests for use with Active Model has_secure_password (assuming the default ORM
|
12
|
+
and test framework are being used).
|
13
|
+
|
14
|
+
You don't have to think up every attribute up front, but it helps to
|
15
|
+
sketch out a few so you can start working with the model immediately.
|
16
|
+
|
17
|
+
This generator invokes your configured ORM and test framework, which
|
18
|
+
defaults to Active Record and TestUnit.
|
19
|
+
|
20
|
+
Finally, if --parent option is given, it's used as superclass of the
|
21
|
+
created model. This allows you create Single Table Inheritance models.
|
22
|
+
|
23
|
+
If you pass a namespaced model name (e.g. admin/account or Admin::Account)
|
24
|
+
then the generator will create a module with a table_name_prefix method
|
25
|
+
to prefix the model's table name with the module name (e.g. admin_accounts)
|
26
|
+
|
27
|
+
Available field types:
|
28
|
+
|
29
|
+
Just after the field name you can specify a type like text or boolean.
|
30
|
+
It will generate the column with the associated SQL type. For instance:
|
31
|
+
|
32
|
+
`bin/rails generate model post title:string body:text`
|
33
|
+
|
34
|
+
will generate a title column with a varchar type and a body column with a text
|
35
|
+
type. If no type is specified the string type will be used by default.
|
36
|
+
You can use the following types:
|
37
|
+
|
38
|
+
integer
|
39
|
+
primary_key
|
40
|
+
decimal
|
41
|
+
float
|
42
|
+
boolean
|
43
|
+
binary
|
44
|
+
string
|
45
|
+
text
|
46
|
+
date
|
47
|
+
time
|
48
|
+
datetime
|
49
|
+
|
50
|
+
You can also consider `references` as a kind of type. For instance, if you run:
|
51
|
+
|
52
|
+
`bin/rails generate model photo title:string album:references`
|
53
|
+
|
54
|
+
It will generate an `album_id` column. You should generate these kinds of fields when
|
55
|
+
you will use a `belongs_to` association, for instance. `references` also supports
|
56
|
+
polymorphism, you can enable polymorphism like this:
|
57
|
+
|
58
|
+
`bin/rails generate model product supplier:references{polymorphic}`
|
59
|
+
|
60
|
+
For integer, string, text and binary fields, an integer in curly braces will
|
61
|
+
be set as the limit:
|
62
|
+
|
63
|
+
`bin/rails generate model user pseudo:string{30}`
|
64
|
+
|
65
|
+
For decimal, two integers separated by a comma in curly braces will be used
|
66
|
+
for precision and scale:
|
67
|
+
|
68
|
+
`bin/rails generate model product 'price:decimal{10,2}'`
|
69
|
+
|
70
|
+
You can add a `:uniq` or `:index` suffix for unique or standard indexes
|
71
|
+
respectively:
|
72
|
+
|
73
|
+
`bin/rails generate model user pseudo:string:uniq`
|
74
|
+
`bin/rails generate model user pseudo:string:index`
|
75
|
+
|
76
|
+
You can combine any single curly brace option with the index options:
|
77
|
+
|
78
|
+
`bin/rails generate model user username:string{30}:uniq`
|
79
|
+
`bin/rails generate model product supplier:references{polymorphic}:index`
|
80
|
+
|
81
|
+
If you require a `password_digest` string column for use with
|
82
|
+
has_secure_password, you can specify `password:digest`:
|
83
|
+
|
84
|
+
`bin/rails generate model user password:digest`
|
85
|
+
|
86
|
+
If you require a `token` string column for use with
|
87
|
+
has_secure_token, you can specify `auth_token:token`:
|
88
|
+
|
89
|
+
`bin/rails generate model user auth_token:token`
|
90
|
+
|
91
|
+
Examples:
|
92
|
+
`bin/rails generate model account`
|
93
|
+
|
94
|
+
For Active Record and TestUnit it creates:
|
95
|
+
|
96
|
+
Model: app/models/account.rb
|
97
|
+
Test: test/models/account_test.rb
|
98
|
+
Fixtures: test/fixtures/accounts.yml
|
99
|
+
Migration: db/migrate/XXX_create_accounts.rb
|
100
|
+
|
101
|
+
`bin/rails generate model post title:string body:text published:boolean`
|
102
|
+
|
103
|
+
Creates a Post model with a string title, text body, and published flag.
|
104
|
+
|
105
|
+
`bin/rails generate model admin/account`
|
106
|
+
|
107
|
+
For Active Record and TestUnit it creates:
|
108
|
+
|
109
|
+
Module: app/models/admin.rb
|
110
|
+
Model: app/models/admin/account.rb
|
111
|
+
Test: test/models/admin/account_test.rb
|
112
|
+
Fixtures: test/fixtures/admin/accounts.yml
|
113
|
+
Migration: db/migrate/XXX_create_admin_accounts.rb
|
@@ -11,20 +11,25 @@ module ActiveRecord
|
|
11
11
|
|
12
12
|
class_option :migration, type: :boolean
|
13
13
|
class_option :timestamps, type: :boolean
|
14
|
-
class_option :parent, type: :string, desc: "The parent class for the generated model"
|
14
|
+
class_option :parent, type: :string, default: "ApplicationRecord", desc: "The parent class for the generated model"
|
15
15
|
class_option :indexes, type: :boolean, default: true, desc: "Add indexes for references and belongs_to columns"
|
16
16
|
class_option :primary_key_type, type: :string, desc: "The type for primary key"
|
17
17
|
class_option :database, type: :string, aliases: %i(--db), desc: "The database for your model's migration. By default, the current environment's primary database is used."
|
18
18
|
|
19
|
+
Rails::Generators.templates_path.each do |path|
|
20
|
+
source_paths << File.join(path, base_name, "migration")
|
21
|
+
end
|
22
|
+
source_paths << File.expand_path(File.join(base_name, "migration", "templates"), base_root)
|
23
|
+
|
19
24
|
# creates the migration file for the model.
|
20
25
|
def create_migration_file
|
21
26
|
return if skip_migration_creation?
|
22
27
|
attributes.each { |a| a.attr_options.delete(:index) if a.reference? && !a.has_index? } if options[:indexes] == false
|
23
|
-
migration_template "
|
28
|
+
migration_template "create_table_migration.rb", File.join(db_migrate_path, "create_#{table_name}.rb")
|
24
29
|
end
|
25
30
|
|
26
31
|
def create_model_file
|
27
|
-
generate_abstract_class if database && !
|
32
|
+
generate_abstract_class if database && !custom_parent?
|
28
33
|
template "model.rb", File.join("app/models", class_path, "#{file_name}.rb")
|
29
34
|
end
|
30
35
|
|
@@ -40,7 +45,7 @@ module ActiveRecord
|
|
40
45
|
# - options parent is present and database option is not present
|
41
46
|
# - migrations option is nil or false
|
42
47
|
def skip_migration_creation?
|
43
|
-
|
48
|
+
custom_parent? && !database || !migration
|
44
49
|
end
|
45
50
|
|
46
51
|
def attributes_with_index
|
@@ -49,12 +54,12 @@ module ActiveRecord
|
|
49
54
|
|
50
55
|
# Used by the migration template to determine the parent name of the model
|
51
56
|
def parent_class_name
|
52
|
-
if
|
57
|
+
if custom_parent?
|
53
58
|
parent
|
54
59
|
elsif database
|
55
60
|
abstract_class_name
|
56
61
|
else
|
57
|
-
|
62
|
+
parent
|
58
63
|
end
|
59
64
|
end
|
60
65
|
|
@@ -77,6 +82,10 @@ module ActiveRecord
|
|
77
82
|
options[:parent]
|
78
83
|
end
|
79
84
|
|
85
|
+
def custom_parent?
|
86
|
+
parent != self.class.class_options[:parent].default
|
87
|
+
end
|
88
|
+
|
80
89
|
def migration
|
81
90
|
options[:migration]
|
82
91
|
end
|