activerecord 6.0.0 → 6.1.3
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of activerecord might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/CHANGELOG.md +1045 -575
- data/MIT-LICENSE +1 -1
- data/README.rdoc +4 -4
- data/lib/active_record.rb +7 -13
- data/lib/active_record/aggregations.rb +5 -6
- data/lib/active_record/association_relation.rb +30 -10
- data/lib/active_record/associations.rb +120 -13
- data/lib/active_record/associations/alias_tracker.rb +19 -16
- data/lib/active_record/associations/association.rb +49 -29
- data/lib/active_record/associations/association_scope.rb +19 -15
- data/lib/active_record/associations/belongs_to_association.rb +22 -8
- data/lib/active_record/associations/belongs_to_polymorphic_association.rb +8 -3
- data/lib/active_record/associations/builder/association.rb +32 -5
- data/lib/active_record/associations/builder/belongs_to.rb +10 -7
- data/lib/active_record/associations/builder/collection_association.rb +5 -4
- data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +0 -3
- data/lib/active_record/associations/builder/has_many.rb +6 -2
- data/lib/active_record/associations/builder/has_one.rb +11 -14
- data/lib/active_record/associations/builder/singular_association.rb +1 -1
- data/lib/active_record/associations/collection_association.rb +25 -8
- data/lib/active_record/associations/collection_proxy.rb +14 -7
- data/lib/active_record/associations/foreign_association.rb +13 -0
- data/lib/active_record/associations/has_many_association.rb +24 -3
- data/lib/active_record/associations/has_many_through_association.rb +10 -4
- data/lib/active_record/associations/has_one_association.rb +15 -1
- data/lib/active_record/associations/join_dependency.rb +77 -42
- data/lib/active_record/associations/join_dependency/join_association.rb +39 -16
- data/lib/active_record/associations/join_dependency/join_part.rb +3 -3
- data/lib/active_record/associations/preloader.rb +13 -8
- data/lib/active_record/associations/preloader/association.rb +51 -25
- data/lib/active_record/associations/preloader/through_association.rb +2 -2
- data/lib/active_record/associations/singular_association.rb +1 -1
- data/lib/active_record/associations/through_association.rb +1 -1
- data/lib/active_record/attribute_assignment.rb +10 -9
- data/lib/active_record/attribute_methods.rb +64 -54
- data/lib/active_record/attribute_methods/before_type_cast.rb +13 -10
- data/lib/active_record/attribute_methods/dirty.rb +3 -13
- data/lib/active_record/attribute_methods/primary_key.rb +6 -4
- data/lib/active_record/attribute_methods/query.rb +3 -6
- data/lib/active_record/attribute_methods/read.rb +8 -12
- data/lib/active_record/attribute_methods/serialization.rb +11 -6
- data/lib/active_record/attribute_methods/time_zone_conversion.rb +12 -15
- data/lib/active_record/attribute_methods/write.rb +12 -21
- data/lib/active_record/attributes.rb +33 -9
- data/lib/active_record/autosave_association.rb +63 -44
- data/lib/active_record/base.rb +2 -14
- data/lib/active_record/callbacks.rb +153 -24
- data/lib/active_record/coders/yaml_column.rb +1 -2
- data/lib/active_record/connection_adapters.rb +50 -0
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +202 -138
- data/lib/active_record/connection_adapters/abstract/database_limits.rb +2 -44
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +87 -38
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +5 -10
- data/lib/active_record/connection_adapters/abstract/quoting.rb +34 -34
- data/lib/active_record/connection_adapters/abstract/savepoints.rb +3 -3
- data/lib/active_record/connection_adapters/abstract/schema_creation.rb +152 -116
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +141 -52
- data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +3 -3
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +267 -105
- data/lib/active_record/connection_adapters/abstract/transaction.rb +82 -35
- data/lib/active_record/connection_adapters/abstract_adapter.rb +74 -77
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +149 -115
- data/lib/active_record/connection_adapters/column.rb +15 -1
- data/lib/active_record/connection_adapters/deduplicable.rb +29 -0
- data/lib/active_record/connection_adapters/legacy_pool_manager.rb +31 -0
- data/lib/active_record/connection_adapters/mysql/column.rb +1 -1
- data/lib/active_record/connection_adapters/mysql/database_statements.rb +30 -36
- data/lib/active_record/connection_adapters/mysql/explain_pretty_printer.rb +1 -2
- data/lib/active_record/connection_adapters/mysql/quoting.rb +18 -3
- data/lib/active_record/connection_adapters/mysql/schema_creation.rb +32 -7
- data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +8 -0
- data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +5 -2
- data/lib/active_record/connection_adapters/mysql/schema_statements.rb +17 -13
- data/lib/active_record/connection_adapters/mysql/type_metadata.rb +10 -1
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +31 -13
- data/lib/active_record/connection_adapters/pool_config.rb +73 -0
- data/lib/active_record/connection_adapters/pool_manager.rb +43 -0
- data/lib/active_record/connection_adapters/postgresql/column.rb +24 -1
- data/lib/active_record/connection_adapters/postgresql/database_statements.rb +21 -56
- data/lib/active_record/connection_adapters/postgresql/oid.rb +2 -0
- data/lib/active_record/connection_adapters/postgresql/oid/array.rb +0 -1
- data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +3 -5
- data/lib/active_record/connection_adapters/postgresql/oid/date.rb +2 -2
- data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +10 -2
- data/lib/active_record/connection_adapters/postgresql/oid/enum.rb +0 -1
- data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +0 -1
- data/lib/active_record/connection_adapters/postgresql/oid/interval.rb +49 -0
- data/lib/active_record/connection_adapters/postgresql/oid/legacy_point.rb +2 -3
- data/lib/active_record/connection_adapters/postgresql/oid/macaddr.rb +25 -0
- data/lib/active_record/connection_adapters/postgresql/oid/money.rb +2 -2
- data/lib/active_record/connection_adapters/postgresql/oid/oid.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/oid/point.rb +2 -3
- data/lib/active_record/connection_adapters/postgresql/oid/range.rb +24 -6
- data/lib/active_record/connection_adapters/postgresql/oid/specialized_string.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +11 -2
- data/lib/active_record/connection_adapters/postgresql/quoting.rb +4 -4
- data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +2 -2
- data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +7 -3
- data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +0 -1
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +72 -54
- data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +8 -0
- data/lib/active_record/connection_adapters/postgresql/utils.rb +0 -1
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +83 -65
- data/lib/active_record/connection_adapters/schema_cache.rb +98 -15
- data/lib/active_record/connection_adapters/sql_type_metadata.rb +10 -0
- data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +38 -12
- data/lib/active_record/connection_adapters/sqlite3/quoting.rb +1 -2
- data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +5 -1
- data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +38 -5
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +61 -57
- data/lib/active_record/connection_adapters/statement_pool.rb +0 -1
- data/lib/active_record/connection_handling.rb +219 -81
- data/lib/active_record/core.rb +253 -67
- data/lib/active_record/counter_cache.rb +4 -1
- data/lib/active_record/database_configurations.rb +124 -85
- data/lib/active_record/database_configurations/connection_url_resolver.rb +98 -0
- data/lib/active_record/database_configurations/database_config.rb +52 -9
- data/lib/active_record/database_configurations/hash_config.rb +54 -8
- data/lib/active_record/database_configurations/url_config.rb +15 -41
- data/lib/active_record/delegated_type.rb +209 -0
- data/lib/active_record/destroy_association_async_job.rb +36 -0
- data/lib/active_record/dynamic_matchers.rb +2 -3
- data/lib/active_record/enum.rb +82 -38
- data/lib/active_record/errors.rb +47 -12
- data/lib/active_record/explain.rb +9 -5
- data/lib/active_record/explain_subscriber.rb +1 -1
- data/lib/active_record/fixture_set/file.rb +10 -17
- data/lib/active_record/fixture_set/model_metadata.rb +1 -2
- data/lib/active_record/fixture_set/render_context.rb +1 -1
- data/lib/active_record/fixture_set/table_row.rb +2 -3
- data/lib/active_record/fixture_set/table_rows.rb +0 -1
- data/lib/active_record/fixtures.rb +58 -12
- data/lib/active_record/gem_version.rb +2 -2
- data/lib/active_record/inheritance.rb +40 -21
- data/lib/active_record/insert_all.rb +39 -10
- data/lib/active_record/integration.rb +3 -5
- data/lib/active_record/internal_metadata.rb +16 -7
- data/lib/active_record/legacy_yaml_adapter.rb +7 -3
- data/lib/active_record/locking/optimistic.rb +33 -18
- data/lib/active_record/locking/pessimistic.rb +6 -2
- data/lib/active_record/log_subscriber.rb +28 -9
- data/lib/active_record/middleware/database_selector.rb +4 -2
- data/lib/active_record/middleware/database_selector/resolver.rb +14 -14
- data/lib/active_record/middleware/database_selector/resolver/session.rb +3 -0
- data/lib/active_record/migration.rb +115 -85
- data/lib/active_record/migration/command_recorder.rb +53 -45
- data/lib/active_record/migration/compatibility.rb +71 -20
- data/lib/active_record/migration/join_table.rb +0 -1
- data/lib/active_record/model_schema.rb +120 -15
- data/lib/active_record/nested_attributes.rb +2 -5
- data/lib/active_record/no_touching.rb +1 -1
- data/lib/active_record/null_relation.rb +0 -1
- data/lib/active_record/persistence.rb +50 -46
- data/lib/active_record/query_cache.rb +15 -5
- data/lib/active_record/querying.rb +12 -7
- data/lib/active_record/railtie.rb +65 -45
- data/lib/active_record/railties/console_sandbox.rb +2 -4
- data/lib/active_record/railties/databases.rake +277 -97
- data/lib/active_record/readonly_attributes.rb +4 -0
- data/lib/active_record/reflection.rb +77 -63
- data/lib/active_record/relation.rb +107 -67
- data/lib/active_record/relation/batches.rb +38 -32
- data/lib/active_record/relation/batches/batch_enumerator.rb +25 -9
- data/lib/active_record/relation/calculations.rb +102 -45
- data/lib/active_record/relation/delegation.rb +9 -7
- data/lib/active_record/relation/finder_methods.rb +55 -17
- data/lib/active_record/relation/from_clause.rb +5 -1
- data/lib/active_record/relation/merger.rb +27 -26
- data/lib/active_record/relation/predicate_builder.rb +59 -40
- data/lib/active_record/relation/predicate_builder/array_handler.rb +8 -9
- data/lib/active_record/relation/predicate_builder/association_query_value.rb +4 -5
- data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +10 -6
- data/lib/active_record/relation/predicate_builder/relation_handler.rb +1 -1
- data/lib/active_record/relation/query_methods.rb +343 -180
- data/lib/active_record/relation/record_fetch_warning.rb +3 -3
- data/lib/active_record/relation/spawn_methods.rb +8 -8
- data/lib/active_record/relation/where_clause.rb +107 -61
- data/lib/active_record/result.rb +41 -34
- data/lib/active_record/runtime_registry.rb +2 -2
- data/lib/active_record/sanitization.rb +6 -17
- data/lib/active_record/schema_dumper.rb +34 -4
- data/lib/active_record/schema_migration.rb +2 -8
- data/lib/active_record/scoping.rb +0 -1
- data/lib/active_record/scoping/default.rb +0 -1
- data/lib/active_record/scoping/named.rb +7 -18
- data/lib/active_record/secure_token.rb +16 -8
- data/lib/active_record/serialization.rb +5 -3
- data/lib/active_record/signed_id.rb +116 -0
- data/lib/active_record/statement_cache.rb +20 -4
- data/lib/active_record/store.rb +3 -3
- data/lib/active_record/suppressor.rb +2 -2
- data/lib/active_record/table_metadata.rb +42 -36
- data/lib/active_record/tasks/database_tasks.rb +140 -113
- data/lib/active_record/tasks/mysql_database_tasks.rb +34 -36
- data/lib/active_record/tasks/postgresql_database_tasks.rb +24 -27
- data/lib/active_record/tasks/sqlite_database_tasks.rb +13 -10
- data/lib/active_record/test_databases.rb +5 -4
- data/lib/active_record/test_fixtures.rb +38 -16
- data/lib/active_record/timestamp.rb +4 -7
- data/lib/active_record/touch_later.rb +20 -21
- data/lib/active_record/transactions.rb +26 -73
- data/lib/active_record/type.rb +8 -2
- data/lib/active_record/type/adapter_specific_registry.rb +2 -5
- data/lib/active_record/type/hash_lookup_type_map.rb +0 -1
- data/lib/active_record/type/serialized.rb +6 -3
- data/lib/active_record/type/time.rb +10 -0
- data/lib/active_record/type/type_map.rb +0 -1
- data/lib/active_record/type/unsigned_integer.rb +0 -1
- data/lib/active_record/type_caster/connection.rb +0 -1
- data/lib/active_record/type_caster/map.rb +8 -5
- data/lib/active_record/validations.rb +3 -3
- data/lib/active_record/validations/associated.rb +1 -2
- data/lib/active_record/validations/numericality.rb +35 -0
- data/lib/active_record/validations/uniqueness.rb +24 -4
- data/lib/arel.rb +15 -12
- data/lib/arel/attributes/attribute.rb +4 -0
- data/lib/arel/collectors/bind.rb +5 -0
- data/lib/arel/collectors/composite.rb +8 -0
- data/lib/arel/collectors/sql_string.rb +7 -0
- data/lib/arel/collectors/substitute_binds.rb +7 -0
- data/lib/arel/nodes.rb +3 -1
- data/lib/arel/nodes/binary.rb +82 -8
- data/lib/arel/nodes/bind_param.rb +8 -0
- data/lib/arel/nodes/casted.rb +21 -9
- data/lib/arel/nodes/equality.rb +6 -9
- data/lib/arel/nodes/grouping.rb +3 -0
- data/lib/arel/nodes/homogeneous_in.rb +72 -0
- data/lib/arel/nodes/in.rb +8 -1
- data/lib/arel/nodes/infix_operation.rb +13 -1
- data/lib/arel/nodes/join_source.rb +1 -1
- data/lib/arel/nodes/node.rb +7 -6
- data/lib/arel/nodes/ordering.rb +27 -0
- data/lib/arel/nodes/sql_literal.rb +3 -0
- data/lib/arel/nodes/table_alias.rb +7 -3
- data/lib/arel/nodes/unary.rb +0 -1
- data/lib/arel/predications.rb +17 -24
- data/lib/arel/select_manager.rb +1 -2
- data/lib/arel/table.rb +13 -5
- data/lib/arel/visitors.rb +0 -7
- data/lib/arel/visitors/dot.rb +14 -3
- data/lib/arel/visitors/mysql.rb +11 -1
- data/lib/arel/visitors/postgresql.rb +15 -5
- data/lib/arel/visitors/sqlite.rb +0 -1
- data/lib/arel/visitors/to_sql.rb +89 -79
- data/lib/arel/visitors/visitor.rb +0 -1
- data/lib/rails/generators/active_record/application_record/application_record_generator.rb +0 -1
- data/lib/rails/generators/active_record/migration.rb +6 -2
- data/lib/rails/generators/active_record/migration/migration_generator.rb +1 -0
- data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb.tt +2 -0
- data/lib/rails/generators/active_record/migration/templates/migration.rb.tt +4 -4
- data/lib/rails/generators/active_record/model/model_generator.rb +38 -2
- data/lib/rails/generators/active_record/model/templates/abstract_base_class.rb.tt +7 -0
- metadata +30 -27
- data/lib/active_record/attribute_decorators.rb +0 -90
- data/lib/active_record/connection_adapters/connection_specification.rb +0 -297
- data/lib/active_record/connection_adapters/determine_if_preparable_visitor.rb +0 -29
- data/lib/active_record/define_callbacks.rb +0 -22
- data/lib/active_record/railties/collection_cache_association_loading.rb +0 -34
- data/lib/active_record/relation/predicate_builder/base_handler.rb +0 -18
- data/lib/active_record/relation/where_clause_factory.rb +0 -33
- data/lib/arel/attributes.rb +0 -22
- data/lib/arel/visitors/depth_first.rb +0 -204
- data/lib/arel/visitors/ibm_db.rb +0 -34
- data/lib/arel/visitors/informix.rb +0 -62
- data/lib/arel/visitors/mssql.rb +0 -157
- data/lib/arel/visitors/oracle.rb +0 -159
- data/lib/arel/visitors/oracle12.rb +0 -66
- data/lib/arel/visitors/where_sql.rb +0 -23
@@ -43,13 +43,13 @@ module ActiveRecord
|
|
43
43
|
# The validation context can be changed by passing <tt>context: context</tt>.
|
44
44
|
# The regular {ActiveRecord::Base#save}[rdoc-ref:Persistence#save] method is replaced
|
45
45
|
# with this when the validations module is mixed in, which it is by default.
|
46
|
-
def save(options
|
46
|
+
def save(**options)
|
47
47
|
perform_validations(options) ? super : false
|
48
48
|
end
|
49
49
|
|
50
50
|
# Attempts to save the record just like {ActiveRecord::Base#save}[rdoc-ref:Base#save] but
|
51
51
|
# will raise an ActiveRecord::RecordInvalid exception instead of returning +false+ if the record is not valid.
|
52
|
-
def save!(options
|
52
|
+
def save!(**options)
|
53
53
|
perform_validations(options) ? super : raise_validation_error
|
54
54
|
end
|
55
55
|
|
@@ -72,7 +72,6 @@ module ActiveRecord
|
|
72
72
|
alias_method :validate, :valid?
|
73
73
|
|
74
74
|
private
|
75
|
-
|
76
75
|
def default_validation_context
|
77
76
|
new_record? ? :create : :update
|
78
77
|
end
|
@@ -92,3 +91,4 @@ require "active_record/validations/uniqueness"
|
|
92
91
|
require "active_record/validations/presence"
|
93
92
|
require "active_record/validations/absence"
|
94
93
|
require "active_record/validations/length"
|
94
|
+
require "active_record/validations/numericality"
|
@@ -5,12 +5,11 @@ module ActiveRecord
|
|
5
5
|
class AssociatedValidator < ActiveModel::EachValidator #:nodoc:
|
6
6
|
def validate_each(record, attribute, value)
|
7
7
|
if Array(value).reject { |r| valid_object?(r) }.any?
|
8
|
-
record.errors.add(attribute, :invalid, options.merge(value: value))
|
8
|
+
record.errors.add(attribute, :invalid, **options.merge(value: value))
|
9
9
|
end
|
10
10
|
end
|
11
11
|
|
12
12
|
private
|
13
|
-
|
14
13
|
def valid_object?(record)
|
15
14
|
(record.respond_to?(:marked_for_destruction?) && record.marked_for_destruction?) || record.valid?
|
16
15
|
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ActiveRecord
|
4
|
+
module Validations
|
5
|
+
class NumericalityValidator < ActiveModel::Validations::NumericalityValidator # :nodoc:
|
6
|
+
def validate_each(record, attribute, value, precision: nil, scale: nil)
|
7
|
+
precision = [column_precision_for(record, attribute) || BigDecimal.double_fig, BigDecimal.double_fig].min
|
8
|
+
scale = column_scale_for(record, attribute)
|
9
|
+
super(record, attribute, value, precision: precision, scale: scale)
|
10
|
+
end
|
11
|
+
|
12
|
+
private
|
13
|
+
def column_precision_for(record, attribute)
|
14
|
+
record.class.type_for_attribute(attribute.to_s)&.precision
|
15
|
+
end
|
16
|
+
|
17
|
+
def column_scale_for(record, attribute)
|
18
|
+
record.class.type_for_attribute(attribute.to_s)&.scale
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
module ClassMethods
|
23
|
+
# Validates whether the value of the specified attribute is numeric by
|
24
|
+
# trying to convert it to a float with Kernel.Float (if <tt>only_integer</tt>
|
25
|
+
# is +false+) or applying it to the regular expression <tt>/\A[\+\-]?\d+\z/</tt>
|
26
|
+
# (if <tt>only_integer</tt> is set to +true+). Kernel.Float precision
|
27
|
+
# defaults to the column's precision value or 15.
|
28
|
+
#
|
29
|
+
# See ActiveModel::Validations::HelperMethods.validates_numericality_of for more information.
|
30
|
+
def validates_numericality_of(*attr_names)
|
31
|
+
validates_with NumericalityValidator, _merge_attributes(attr_names)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -29,13 +29,22 @@ module ActiveRecord
|
|
29
29
|
end
|
30
30
|
end
|
31
31
|
relation = scope_relation(record, relation)
|
32
|
-
|
32
|
+
|
33
|
+
if options[:conditions]
|
34
|
+
conditions = options[:conditions]
|
35
|
+
|
36
|
+
relation = if conditions.arity.zero?
|
37
|
+
relation.instance_exec(&conditions)
|
38
|
+
else
|
39
|
+
relation.instance_exec(record, &conditions)
|
40
|
+
end
|
41
|
+
end
|
33
42
|
|
34
43
|
if relation.exists?
|
35
44
|
error_options = options.except(:case_sensitive, :scope, :conditions)
|
36
45
|
error_options[:value] = value
|
37
46
|
|
38
|
-
record.errors.add(attribute, :taken, error_options)
|
47
|
+
record.errors.add(attribute, :taken, **error_options)
|
39
48
|
end
|
40
49
|
end
|
41
50
|
|
@@ -61,7 +70,7 @@ module ActiveRecord
|
|
61
70
|
return relation.none! if bind.unboundable?
|
62
71
|
|
63
72
|
if !options.key?(:case_sensitive) || bind.nil?
|
64
|
-
klass.connection.default_uniqueness_comparison(attr, bind
|
73
|
+
klass.connection.default_uniqueness_comparison(attr, bind)
|
65
74
|
elsif options[:case_sensitive]
|
66
75
|
klass.connection.case_sensitive_comparison(attr, bind)
|
67
76
|
else
|
@@ -78,7 +87,7 @@ module ActiveRecord
|
|
78
87
|
scope_value = if record.class._reflect_on_association(scope_item)
|
79
88
|
record.association(scope_item).reader
|
80
89
|
else
|
81
|
-
record.
|
90
|
+
record.read_attribute(scope_item)
|
82
91
|
end
|
83
92
|
relation = relation.where(scope_item => scope_value)
|
84
93
|
end
|
@@ -126,6 +135,17 @@ module ActiveRecord
|
|
126
135
|
# validates_uniqueness_of :title, conditions: -> { where.not(status: 'archived') }
|
127
136
|
# end
|
128
137
|
#
|
138
|
+
# To build conditions based on the record's state, define the conditions
|
139
|
+
# callable with a parameter, which will be the record itself. This
|
140
|
+
# example validates the title is unique for the year of publication:
|
141
|
+
#
|
142
|
+
# class Article < ActiveRecord::Base
|
143
|
+
# validates_uniqueness_of :title, conditions: ->(article) {
|
144
|
+
# published_at = article.published_at
|
145
|
+
# where(published_at: published_at.beginning_of_year..published_at.end_of_year)
|
146
|
+
# }
|
147
|
+
# end
|
148
|
+
#
|
129
149
|
# When the record is created, a check is performed to make sure that no
|
130
150
|
# record exists in the database with the given value for the specified
|
131
151
|
# attribute (that maps to a column). When the record is updated,
|
data/lib/arel.rb
CHANGED
@@ -12,7 +12,7 @@ require "arel/math"
|
|
12
12
|
require "arel/alias_predication"
|
13
13
|
require "arel/order_predications"
|
14
14
|
require "arel/table"
|
15
|
-
require "arel/attributes"
|
15
|
+
require "arel/attributes/attribute"
|
16
16
|
|
17
17
|
require "arel/visitors"
|
18
18
|
require "arel/collectors/sql_string"
|
@@ -24,28 +24,31 @@ require "arel/update_manager"
|
|
24
24
|
require "arel/delete_manager"
|
25
25
|
require "arel/nodes"
|
26
26
|
|
27
|
-
module Arel
|
27
|
+
module Arel
|
28
28
|
VERSION = "10.0.0"
|
29
29
|
|
30
|
+
# Wrap a known-safe SQL string for passing to query methods, e.g.
|
31
|
+
#
|
32
|
+
# Post.order(Arel.sql("length(title)")).last
|
33
|
+
#
|
34
|
+
# Great caution should be taken to avoid SQL injection vulnerabilities.
|
35
|
+
# This method should not be used with unsafe values such as request
|
36
|
+
# parameters or model attributes.
|
30
37
|
def self.sql(raw_sql)
|
31
38
|
Arel::Nodes::SqlLiteral.new raw_sql
|
32
39
|
end
|
33
40
|
|
34
|
-
def self.star
|
41
|
+
def self.star # :nodoc:
|
35
42
|
sql "*"
|
36
43
|
end
|
37
44
|
|
38
|
-
def self.arel_node?(value)
|
39
|
-
value.is_a?(Arel::Node) || value.is_a?(Arel::Attribute) || value.is_a?(Arel::Nodes::SqlLiteral)
|
45
|
+
def self.arel_node?(value) # :nodoc:
|
46
|
+
value.is_a?(Arel::Nodes::Node) || value.is_a?(Arel::Attribute) || value.is_a?(Arel::Nodes::SqlLiteral)
|
40
47
|
end
|
41
48
|
|
42
|
-
def self.fetch_attribute(value)
|
43
|
-
|
44
|
-
|
45
|
-
yield value.left.is_a?(Arel::Attributes::Attribute) ? value.left : value.right
|
49
|
+
def self.fetch_attribute(value, &block) # :nodoc:
|
50
|
+
unless String === value
|
51
|
+
value.fetch_attribute(&block)
|
46
52
|
end
|
47
53
|
end
|
48
|
-
|
49
|
-
## Convenience Alias
|
50
|
-
Node = Arel::Nodes::Node
|
51
54
|
end
|
data/lib/arel/collectors/bind.rb
CHANGED
@@ -3,6 +3,8 @@
|
|
3
3
|
module Arel # :nodoc: all
|
4
4
|
module Collectors
|
5
5
|
class Composite
|
6
|
+
attr_accessor :preparable
|
7
|
+
|
6
8
|
def initialize(left, right)
|
7
9
|
@left = left
|
8
10
|
@right = right
|
@@ -20,6 +22,12 @@ module Arel # :nodoc: all
|
|
20
22
|
self
|
21
23
|
end
|
22
24
|
|
25
|
+
def add_binds(binds, &block)
|
26
|
+
left.add_binds(binds, &block)
|
27
|
+
right.add_binds(binds, &block)
|
28
|
+
self
|
29
|
+
end
|
30
|
+
|
23
31
|
def value
|
24
32
|
[left.value, right.value]
|
25
33
|
end
|
@@ -5,6 +5,8 @@ require "arel/collectors/plain_string"
|
|
5
5
|
module Arel # :nodoc: all
|
6
6
|
module Collectors
|
7
7
|
class SQLString < PlainString
|
8
|
+
attr_accessor :preparable
|
9
|
+
|
8
10
|
def initialize(*)
|
9
11
|
super
|
10
12
|
@bind_index = 1
|
@@ -15,6 +17,11 @@ module Arel # :nodoc: all
|
|
15
17
|
@bind_index += 1
|
16
18
|
self
|
17
19
|
end
|
20
|
+
|
21
|
+
def add_binds(binds, &block)
|
22
|
+
self << (@bind_index...@bind_index += binds.size).map(&block).join(", ")
|
23
|
+
self
|
24
|
+
end
|
18
25
|
end
|
19
26
|
end
|
20
27
|
end
|
@@ -3,6 +3,8 @@
|
|
3
3
|
module Arel # :nodoc: all
|
4
4
|
module Collectors
|
5
5
|
class SubstituteBinds
|
6
|
+
attr_accessor :preparable
|
7
|
+
|
6
8
|
def initialize(quoter, delegate_collector)
|
7
9
|
@quoter = quoter
|
8
10
|
@delegate = delegate_collector
|
@@ -14,9 +16,14 @@ module Arel # :nodoc: all
|
|
14
16
|
end
|
15
17
|
|
16
18
|
def add_bind(bind)
|
19
|
+
bind = bind.value_for_database if bind.respond_to?(:value_for_database)
|
17
20
|
self << quoter.quote(bind)
|
18
21
|
end
|
19
22
|
|
23
|
+
def add_binds(binds)
|
24
|
+
self << binds.map { |bind| quoter.quote(bind) }.join(", ")
|
25
|
+
end
|
26
|
+
|
20
27
|
def value
|
21
28
|
delegate.value
|
22
29
|
end
|
data/lib/arel/nodes.rb
CHANGED
@@ -18,6 +18,8 @@ require "arel/nodes/false"
|
|
18
18
|
# unary
|
19
19
|
require "arel/nodes/unary"
|
20
20
|
require "arel/nodes/grouping"
|
21
|
+
require "arel/nodes/homogeneous_in"
|
22
|
+
require "arel/nodes/ordering"
|
21
23
|
require "arel/nodes/ascending"
|
22
24
|
require "arel/nodes/descending"
|
23
25
|
require "arel/nodes/unqualified_column"
|
@@ -26,7 +28,7 @@ require "arel/nodes/with"
|
|
26
28
|
# binary
|
27
29
|
require "arel/nodes/binary"
|
28
30
|
require "arel/nodes/equality"
|
29
|
-
require "arel/nodes/in"
|
31
|
+
require "arel/nodes/in"
|
30
32
|
require "arel/nodes/join_source"
|
31
33
|
require "arel/nodes/delete_statement"
|
32
34
|
require "arel/nodes/table_alias"
|
data/lib/arel/nodes/binary.rb
CHANGED
@@ -29,18 +29,92 @@ module Arel # :nodoc: all
|
|
29
29
|
alias :== :eql?
|
30
30
|
end
|
31
31
|
|
32
|
+
module FetchAttribute
|
33
|
+
def fetch_attribute
|
34
|
+
if left.is_a?(Arel::Attributes::Attribute)
|
35
|
+
yield left
|
36
|
+
elsif right.is_a?(Arel::Attributes::Attribute)
|
37
|
+
yield right
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
class Between < Binary; include FetchAttribute; end
|
43
|
+
|
44
|
+
class GreaterThan < Binary
|
45
|
+
include FetchAttribute
|
46
|
+
|
47
|
+
def invert
|
48
|
+
Arel::Nodes::LessThanOrEqual.new(left, right)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
class GreaterThanOrEqual < Binary
|
53
|
+
include FetchAttribute
|
54
|
+
|
55
|
+
def invert
|
56
|
+
Arel::Nodes::LessThan.new(left, right)
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
class LessThan < Binary
|
61
|
+
include FetchAttribute
|
62
|
+
|
63
|
+
def invert
|
64
|
+
Arel::Nodes::GreaterThanOrEqual.new(left, right)
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
class LessThanOrEqual < Binary
|
69
|
+
include FetchAttribute
|
70
|
+
|
71
|
+
def invert
|
72
|
+
Arel::Nodes::GreaterThan.new(left, right)
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
class IsDistinctFrom < Binary
|
77
|
+
include FetchAttribute
|
78
|
+
|
79
|
+
def invert
|
80
|
+
Arel::Nodes::IsNotDistinctFrom.new(left, right)
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
class IsNotDistinctFrom < Binary
|
85
|
+
include FetchAttribute
|
86
|
+
|
87
|
+
def invert
|
88
|
+
Arel::Nodes::IsDistinctFrom.new(left, right)
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
class NotEqual < Binary
|
93
|
+
include FetchAttribute
|
94
|
+
|
95
|
+
def invert
|
96
|
+
Arel::Nodes::Equality.new(left, right)
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
class NotIn < Binary
|
101
|
+
include FetchAttribute
|
102
|
+
|
103
|
+
def invert
|
104
|
+
Arel::Nodes::In.new(left, right)
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
class Or < Binary
|
109
|
+
def fetch_attribute(&block)
|
110
|
+
left.fetch_attribute(&block) && right.fetch_attribute(&block)
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
32
114
|
%w{
|
33
115
|
As
|
34
116
|
Assignment
|
35
|
-
Between
|
36
|
-
GreaterThan
|
37
|
-
GreaterThanOrEqual
|
38
117
|
Join
|
39
|
-
LessThan
|
40
|
-
LessThanOrEqual
|
41
|
-
NotEqual
|
42
|
-
NotIn
|
43
|
-
Or
|
44
118
|
Union
|
45
119
|
UnionAll
|
46
120
|
Intersect
|
@@ -24,6 +24,14 @@ module Arel # :nodoc: all
|
|
24
24
|
value.nil?
|
25
25
|
end
|
26
26
|
|
27
|
+
def value_before_type_cast
|
28
|
+
if value.respond_to?(:value_before_type_cast)
|
29
|
+
value.value_before_type_cast
|
30
|
+
else
|
31
|
+
value
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
27
35
|
def infinite?
|
28
36
|
value.respond_to?(:infinite?) && value.infinite?
|
29
37
|
end
|
data/lib/arel/nodes/casted.rb
CHANGED
@@ -3,30 +3,42 @@
|
|
3
3
|
module Arel # :nodoc: all
|
4
4
|
module Nodes
|
5
5
|
class Casted < Arel::Nodes::NodeExpression # :nodoc:
|
6
|
-
attr_reader :
|
7
|
-
|
8
|
-
|
6
|
+
attr_reader :value, :attribute
|
7
|
+
alias :value_before_type_cast :value
|
8
|
+
|
9
|
+
def initialize(value, attribute)
|
10
|
+
@value = value
|
9
11
|
@attribute = attribute
|
10
12
|
super()
|
11
13
|
end
|
12
14
|
|
13
|
-
def nil?;
|
15
|
+
def nil?; value.nil?; end
|
16
|
+
|
17
|
+
def value_for_database
|
18
|
+
if attribute.able_to_type_cast?
|
19
|
+
attribute.type_cast_for_database(value)
|
20
|
+
else
|
21
|
+
value
|
22
|
+
end
|
23
|
+
end
|
14
24
|
|
15
25
|
def hash
|
16
|
-
[self.class,
|
26
|
+
[self.class, value, attribute].hash
|
17
27
|
end
|
18
28
|
|
19
29
|
def eql?(other)
|
20
30
|
self.class == other.class &&
|
21
|
-
|
22
|
-
|
31
|
+
self.value == other.value &&
|
32
|
+
self.attribute == other.attribute
|
23
33
|
end
|
24
34
|
alias :== :eql?
|
25
35
|
end
|
26
36
|
|
27
37
|
class Quoted < Arel::Nodes::Unary # :nodoc:
|
28
|
-
alias :
|
29
|
-
|
38
|
+
alias :value_for_database :value
|
39
|
+
alias :value_before_type_cast :value
|
40
|
+
|
41
|
+
def nil?; value.nil?; end
|
30
42
|
|
31
43
|
def infinite?
|
32
44
|
value.respond_to?(:infinite?) && value.infinite?
|