activerecord 4.2.11.3 → 5.0.7.2
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 +1638 -1132
- data/MIT-LICENSE +2 -2
- data/README.rdoc +7 -8
- data/examples/performance.rb +2 -3
- data/examples/simple.rb +0 -1
- data/lib/active_record.rb +7 -2
- data/lib/active_record/aggregations.rb +34 -21
- data/lib/active_record/association_relation.rb +7 -4
- data/lib/active_record/associations.rb +347 -218
- data/lib/active_record/associations/alias_tracker.rb +19 -16
- data/lib/active_record/associations/association.rb +22 -10
- data/lib/active_record/associations/association_scope.rb +75 -104
- data/lib/active_record/associations/belongs_to_association.rb +21 -32
- data/lib/active_record/associations/builder/association.rb +28 -34
- data/lib/active_record/associations/builder/belongs_to.rb +43 -18
- data/lib/active_record/associations/builder/collection_association.rb +7 -19
- data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +16 -11
- data/lib/active_record/associations/builder/has_many.rb +4 -4
- data/lib/active_record/associations/builder/has_one.rb +11 -6
- data/lib/active_record/associations/builder/singular_association.rb +13 -11
- data/lib/active_record/associations/collection_association.rb +85 -69
- data/lib/active_record/associations/collection_proxy.rb +104 -46
- data/lib/active_record/associations/foreign_association.rb +1 -1
- data/lib/active_record/associations/has_many_association.rb +21 -78
- data/lib/active_record/associations/has_many_through_association.rb +6 -47
- data/lib/active_record/associations/has_one_association.rb +12 -5
- data/lib/active_record/associations/join_dependency.rb +38 -22
- data/lib/active_record/associations/join_dependency/join_association.rb +15 -14
- data/lib/active_record/associations/join_dependency/join_part.rb +2 -2
- data/lib/active_record/associations/preloader.rb +14 -4
- data/lib/active_record/associations/preloader/association.rb +52 -71
- data/lib/active_record/associations/preloader/collection_association.rb +0 -7
- data/lib/active_record/associations/preloader/has_many_through.rb +1 -1
- data/lib/active_record/associations/preloader/has_one.rb +0 -8
- data/lib/active_record/associations/preloader/singular_association.rb +0 -1
- data/lib/active_record/associations/preloader/through_association.rb +36 -17
- data/lib/active_record/associations/singular_association.rb +13 -1
- data/lib/active_record/associations/through_association.rb +12 -4
- data/lib/active_record/attribute.rb +69 -19
- data/lib/active_record/attribute/user_provided_default.rb +28 -0
- data/lib/active_record/attribute_assignment.rb +19 -140
- data/lib/active_record/attribute_decorators.rb +6 -5
- data/lib/active_record/attribute_methods.rb +69 -44
- data/lib/active_record/attribute_methods/before_type_cast.rb +1 -1
- data/lib/active_record/attribute_methods/dirty.rb +46 -86
- data/lib/active_record/attribute_methods/primary_key.rb +16 -3
- data/lib/active_record/attribute_methods/query.rb +2 -2
- data/lib/active_record/attribute_methods/read.rb +31 -59
- data/lib/active_record/attribute_methods/serialization.rb +13 -16
- data/lib/active_record/attribute_methods/time_zone_conversion.rb +61 -14
- data/lib/active_record/attribute_methods/write.rb +13 -37
- data/lib/active_record/attribute_mutation_tracker.rb +70 -0
- data/lib/active_record/attribute_set.rb +32 -3
- data/lib/active_record/attribute_set/builder.rb +42 -16
- data/lib/active_record/attributes.rb +199 -81
- data/lib/active_record/autosave_association.rb +54 -17
- data/lib/active_record/base.rb +32 -23
- data/lib/active_record/callbacks.rb +39 -43
- data/lib/active_record/coders/json.rb +1 -1
- data/lib/active_record/coders/yaml_column.rb +20 -8
- data/lib/active_record/collection_cache_key.rb +50 -0
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +467 -189
- data/lib/active_record/connection_adapters/abstract/database_limits.rb +3 -3
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +66 -62
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +39 -4
- data/lib/active_record/connection_adapters/abstract/quoting.rb +86 -13
- data/lib/active_record/connection_adapters/abstract/savepoints.rb +3 -3
- data/lib/active_record/connection_adapters/abstract/schema_creation.rb +61 -39
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +236 -188
- data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +72 -17
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +407 -156
- data/lib/active_record/connection_adapters/abstract/transaction.rb +51 -34
- data/lib/active_record/connection_adapters/abstract_adapter.rb +177 -71
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +433 -399
- data/lib/active_record/connection_adapters/column.rb +28 -43
- data/lib/active_record/connection_adapters/connection_specification.rb +15 -27
- data/lib/active_record/connection_adapters/determine_if_preparable_visitor.rb +22 -0
- data/lib/active_record/connection_adapters/mysql/column.rb +50 -0
- data/lib/active_record/connection_adapters/mysql/database_statements.rb +108 -0
- data/lib/active_record/connection_adapters/mysql/explain_pretty_printer.rb +70 -0
- data/lib/active_record/connection_adapters/mysql/quoting.rb +51 -0
- data/lib/active_record/connection_adapters/mysql/schema_creation.rb +67 -0
- data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +93 -0
- data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +54 -0
- data/lib/active_record/connection_adapters/mysql/type_metadata.rb +32 -0
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +25 -166
- data/lib/active_record/connection_adapters/postgresql/column.rb +33 -11
- data/lib/active_record/connection_adapters/postgresql/database_statements.rb +18 -72
- data/lib/active_record/connection_adapters/postgresql/explain_pretty_printer.rb +42 -0
- data/lib/active_record/connection_adapters/postgresql/oid.rb +1 -6
- data/lib/active_record/connection_adapters/postgresql/oid/array.rb +37 -57
- data/lib/active_record/connection_adapters/postgresql/oid/bit.rb +3 -3
- data/lib/active_record/connection_adapters/postgresql/oid/bytea.rb +2 -2
- data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +3 -1
- data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +7 -22
- data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +13 -3
- data/lib/active_record/connection_adapters/postgresql/oid/json.rb +1 -26
- data/lib/active_record/connection_adapters/postgresql/oid/jsonb.rb +2 -2
- data/lib/active_record/connection_adapters/postgresql/oid/money.rb +0 -4
- data/lib/active_record/connection_adapters/postgresql/oid/point.rb +4 -4
- data/lib/active_record/connection_adapters/postgresql/oid/rails_5_1_point.rb +50 -0
- data/lib/active_record/connection_adapters/postgresql/oid/range.rb +31 -17
- data/lib/active_record/connection_adapters/postgresql/oid/specialized_string.rb +0 -4
- data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +2 -2
- data/lib/active_record/connection_adapters/postgresql/oid/vector.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/oid/xml.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/quoting.rb +56 -19
- data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +29 -10
- data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +107 -79
- data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +47 -0
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +250 -154
- data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +35 -0
- data/lib/active_record/connection_adapters/postgresql/utils.rb +2 -2
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +264 -170
- data/lib/active_record/connection_adapters/schema_cache.rb +36 -23
- data/lib/active_record/connection_adapters/sql_type_metadata.rb +32 -0
- data/lib/active_record/connection_adapters/sqlite3/explain_pretty_printer.rb +19 -0
- data/lib/active_record/connection_adapters/sqlite3/quoting.rb +48 -0
- data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +22 -0
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +151 -194
- data/lib/active_record/connection_adapters/statement_pool.rb +31 -12
- data/lib/active_record/connection_handling.rb +37 -14
- data/lib/active_record/core.rb +92 -108
- data/lib/active_record/counter_cache.rb +13 -24
- data/lib/active_record/dynamic_matchers.rb +1 -20
- data/lib/active_record/enum.rb +116 -76
- data/lib/active_record/errors.rb +87 -48
- data/lib/active_record/explain.rb +20 -9
- data/lib/active_record/explain_registry.rb +1 -1
- data/lib/active_record/explain_subscriber.rb +1 -1
- data/lib/active_record/fixture_set/file.rb +26 -5
- data/lib/active_record/fixtures.rb +77 -41
- data/lib/active_record/gem_version.rb +4 -4
- data/lib/active_record/inheritance.rb +32 -40
- data/lib/active_record/integration.rb +17 -14
- data/lib/active_record/internal_metadata.rb +56 -0
- data/lib/active_record/legacy_yaml_adapter.rb +18 -2
- data/lib/active_record/locale/en.yml +3 -2
- data/lib/active_record/locking/optimistic.rb +15 -15
- data/lib/active_record/locking/pessimistic.rb +1 -1
- data/lib/active_record/log_subscriber.rb +48 -24
- data/lib/active_record/migration.rb +362 -111
- data/lib/active_record/migration/command_recorder.rb +59 -18
- data/lib/active_record/migration/compatibility.rb +126 -0
- data/lib/active_record/model_schema.rb +270 -73
- data/lib/active_record/nested_attributes.rb +58 -29
- data/lib/active_record/no_touching.rb +4 -0
- data/lib/active_record/null_relation.rb +16 -8
- data/lib/active_record/persistence.rb +152 -90
- data/lib/active_record/query_cache.rb +18 -23
- data/lib/active_record/querying.rb +12 -11
- data/lib/active_record/railtie.rb +23 -16
- data/lib/active_record/railties/controller_runtime.rb +1 -1
- data/lib/active_record/railties/databases.rake +52 -41
- data/lib/active_record/readonly_attributes.rb +1 -1
- data/lib/active_record/reflection.rb +302 -115
- data/lib/active_record/relation.rb +187 -120
- data/lib/active_record/relation/batches.rb +141 -36
- data/lib/active_record/relation/batches/batch_enumerator.rb +67 -0
- data/lib/active_record/relation/calculations.rb +92 -117
- data/lib/active_record/relation/delegation.rb +8 -20
- data/lib/active_record/relation/finder_methods.rb +173 -89
- data/lib/active_record/relation/from_clause.rb +32 -0
- data/lib/active_record/relation/merger.rb +16 -42
- data/lib/active_record/relation/predicate_builder.rb +120 -107
- data/lib/active_record/relation/predicate_builder/array_handler.rb +11 -16
- data/lib/active_record/relation/predicate_builder/association_query_handler.rb +88 -0
- data/lib/active_record/relation/predicate_builder/base_handler.rb +17 -0
- data/lib/active_record/relation/predicate_builder/basic_object_handler.rb +17 -0
- data/lib/active_record/relation/predicate_builder/class_handler.rb +27 -0
- data/lib/active_record/relation/predicate_builder/polymorphic_array_handler.rb +57 -0
- data/lib/active_record/relation/predicate_builder/range_handler.rb +33 -0
- data/lib/active_record/relation/predicate_builder/relation_handler.rb +1 -1
- data/lib/active_record/relation/query_attribute.rb +19 -0
- data/lib/active_record/relation/query_methods.rb +308 -244
- data/lib/active_record/relation/record_fetch_warning.rb +49 -0
- data/lib/active_record/relation/spawn_methods.rb +4 -7
- data/lib/active_record/relation/where_clause.rb +174 -0
- data/lib/active_record/relation/where_clause_factory.rb +38 -0
- data/lib/active_record/result.rb +11 -4
- data/lib/active_record/runtime_registry.rb +1 -1
- data/lib/active_record/sanitization.rb +105 -66
- data/lib/active_record/schema.rb +26 -22
- data/lib/active_record/schema_dumper.rb +54 -37
- data/lib/active_record/schema_migration.rb +11 -14
- data/lib/active_record/scoping.rb +34 -16
- data/lib/active_record/scoping/default.rb +28 -10
- data/lib/active_record/scoping/named.rb +59 -26
- data/lib/active_record/secure_token.rb +38 -0
- data/lib/active_record/serialization.rb +3 -5
- data/lib/active_record/statement_cache.rb +17 -15
- data/lib/active_record/store.rb +8 -3
- data/lib/active_record/suppressor.rb +58 -0
- data/lib/active_record/table_metadata.rb +69 -0
- data/lib/active_record/tasks/database_tasks.rb +66 -49
- data/lib/active_record/tasks/mysql_database_tasks.rb +6 -14
- data/lib/active_record/tasks/postgresql_database_tasks.rb +12 -3
- data/lib/active_record/tasks/sqlite_database_tasks.rb +5 -1
- data/lib/active_record/timestamp.rb +20 -9
- data/lib/active_record/touch_later.rb +63 -0
- data/lib/active_record/transactions.rb +139 -57
- data/lib/active_record/type.rb +66 -17
- data/lib/active_record/type/adapter_specific_registry.rb +130 -0
- data/lib/active_record/type/date.rb +2 -45
- data/lib/active_record/type/date_time.rb +2 -49
- data/lib/active_record/type/internal/abstract_json.rb +33 -0
- data/lib/active_record/type/internal/timezone.rb +15 -0
- data/lib/active_record/type/serialized.rb +15 -14
- data/lib/active_record/type/time.rb +10 -16
- data/lib/active_record/type/type_map.rb +4 -4
- data/lib/active_record/type_caster.rb +7 -0
- data/lib/active_record/type_caster/connection.rb +29 -0
- data/lib/active_record/type_caster/map.rb +19 -0
- data/lib/active_record/validations.rb +33 -32
- data/lib/active_record/validations/absence.rb +23 -0
- data/lib/active_record/validations/associated.rb +10 -3
- data/lib/active_record/validations/length.rb +24 -0
- data/lib/active_record/validations/presence.rb +11 -12
- data/lib/active_record/validations/uniqueness.rb +33 -33
- data/lib/rails/generators/active_record/migration.rb +15 -0
- data/lib/rails/generators/active_record/migration/migration_generator.rb +8 -5
- data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb +8 -3
- data/lib/rails/generators/active_record/migration/templates/migration.rb +8 -1
- data/lib/rails/generators/active_record/model/model_generator.rb +33 -16
- data/lib/rails/generators/active_record/model/templates/application_record.rb +5 -0
- data/lib/rails/generators/active_record/model/templates/model.rb +3 -0
- metadata +58 -34
- data/lib/active_record/connection_adapters/mysql_adapter.rb +0 -498
- data/lib/active_record/connection_adapters/postgresql/array_parser.rb +0 -93
- data/lib/active_record/connection_adapters/postgresql/oid/date.rb +0 -11
- data/lib/active_record/connection_adapters/postgresql/oid/float.rb +0 -21
- data/lib/active_record/connection_adapters/postgresql/oid/infinity.rb +0 -13
- data/lib/active_record/connection_adapters/postgresql/oid/integer.rb +0 -11
- data/lib/active_record/connection_adapters/postgresql/oid/time.rb +0 -11
- data/lib/active_record/serializers/xml_serializer.rb +0 -193
- data/lib/active_record/type/big_integer.rb +0 -13
- data/lib/active_record/type/binary.rb +0 -50
- data/lib/active_record/type/boolean.rb +0 -31
- data/lib/active_record/type/decimal.rb +0 -64
- data/lib/active_record/type/decimal_without_scale.rb +0 -11
- data/lib/active_record/type/decorator.rb +0 -14
- data/lib/active_record/type/float.rb +0 -19
- data/lib/active_record/type/integer.rb +0 -59
- data/lib/active_record/type/mutable.rb +0 -16
- data/lib/active_record/type/numeric.rb +0 -36
- data/lib/active_record/type/string.rb +0 -40
- data/lib/active_record/type/text.rb +0 -11
- data/lib/active_record/type/time_value.rb +0 -38
- data/lib/active_record/type/unsigned_integer.rb +0 -15
- data/lib/active_record/type/value.rb +0 -110
@@ -1,38 +1,39 @@
|
|
1
|
-
|
2
|
-
require 'arel/collectors/bind'
|
1
|
+
require "arel/collectors/bind"
|
3
2
|
|
4
3
|
module ActiveRecord
|
5
|
-
# = Active Record Relation
|
4
|
+
# = Active Record \Relation
|
6
5
|
class Relation
|
7
6
|
MULTI_VALUE_METHODS = [:includes, :eager_load, :preload, :select, :group,
|
8
|
-
:order, :joins, :
|
7
|
+
:order, :joins, :left_joins, :left_outer_joins, :references,
|
9
8
|
:extending, :unscope]
|
10
9
|
|
11
|
-
SINGLE_VALUE_METHODS = [:limit, :offset, :lock, :readonly, :
|
12
|
-
:reverse_order, :distinct, :create_with
|
10
|
+
SINGLE_VALUE_METHODS = [:limit, :offset, :lock, :readonly, :reordering,
|
11
|
+
:reverse_order, :distinct, :create_with]
|
12
|
+
CLAUSE_METHODS = [:where, :having, :from]
|
13
13
|
INVALID_METHODS_FOR_DELETE_ALL = [:limit, :distinct, :offset, :group, :having]
|
14
14
|
|
15
|
-
VALUE_METHODS = MULTI_VALUE_METHODS + SINGLE_VALUE_METHODS
|
15
|
+
VALUE_METHODS = MULTI_VALUE_METHODS + SINGLE_VALUE_METHODS + CLAUSE_METHODS
|
16
16
|
|
17
|
+
include Enumerable
|
17
18
|
include FinderMethods, Calculations, SpawnMethods, QueryMethods, Batches, Explain, Delegation
|
18
19
|
|
19
|
-
attr_reader :table, :klass, :loaded
|
20
|
+
attr_reader :table, :klass, :loaded, :predicate_builder
|
20
21
|
alias :model :klass
|
21
22
|
alias :loaded? :loaded
|
22
23
|
|
23
|
-
def initialize(klass, table, values = {})
|
24
|
+
def initialize(klass, table, predicate_builder, values = {})
|
24
25
|
@klass = klass
|
25
26
|
@table = table
|
26
27
|
@values = values
|
27
28
|
@offsets = {}
|
28
29
|
@loaded = false
|
30
|
+
@predicate_builder = predicate_builder
|
29
31
|
end
|
30
32
|
|
31
33
|
def initialize_copy(other)
|
32
34
|
# This method is a hot spot, so for now, use Hash[] to dup the hash.
|
33
35
|
# https://bugs.ruby-lang.org/issues/7166
|
34
36
|
@values = Hash[@values]
|
35
|
-
@values[:bind] = @values[:bind].dup if @values.key? :bind
|
36
37
|
reset
|
37
38
|
end
|
38
39
|
|
@@ -44,9 +45,9 @@ module ActiveRecord
|
|
44
45
|
k.name == primary_key
|
45
46
|
}]
|
46
47
|
|
47
|
-
if !primary_key_value &&
|
48
|
-
primary_key_value =
|
49
|
-
values[klass.
|
48
|
+
if !primary_key_value && klass.prefetch_primary_key?
|
49
|
+
primary_key_value = klass.next_sequence_value
|
50
|
+
values[arel_attribute(klass.primary_key)] = primary_key_value
|
50
51
|
end
|
51
52
|
end
|
52
53
|
|
@@ -80,7 +81,7 @@ module ActiveRecord
|
|
80
81
|
end
|
81
82
|
|
82
83
|
relation = scope.where(@klass.primary_key => (id_was || id))
|
83
|
-
bvs = binds + relation.
|
84
|
+
bvs = binds + relation.bound_attributes
|
84
85
|
um = relation
|
85
86
|
.arel
|
86
87
|
.compile_update(substitutes, @klass.primary_key)
|
@@ -93,21 +94,25 @@ module ActiveRecord
|
|
93
94
|
end
|
94
95
|
|
95
96
|
def substitute_values(values) # :nodoc:
|
96
|
-
binds =
|
97
|
-
|
98
|
-
end
|
97
|
+
binds = []
|
98
|
+
substitutes = []
|
99
99
|
|
100
|
-
|
101
|
-
|
100
|
+
values.each do |arel_attr, value|
|
101
|
+
binds.push QueryAttribute.new(arel_attr.name, value, klass.type_for_attribute(arel_attr.name))
|
102
|
+
substitutes.push [arel_attr, Arel::Nodes::BindParam.new]
|
102
103
|
end
|
103
104
|
|
104
105
|
[substitutes, binds]
|
105
106
|
end
|
106
107
|
|
108
|
+
def arel_attribute(name) # :nodoc:
|
109
|
+
klass.arel_attribute(name, table)
|
110
|
+
end
|
111
|
+
|
107
112
|
# Initializes new record from relation while maintaining the current
|
108
113
|
# scope.
|
109
114
|
#
|
110
|
-
# Expects arguments in the same format as
|
115
|
+
# Expects arguments in the same format as {ActiveRecord::Base.new}[rdoc-ref:Core.new].
|
111
116
|
#
|
112
117
|
# users = User.where(name: 'DHH')
|
113
118
|
# user = users.new # => #<User id: nil, name: "DHH", created_at: nil, updated_at: nil>
|
@@ -125,28 +130,32 @@ module ActiveRecord
|
|
125
130
|
# Tries to create a new record with the same scoped attributes
|
126
131
|
# defined in the relation. Returns the initialized object if validation fails.
|
127
132
|
#
|
128
|
-
# Expects arguments in the same format as
|
133
|
+
# Expects arguments in the same format as
|
134
|
+
# {ActiveRecord::Base.create}[rdoc-ref:Persistence::ClassMethods#create].
|
129
135
|
#
|
130
136
|
# ==== Examples
|
137
|
+
#
|
131
138
|
# users = User.where(name: 'Oscar')
|
132
|
-
# users.create # #<User id: 3, name: "
|
139
|
+
# users.create # => #<User id: 3, name: "Oscar", ...>
|
133
140
|
#
|
134
141
|
# users.create(name: 'fxn')
|
135
|
-
# users.create # #<User id: 4, name: "fxn", ...>
|
142
|
+
# users.create # => #<User id: 4, name: "fxn", ...>
|
136
143
|
#
|
137
144
|
# users.create { |user| user.name = 'tenderlove' }
|
138
|
-
# # #<User id: 5, name: "tenderlove", ...>
|
145
|
+
# # => #<User id: 5, name: "tenderlove", ...>
|
139
146
|
#
|
140
147
|
# users.create(name: nil) # validation on name
|
141
|
-
# # #<User id: nil, name: nil, ...>
|
148
|
+
# # => #<User id: nil, name: nil, ...>
|
142
149
|
def create(*args, &block)
|
143
150
|
scoping { @klass.create(*args, &block) }
|
144
151
|
end
|
145
152
|
|
146
|
-
# Similar to #create, but calls
|
147
|
-
#
|
153
|
+
# Similar to #create, but calls
|
154
|
+
# {create!}[rdoc-ref:Persistence::ClassMethods#create!]
|
155
|
+
# on the base class. Raises an exception if a validation error occurs.
|
148
156
|
#
|
149
|
-
# Expects arguments in the same format as
|
157
|
+
# Expects arguments in the same format as
|
158
|
+
# {ActiveRecord::Base.create!}[rdoc-ref:Persistence::ClassMethods#create!].
|
150
159
|
def create!(*args, &block)
|
151
160
|
scoping { @klass.create!(*args, &block) }
|
152
161
|
end
|
@@ -180,7 +189,7 @@ module ActiveRecord
|
|
180
189
|
# User.create_with(last_name: 'Johansson').find_or_create_by(first_name: 'Scarlett')
|
181
190
|
# # => #<User id: 2, first_name: "Scarlett", last_name: "Johansson">
|
182
191
|
#
|
183
|
-
# This method accepts a block, which is passed down to
|
192
|
+
# This method accepts a block, which is passed down to #create. The last example
|
184
193
|
# above can be alternatively written this way:
|
185
194
|
#
|
186
195
|
# # Find the first user named "Scarlett" or create a new one with a
|
@@ -192,7 +201,7 @@ module ActiveRecord
|
|
192
201
|
#
|
193
202
|
# This method always returns a record, but if creation was attempted and
|
194
203
|
# failed due to validation errors it won't be persisted, you get what
|
195
|
-
#
|
204
|
+
# #create returns in such situation.
|
196
205
|
#
|
197
206
|
# Please note *this method is not atomic*, it runs first a SELECT, and if
|
198
207
|
# there are no results an INSERT is attempted. If there are other threads
|
@@ -204,7 +213,9 @@ module ActiveRecord
|
|
204
213
|
# constraint an exception may be raised, just retry:
|
205
214
|
#
|
206
215
|
# begin
|
207
|
-
# CreditAccount.
|
216
|
+
# CreditAccount.transaction(requires_new: true) do
|
217
|
+
# CreditAccount.find_or_create_by(user_id: user.id)
|
218
|
+
# end
|
208
219
|
# rescue ActiveRecord::RecordNotUnique
|
209
220
|
# retry
|
210
221
|
# end
|
@@ -213,13 +224,15 @@ module ActiveRecord
|
|
213
224
|
find_by(attributes) || create(attributes, &block)
|
214
225
|
end
|
215
226
|
|
216
|
-
# Like
|
227
|
+
# Like #find_or_create_by, but calls
|
228
|
+
# {create!}[rdoc-ref:Persistence::ClassMethods#create!] so an exception
|
217
229
|
# is raised if the created record is invalid.
|
218
230
|
def find_or_create_by!(attributes, &block)
|
219
231
|
find_by(attributes) || create!(attributes, &block)
|
220
232
|
end
|
221
233
|
|
222
|
-
# Like
|
234
|
+
# Like #find_or_create_by, but calls {new}[rdoc-ref:Core#new]
|
235
|
+
# instead of {create}[rdoc-ref:Persistence::ClassMethods#create].
|
223
236
|
def find_or_initialize_by(attributes, &block)
|
224
237
|
find_by(attributes) || new(attributes, &block)
|
225
238
|
end
|
@@ -240,17 +253,21 @@ module ActiveRecord
|
|
240
253
|
|
241
254
|
# Converts relation objects to Array.
|
242
255
|
def to_a
|
256
|
+
records.dup
|
257
|
+
end
|
258
|
+
|
259
|
+
def records # :nodoc:
|
243
260
|
load
|
244
261
|
@records
|
245
262
|
end
|
246
263
|
|
247
264
|
# Serializes the relation objects Array.
|
248
265
|
def encode_with(coder)
|
249
|
-
coder.represent_seq(nil,
|
266
|
+
coder.represent_seq(nil, records)
|
250
267
|
end
|
251
268
|
|
252
269
|
def as_json(options = nil) #:nodoc:
|
253
|
-
|
270
|
+
records.as_json(options)
|
254
271
|
end
|
255
272
|
|
256
273
|
# Returns size of the records.
|
@@ -270,22 +287,54 @@ module ActiveRecord
|
|
270
287
|
end
|
271
288
|
end
|
272
289
|
|
290
|
+
# Returns true if there are no records.
|
291
|
+
def none?
|
292
|
+
return super if block_given?
|
293
|
+
empty?
|
294
|
+
end
|
295
|
+
|
273
296
|
# Returns true if there are any records.
|
274
297
|
def any?
|
275
|
-
if block_given?
|
276
|
-
|
277
|
-
|
278
|
-
|
279
|
-
|
298
|
+
return super if block_given?
|
299
|
+
!empty?
|
300
|
+
end
|
301
|
+
|
302
|
+
# Returns true if there is exactly one record.
|
303
|
+
def one?
|
304
|
+
return super if block_given?
|
305
|
+
limit_value ? records.one? : size == 1
|
280
306
|
end
|
281
307
|
|
282
308
|
# Returns true if there is more than one record.
|
283
309
|
def many?
|
284
|
-
if block_given?
|
285
|
-
|
286
|
-
|
287
|
-
|
288
|
-
|
310
|
+
return super if block_given?
|
311
|
+
limit_value ? records.many? : size > 1
|
312
|
+
end
|
313
|
+
|
314
|
+
# Returns a cache key that can be used to identify the records fetched by
|
315
|
+
# this query. The cache key is built with a fingerprint of the sql query,
|
316
|
+
# the number of records matched by the query and a timestamp of the last
|
317
|
+
# updated record. When a new record comes to match the query, or any of
|
318
|
+
# the existing records is updated or deleted, the cache key changes.
|
319
|
+
#
|
320
|
+
# Product.where("name like ?", "%Cosmic Encounter%").cache_key
|
321
|
+
# # => "products/query-1850ab3d302391b85b8693e941286659-1-20150714212553907087000"
|
322
|
+
#
|
323
|
+
# If the collection is loaded, the method will iterate through the records
|
324
|
+
# to generate the timestamp, otherwise it will trigger one SQL query like:
|
325
|
+
#
|
326
|
+
# SELECT COUNT(*), MAX("products"."updated_at") FROM "products" WHERE (name like '%Cosmic Encounter%')
|
327
|
+
#
|
328
|
+
# You can also pass a custom timestamp column to fetch the timestamp of the
|
329
|
+
# last updated record.
|
330
|
+
#
|
331
|
+
# Product.where("name like ?", "%Game%").cache_key(:last_reviewed_at)
|
332
|
+
#
|
333
|
+
# You can customize the strategy to generate the key on a per model basis
|
334
|
+
# overriding ActiveRecord::Base#collection_cache_key.
|
335
|
+
def cache_key(timestamp_column = :updated_at)
|
336
|
+
@cache_keys ||= {}
|
337
|
+
@cache_keys[timestamp_column] ||= @klass.collection_cache_key(self, timestamp_column)
|
289
338
|
end
|
290
339
|
|
291
340
|
# Scope all queries to the current scope.
|
@@ -298,7 +347,7 @@ module ActiveRecord
|
|
298
347
|
# Please check unscoped if you want to remove all previous scopes (including
|
299
348
|
# the default_scope) during the execution of a block.
|
300
349
|
def scoping
|
301
|
-
previous, klass.current_scope = klass.current_scope, self
|
350
|
+
previous, klass.current_scope = klass.current_scope(true), self
|
302
351
|
yield
|
303
352
|
ensure
|
304
353
|
klass.current_scope = previous
|
@@ -306,9 +355,8 @@ module ActiveRecord
|
|
306
355
|
|
307
356
|
# Updates all records in the current relation with details given. This method constructs a single SQL UPDATE
|
308
357
|
# statement and sends it straight to the database. It does not instantiate the involved models and it does not
|
309
|
-
# trigger Active Record callbacks or validations.
|
310
|
-
#
|
311
|
-
# database.
|
358
|
+
# trigger Active Record callbacks or validations. However, values passed to #update_all will still go through
|
359
|
+
# Active Record's normal type casting and serialization.
|
312
360
|
#
|
313
361
|
# ==== Parameters
|
314
362
|
#
|
@@ -324,25 +372,27 @@ module ActiveRecord
|
|
324
372
|
#
|
325
373
|
# # Update all books that match conditions, but limit it to 5 ordered by date
|
326
374
|
# Book.where('title LIKE ?', '%Rails%').order(:created_at).limit(5).update_all(author: 'David')
|
375
|
+
#
|
376
|
+
# # Update all invoices and set the number column to its id value.
|
377
|
+
# Invoice.update_all('number = id')
|
327
378
|
def update_all(updates)
|
328
379
|
raise ArgumentError, "Empty list of attributes to change" if updates.blank?
|
329
380
|
|
330
|
-
stmt = Arel::UpdateManager.new
|
381
|
+
stmt = Arel::UpdateManager.new
|
331
382
|
|
332
383
|
stmt.set Arel.sql(@klass.send(:sanitize_sql_for_assignment, updates))
|
333
384
|
stmt.table(table)
|
334
|
-
stmt.key = table[primary_key]
|
335
385
|
|
336
386
|
if joins_values.any?
|
337
|
-
@klass.connection.join_to_update(stmt, arel)
|
387
|
+
@klass.connection.join_to_update(stmt, arel, arel_attribute(primary_key))
|
338
388
|
else
|
389
|
+
stmt.key = arel_attribute(primary_key)
|
339
390
|
stmt.take(arel.limit)
|
340
391
|
stmt.order(*arel.orders)
|
341
392
|
stmt.wheres = arel.constraints
|
342
393
|
end
|
343
394
|
|
344
|
-
|
345
|
-
@klass.connection.update stmt, 'SQL', bvs
|
395
|
+
@klass.connection.update stmt, 'SQL', bound_attributes
|
346
396
|
end
|
347
397
|
|
348
398
|
# Updates an object (or multiple objects) and saves it to the database, if validations pass.
|
@@ -361,20 +411,39 @@ module ActiveRecord
|
|
361
411
|
# # Updates multiple records
|
362
412
|
# people = { 1 => { "first_name" => "David" }, 2 => { "first_name" => "Jeremy" } }
|
363
413
|
# Person.update(people.keys, people.values)
|
364
|
-
|
414
|
+
#
|
415
|
+
# # Updates multiple records from the result of a relation
|
416
|
+
# people = Person.where(group: 'expert')
|
417
|
+
# people.update(group: 'masters')
|
418
|
+
#
|
419
|
+
# Note: Updating a large number of records will run an
|
420
|
+
# UPDATE query for each record, which may cause a performance
|
421
|
+
# issue. So if it is not needed to run callbacks for each update, it is
|
422
|
+
# preferred to use #update_all for updating all records using
|
423
|
+
# a single query.
|
424
|
+
def update(id = :all, attributes)
|
365
425
|
if id.is_a?(Array)
|
366
426
|
id.map.with_index { |one_id, idx| update(one_id, attributes[idx]) }
|
427
|
+
elsif id == :all
|
428
|
+
records.each { |record| record.update(attributes) }
|
367
429
|
else
|
430
|
+
if ActiveRecord::Base === id
|
431
|
+
id = id.id
|
432
|
+
ActiveSupport::Deprecation.warn(<<-MSG.squish)
|
433
|
+
You are passing an instance of ActiveRecord::Base to `update`.
|
434
|
+
Please pass the id of the object by calling `.id`.
|
435
|
+
MSG
|
436
|
+
end
|
368
437
|
object = find(id)
|
369
438
|
object.update(attributes)
|
370
439
|
object
|
371
440
|
end
|
372
441
|
end
|
373
442
|
|
374
|
-
# Destroys the records
|
375
|
-
# record and calling its
|
376
|
-
# executed (including <tt>:dependent</tt> association options).
|
377
|
-
# collection of objects that were destroyed; each will be frozen, to
|
443
|
+
# Destroys the records by instantiating each
|
444
|
+
# record and calling its {#destroy}[rdoc-ref:Persistence#destroy] method.
|
445
|
+
# Each object's callbacks are executed (including <tt>:dependent</tt> association options).
|
446
|
+
# Returns the collection of objects that were destroyed; each will be frozen, to
|
378
447
|
# reflect that no changes should be made (since they can't be persisted).
|
379
448
|
#
|
380
449
|
# Note: Instantiation, callback execution, and deletion of each
|
@@ -382,31 +451,26 @@ module ActiveRecord
|
|
382
451
|
# once. It generates at least one SQL +DELETE+ query per record (or
|
383
452
|
# possibly more, to enforce your callbacks). If you want to delete many
|
384
453
|
# rows quickly, without concern for their associations or callbacks, use
|
385
|
-
#
|
386
|
-
#
|
387
|
-
# ==== Parameters
|
388
|
-
#
|
389
|
-
# * +conditions+ - A string, array, or hash that specifies which records
|
390
|
-
# to destroy. If omitted, all records are destroyed. See the
|
391
|
-
# Conditions section in the introduction to ActiveRecord::Base for
|
392
|
-
# more information.
|
454
|
+
# #delete_all instead.
|
393
455
|
#
|
394
456
|
# ==== Examples
|
395
457
|
#
|
396
|
-
# Person.destroy_all("last_login < '2004-04-04'")
|
397
|
-
# Person.destroy_all(status: "inactive")
|
398
458
|
# Person.where(age: 0..18).destroy_all
|
399
459
|
def destroy_all(conditions = nil)
|
400
460
|
if conditions
|
461
|
+
ActiveSupport::Deprecation.warn(<<-MESSAGE.squish)
|
462
|
+
Passing conditions to destroy_all is deprecated and will be removed in Rails 5.1.
|
463
|
+
To achieve the same use where(conditions).destroy_all.
|
464
|
+
MESSAGE
|
401
465
|
where(conditions).destroy_all
|
402
466
|
else
|
403
|
-
|
467
|
+
records.each(&:destroy).tap { reset }
|
404
468
|
end
|
405
469
|
end
|
406
470
|
|
407
471
|
# Destroy an object (or multiple objects) that has the given id. The object is instantiated first,
|
408
472
|
# therefore all callbacks and filters are fired off before the object is deleted. This method is
|
409
|
-
# less efficient than
|
473
|
+
# less efficient than #delete but allows cleanup methods and other actions to be run.
|
410
474
|
#
|
411
475
|
# This essentially finds the object (or multiple objects) with the given id, creates a new object
|
412
476
|
# from the attributes, and then calls destroy on it.
|
@@ -431,22 +495,21 @@ module ActiveRecord
|
|
431
495
|
end
|
432
496
|
end
|
433
497
|
|
434
|
-
# Deletes the records
|
435
|
-
# first, and hence not calling the
|
436
|
-
#
|
437
|
-
#
|
498
|
+
# Deletes the records without instantiating the records
|
499
|
+
# first, and hence not calling the {#destroy}[rdoc-ref:Persistence#destroy]
|
500
|
+
# method nor invoking callbacks.
|
501
|
+
# This is a single SQL DELETE statement that goes straight to the database, much more
|
502
|
+
# efficient than #destroy_all. Be careful with relations though, in particular
|
438
503
|
# <tt>:dependent</tt> rules defined on associations are not honored. Returns the
|
439
504
|
# number of rows affected.
|
440
505
|
#
|
441
|
-
# Post.delete_all("person_id = 5 AND (category = 'Something' OR category = 'Else')")
|
442
|
-
# Post.delete_all(["person_id = ? AND (category = ? OR category = ?)", 5, 'Something', 'Else'])
|
443
506
|
# Post.where(person_id: 5).where(category: ['Something', 'Else']).delete_all
|
444
507
|
#
|
445
508
|
# Both calls delete the affected posts all at once with a single DELETE statement.
|
446
509
|
# If you need to destroy dependent associations or call your <tt>before_*</tt> or
|
447
|
-
# +after_destroy+ callbacks, use the
|
510
|
+
# +after_destroy+ callbacks, use the #destroy_all method instead.
|
448
511
|
#
|
449
|
-
# If an invalid method is supplied,
|
512
|
+
# If an invalid method is supplied, #delete_all raises an ActiveRecordError:
|
450
513
|
#
|
451
514
|
# Post.limit(100).delete_all
|
452
515
|
# # => ActiveRecord::ActiveRecordError: delete_all doesn't support limit
|
@@ -454,8 +517,10 @@ module ActiveRecord
|
|
454
517
|
invalid_methods = INVALID_METHODS_FOR_DELETE_ALL.select { |method|
|
455
518
|
if MULTI_VALUE_METHODS.include?(method)
|
456
519
|
send("#{method}_values").any?
|
457
|
-
|
520
|
+
elsif SINGLE_VALUE_METHODS.include?(method)
|
458
521
|
send("#{method}_value")
|
522
|
+
elsif CLAUSE_METHODS.include?(method)
|
523
|
+
send("#{method}_clause").any?
|
459
524
|
end
|
460
525
|
}
|
461
526
|
if invalid_methods.any?
|
@@ -463,19 +528,22 @@ module ActiveRecord
|
|
463
528
|
end
|
464
529
|
|
465
530
|
if conditions
|
531
|
+
ActiveSupport::Deprecation.warn(<<-MESSAGE.squish)
|
532
|
+
Passing conditions to delete_all is deprecated and will be removed in Rails 5.1.
|
533
|
+
To achieve the same use where(conditions).delete_all.
|
534
|
+
MESSAGE
|
466
535
|
where(conditions).delete_all
|
467
536
|
else
|
468
|
-
stmt = Arel::DeleteManager.new
|
537
|
+
stmt = Arel::DeleteManager.new
|
469
538
|
stmt.from(table)
|
470
539
|
|
471
540
|
if joins_values.any?
|
472
|
-
@klass.connection.join_to_delete(stmt, arel,
|
541
|
+
@klass.connection.join_to_delete(stmt, arel, arel_attribute(primary_key))
|
473
542
|
else
|
474
543
|
stmt.wheres = arel.constraints
|
475
544
|
end
|
476
545
|
|
477
|
-
|
478
|
-
affected = @klass.connection.delete(stmt, 'SQL', bvs)
|
546
|
+
affected = @klass.connection.delete(stmt, 'SQL', bound_attributes)
|
479
547
|
|
480
548
|
reset
|
481
549
|
affected
|
@@ -490,7 +558,7 @@ module ActiveRecord
|
|
490
558
|
# You can delete multiple rows at once by passing an Array of <tt>id</tt>s.
|
491
559
|
#
|
492
560
|
# Note: Although it is often much faster than the alternative,
|
493
|
-
#
|
561
|
+
# #destroy, skipping callbacks might bypass business logic in
|
494
562
|
# your application that ensures referential integrity or performs other
|
495
563
|
# essential jobs.
|
496
564
|
#
|
@@ -511,8 +579,8 @@ module ActiveRecord
|
|
511
579
|
# return value is the relation itself, not the records.
|
512
580
|
#
|
513
581
|
# Post.where(published: true).load # => #<ActiveRecord::Relation>
|
514
|
-
def load
|
515
|
-
exec_queries unless loaded?
|
582
|
+
def load(&block)
|
583
|
+
exec_queries(&block) unless loaded?
|
516
584
|
|
517
585
|
self
|
518
586
|
end
|
@@ -526,7 +594,7 @@ module ActiveRecord
|
|
526
594
|
def reset
|
527
595
|
@last = @to_sql = @order_clause = @scope_for_create = @arel = @loaded = nil
|
528
596
|
@should_eager_load = @join_dependency = nil
|
529
|
-
@records = []
|
597
|
+
@records = [].freeze
|
530
598
|
@offsets = {}
|
531
599
|
self
|
532
600
|
end
|
@@ -545,10 +613,10 @@ module ActiveRecord
|
|
545
613
|
find_with_associations { |rel| relation = rel }
|
546
614
|
end
|
547
615
|
|
548
|
-
|
549
|
-
binds = (
|
550
|
-
binds.map! { |
|
551
|
-
collect = visitor.accept(arel.ast, Arel::Collectors::Bind.new)
|
616
|
+
binds = relation.bound_attributes
|
617
|
+
binds = connection.prepare_binds_for_database(binds)
|
618
|
+
binds.map! { |value| connection.quote(value) }
|
619
|
+
collect = visitor.accept(relation.arel.ast, Arel::Collectors::Bind.new)
|
552
620
|
collect.substitute_binds(binds).join
|
553
621
|
end
|
554
622
|
end
|
@@ -558,22 +626,7 @@ module ActiveRecord
|
|
558
626
|
# User.where(name: 'Oscar').where_values_hash
|
559
627
|
# # => {name: "Oscar"}
|
560
628
|
def where_values_hash(relation_table_name = table_name)
|
561
|
-
|
562
|
-
node.left.relation.name == relation_table_name
|
563
|
-
}
|
564
|
-
|
565
|
-
binds = Hash[bind_values.find_all(&:first).map { |column, v| [column.name, v] }]
|
566
|
-
|
567
|
-
Hash[equalities.map { |where|
|
568
|
-
name = where.left.name
|
569
|
-
[name, binds.fetch(name.to_s) {
|
570
|
-
case where.right
|
571
|
-
when Array then where.right.map(&:val)
|
572
|
-
when Arel::Nodes::Casted
|
573
|
-
where.right.val
|
574
|
-
end
|
575
|
-
}]
|
576
|
-
}]
|
629
|
+
where_clause.to_h(relation_table_name)
|
577
630
|
end
|
578
631
|
|
579
632
|
def scope_for_create
|
@@ -595,31 +648,34 @@ module ActiveRecord
|
|
595
648
|
includes_values & joins_values
|
596
649
|
end
|
597
650
|
|
598
|
-
#
|
599
|
-
#
|
651
|
+
# {#uniq}[rdoc-ref:QueryMethods#uniq] and
|
652
|
+
# {#uniq!}[rdoc-ref:QueryMethods#uniq!] are silently deprecated.
|
653
|
+
# #uniq_value delegates to #distinct_value to maintain backwards compatibility.
|
654
|
+
# Use #distinct_value instead.
|
600
655
|
def uniq_value
|
601
656
|
distinct_value
|
602
657
|
end
|
658
|
+
deprecate uniq_value: :distinct_value
|
603
659
|
|
604
660
|
# Compares two relations for equality.
|
605
661
|
def ==(other)
|
606
662
|
case other
|
607
663
|
when Associations::CollectionProxy, AssociationRelation
|
608
|
-
self == other.
|
664
|
+
self == other.records
|
609
665
|
when Relation
|
610
666
|
other.to_sql == to_sql
|
611
667
|
when Array
|
612
|
-
|
668
|
+
records == other
|
613
669
|
end
|
614
670
|
end
|
615
671
|
|
616
672
|
def pretty_print(q)
|
617
|
-
q.pp(self.
|
673
|
+
q.pp(self.records)
|
618
674
|
end
|
619
675
|
|
620
676
|
# Returns true if relation is blank.
|
621
677
|
def blank?
|
622
|
-
|
678
|
+
records.blank?
|
623
679
|
end
|
624
680
|
|
625
681
|
def values
|
@@ -627,16 +683,27 @@ module ActiveRecord
|
|
627
683
|
end
|
628
684
|
|
629
685
|
def inspect
|
630
|
-
entries =
|
686
|
+
entries = records.take([limit_value, 11].compact.min).map!(&:inspect)
|
631
687
|
entries[10] = '...' if entries.size == 11
|
632
688
|
|
633
689
|
"#<#{self.class.name} [#{entries.join(', ')}]>"
|
634
690
|
end
|
635
691
|
|
692
|
+
def empty_scope? # :nodoc:
|
693
|
+
@values == klass.unscoped.values
|
694
|
+
end
|
695
|
+
|
696
|
+
protected
|
697
|
+
|
698
|
+
def load_records(records)
|
699
|
+
@records = records.freeze
|
700
|
+
@loaded = true
|
701
|
+
end
|
702
|
+
|
636
703
|
private
|
637
704
|
|
638
|
-
def exec_queries
|
639
|
-
@records = eager_loading? ? find_with_associations : @klass.find_by_sql(arel,
|
705
|
+
def exec_queries(&block)
|
706
|
+
@records = eager_loading? ? find_with_associations.freeze : @klass.find_by_sql(arel, bound_attributes, &block).freeze
|
640
707
|
|
641
708
|
preload = preload_values
|
642
709
|
preload += includes_values unless eager_loading?
|
@@ -645,7 +712,7 @@ module ActiveRecord
|
|
645
712
|
preloader.preload @records, associations
|
646
713
|
end
|
647
714
|
|
648
|
-
@records.each
|
715
|
+
@records.each(&:readonly!) if readonly_value
|
649
716
|
|
650
717
|
@loaded = true
|
651
718
|
@records
|
@@ -667,7 +734,7 @@ module ActiveRecord
|
|
667
734
|
joined_tables += [table.name, table.table_alias]
|
668
735
|
|
669
736
|
# always convert table names to downcase as in Oracle quoted table names are in uppercase
|
670
|
-
joined_tables = joined_tables.flatten.compact.map
|
737
|
+
joined_tables = joined_tables.flatten.compact.map(&:downcase).uniq
|
671
738
|
|
672
739
|
(references_values - joined_tables).any?
|
673
740
|
end
|
@@ -676,7 +743,7 @@ module ActiveRecord
|
|
676
743
|
return [] if string.blank?
|
677
744
|
# always convert table names to downcase as in Oracle quoted table names are in uppercase
|
678
745
|
# ignore raw_sql_ that is used by Oracle adapter as alias for limit/offset subqueries
|
679
|
-
string.scan(/([a-zA-Z_][.\w]+).?\./).flatten.map
|
746
|
+
string.scan(/([a-zA-Z_][.\w]+).?\./).flatten.map(&:downcase).uniq - ['raw_sql_']
|
680
747
|
end
|
681
748
|
end
|
682
749
|
end
|