activerecord 3.1.10 → 4.2.11
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.
Potentially problematic release.
This version of activerecord might be problematic. Click here for more details.
- checksums.yaml +6 -6
- data/CHANGELOG.md +1837 -338
- data/MIT-LICENSE +1 -1
- data/README.rdoc +39 -43
- data/examples/performance.rb +51 -20
- data/examples/simple.rb +4 -4
- data/lib/active_record/aggregations.rb +57 -43
- data/lib/active_record/association_relation.rb +35 -0
- data/lib/active_record/associations/alias_tracker.rb +47 -39
- data/lib/active_record/associations/association.rb +71 -85
- data/lib/active_record/associations/association_scope.rb +138 -89
- data/lib/active_record/associations/belongs_to_association.rb +65 -25
- data/lib/active_record/associations/belongs_to_polymorphic_association.rb +9 -3
- data/lib/active_record/associations/builder/association.rb +125 -29
- data/lib/active_record/associations/builder/belongs_to.rb +91 -60
- data/lib/active_record/associations/builder/collection_association.rb +69 -49
- data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +113 -42
- data/lib/active_record/associations/builder/has_many.rb +8 -64
- data/lib/active_record/associations/builder/has_one.rb +12 -52
- data/lib/active_record/associations/builder/singular_association.rb +22 -29
- data/lib/active_record/associations/collection_association.rb +294 -187
- data/lib/active_record/associations/collection_proxy.rb +961 -94
- data/lib/active_record/associations/foreign_association.rb +11 -0
- data/lib/active_record/associations/has_many_association.rb +118 -23
- data/lib/active_record/associations/has_many_through_association.rb +115 -45
- data/lib/active_record/associations/has_one_association.rb +57 -24
- data/lib/active_record/associations/has_one_through_association.rb +1 -1
- data/lib/active_record/associations/join_dependency/join_association.rb +76 -102
- data/lib/active_record/associations/join_dependency/join_base.rb +7 -9
- data/lib/active_record/associations/join_dependency/join_part.rb +30 -37
- data/lib/active_record/associations/join_dependency.rb +230 -156
- data/lib/active_record/associations/preloader/association.rb +96 -55
- data/lib/active_record/associations/preloader/collection_association.rb +3 -3
- data/lib/active_record/associations/preloader/has_many_through.rb +7 -3
- data/lib/active_record/associations/preloader/has_one.rb +1 -1
- data/lib/active_record/associations/preloader/singular_association.rb +3 -3
- data/lib/active_record/associations/preloader/through_association.rb +61 -32
- data/lib/active_record/associations/preloader.rb +113 -87
- data/lib/active_record/associations/singular_association.rb +29 -13
- data/lib/active_record/associations/through_association.rb +37 -19
- data/lib/active_record/associations.rb +505 -371
- data/lib/active_record/attribute.rb +163 -0
- data/lib/active_record/attribute_assignment.rb +212 -0
- data/lib/active_record/attribute_decorators.rb +66 -0
- data/lib/active_record/attribute_methods/before_type_cast.rb +52 -7
- data/lib/active_record/attribute_methods/dirty.rb +141 -51
- data/lib/active_record/attribute_methods/primary_key.rb +87 -36
- data/lib/active_record/attribute_methods/query.rb +5 -4
- data/lib/active_record/attribute_methods/read.rb +74 -117
- data/lib/active_record/attribute_methods/serialization.rb +70 -0
- data/lib/active_record/attribute_methods/time_zone_conversion.rb +49 -47
- data/lib/active_record/attribute_methods/write.rb +60 -21
- data/lib/active_record/attribute_methods.rb +409 -48
- data/lib/active_record/attribute_set/builder.rb +106 -0
- data/lib/active_record/attribute_set.rb +81 -0
- data/lib/active_record/attributes.rb +147 -0
- data/lib/active_record/autosave_association.rb +279 -232
- data/lib/active_record/base.rb +84 -1969
- data/lib/active_record/callbacks.rb +66 -28
- data/lib/active_record/coders/json.rb +13 -0
- data/lib/active_record/coders/yaml_column.rb +18 -21
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +422 -243
- data/lib/active_record/connection_adapters/abstract/database_limits.rb +9 -0
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +170 -194
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +32 -19
- data/lib/active_record/connection_adapters/abstract/quoting.rb +79 -57
- data/lib/active_record/connection_adapters/abstract/savepoints.rb +21 -0
- data/lib/active_record/connection_adapters/abstract/schema_creation.rb +125 -0
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +273 -170
- data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +50 -0
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +731 -254
- data/lib/active_record/connection_adapters/abstract/transaction.rb +215 -0
- data/lib/active_record/connection_adapters/abstract_adapter.rb +339 -95
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +946 -0
- data/lib/active_record/connection_adapters/column.rb +33 -221
- data/lib/active_record/connection_adapters/connection_specification.rb +275 -0
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +140 -602
- data/lib/active_record/connection_adapters/mysql_adapter.rb +254 -756
- data/lib/active_record/connection_adapters/postgresql/array_parser.rb +93 -0
- data/lib/active_record/connection_adapters/postgresql/column.rb +20 -0
- data/lib/active_record/connection_adapters/postgresql/database_statements.rb +232 -0
- data/lib/active_record/connection_adapters/postgresql/oid/array.rb +100 -0
- data/lib/active_record/connection_adapters/postgresql/oid/bit.rb +52 -0
- data/lib/active_record/connection_adapters/postgresql/oid/bit_varying.rb +13 -0
- data/lib/active_record/connection_adapters/postgresql/oid/bytea.rb +15 -0
- data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +46 -0
- data/lib/active_record/connection_adapters/postgresql/oid/date.rb +11 -0
- data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +36 -0
- data/lib/active_record/connection_adapters/postgresql/oid/decimal.rb +13 -0
- data/lib/active_record/connection_adapters/postgresql/oid/enum.rb +19 -0
- data/lib/active_record/connection_adapters/postgresql/oid/float.rb +21 -0
- data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +59 -0
- data/lib/active_record/connection_adapters/postgresql/oid/inet.rb +13 -0
- data/lib/active_record/connection_adapters/postgresql/oid/infinity.rb +13 -0
- data/lib/active_record/connection_adapters/postgresql/oid/integer.rb +11 -0
- data/lib/active_record/connection_adapters/postgresql/oid/json.rb +35 -0
- data/lib/active_record/connection_adapters/postgresql/oid/jsonb.rb +23 -0
- data/lib/active_record/connection_adapters/postgresql/oid/money.rb +43 -0
- data/lib/active_record/connection_adapters/postgresql/oid/point.rb +43 -0
- data/lib/active_record/connection_adapters/postgresql/oid/range.rb +79 -0
- data/lib/active_record/connection_adapters/postgresql/oid/specialized_string.rb +19 -0
- data/lib/active_record/connection_adapters/postgresql/oid/time.rb +11 -0
- data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +109 -0
- data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +21 -0
- data/lib/active_record/connection_adapters/postgresql/oid/vector.rb +26 -0
- data/lib/active_record/connection_adapters/postgresql/oid/xml.rb +28 -0
- data/lib/active_record/connection_adapters/postgresql/oid.rb +36 -0
- data/lib/active_record/connection_adapters/postgresql/quoting.rb +108 -0
- data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +30 -0
- data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +152 -0
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +596 -0
- data/lib/active_record/connection_adapters/postgresql/utils.rb +77 -0
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +445 -902
- data/lib/active_record/connection_adapters/schema_cache.rb +94 -0
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +578 -25
- data/lib/active_record/connection_handling.rb +132 -0
- data/lib/active_record/core.rb +579 -0
- data/lib/active_record/counter_cache.rb +159 -102
- data/lib/active_record/dynamic_matchers.rb +140 -0
- data/lib/active_record/enum.rb +197 -0
- data/lib/active_record/errors.rb +102 -34
- data/lib/active_record/explain.rb +38 -0
- data/lib/active_record/explain_registry.rb +30 -0
- data/lib/active_record/explain_subscriber.rb +29 -0
- data/lib/active_record/fixture_set/file.rb +56 -0
- data/lib/active_record/fixtures.rb +318 -260
- data/lib/active_record/gem_version.rb +15 -0
- data/lib/active_record/inheritance.rb +247 -0
- data/lib/active_record/integration.rb +113 -0
- data/lib/active_record/legacy_yaml_adapter.rb +30 -0
- data/lib/active_record/locale/en.yml +8 -1
- data/lib/active_record/locking/optimistic.rb +80 -52
- data/lib/active_record/locking/pessimistic.rb +27 -5
- data/lib/active_record/log_subscriber.rb +25 -18
- data/lib/active_record/migration/command_recorder.rb +130 -38
- data/lib/active_record/migration/join_table.rb +15 -0
- data/lib/active_record/migration.rb +532 -201
- data/lib/active_record/model_schema.rb +342 -0
- data/lib/active_record/nested_attributes.rb +229 -139
- data/lib/active_record/no_touching.rb +52 -0
- data/lib/active_record/null_relation.rb +81 -0
- data/lib/active_record/persistence.rb +304 -99
- data/lib/active_record/query_cache.rb +25 -43
- data/lib/active_record/querying.rb +68 -0
- data/lib/active_record/railtie.rb +86 -45
- data/lib/active_record/railties/console_sandbox.rb +3 -4
- data/lib/active_record/railties/controller_runtime.rb +7 -4
- data/lib/active_record/railties/databases.rake +198 -377
- data/lib/active_record/railties/jdbcmysql_error.rb +2 -2
- data/lib/active_record/readonly_attributes.rb +23 -0
- data/lib/active_record/reflection.rb +516 -165
- data/lib/active_record/relation/batches.rb +96 -45
- data/lib/active_record/relation/calculations.rb +221 -144
- data/lib/active_record/relation/delegation.rb +140 -0
- data/lib/active_record/relation/finder_methods.rb +362 -243
- data/lib/active_record/relation/merger.rb +193 -0
- data/lib/active_record/relation/predicate_builder/array_handler.rb +48 -0
- data/lib/active_record/relation/predicate_builder/relation_handler.rb +13 -0
- data/lib/active_record/relation/predicate_builder.rb +135 -41
- data/lib/active_record/relation/query_methods.rb +982 -155
- data/lib/active_record/relation/spawn_methods.rb +50 -110
- data/lib/active_record/relation.rb +371 -180
- data/lib/active_record/result.rb +109 -12
- data/lib/active_record/runtime_registry.rb +22 -0
- data/lib/active_record/sanitization.rb +191 -0
- data/lib/active_record/schema.rb +19 -13
- data/lib/active_record/schema_dumper.rb +111 -61
- data/lib/active_record/schema_migration.rb +53 -0
- data/lib/active_record/scoping/default.rb +135 -0
- data/lib/active_record/scoping/named.rb +164 -0
- data/lib/active_record/scoping.rb +87 -0
- data/lib/active_record/serialization.rb +7 -45
- data/lib/active_record/serializers/xml_serializer.rb +14 -65
- data/lib/active_record/statement_cache.rb +111 -0
- data/lib/active_record/store.rb +205 -0
- data/lib/active_record/tasks/database_tasks.rb +299 -0
- data/lib/active_record/tasks/mysql_database_tasks.rb +159 -0
- data/lib/active_record/tasks/postgresql_database_tasks.rb +101 -0
- data/lib/active_record/tasks/sqlite_database_tasks.rb +55 -0
- data/lib/active_record/timestamp.rb +35 -14
- data/lib/active_record/transactions.rb +141 -74
- data/lib/active_record/translation.rb +22 -0
- data/lib/active_record/type/big_integer.rb +13 -0
- data/lib/active_record/type/binary.rb +50 -0
- data/lib/active_record/type/boolean.rb +31 -0
- data/lib/active_record/type/date.rb +50 -0
- data/lib/active_record/type/date_time.rb +54 -0
- data/lib/active_record/type/decimal.rb +64 -0
- data/lib/active_record/type/decimal_without_scale.rb +11 -0
- data/lib/active_record/type/decorator.rb +14 -0
- data/lib/active_record/type/float.rb +19 -0
- data/lib/active_record/type/hash_lookup_type_map.rb +23 -0
- data/lib/active_record/type/integer.rb +59 -0
- data/lib/active_record/type/mutable.rb +16 -0
- data/lib/active_record/type/numeric.rb +36 -0
- data/lib/active_record/type/serialized.rb +62 -0
- data/lib/active_record/type/string.rb +40 -0
- data/lib/active_record/type/text.rb +11 -0
- data/lib/active_record/type/time.rb +26 -0
- data/lib/active_record/type/time_value.rb +38 -0
- data/lib/active_record/type/type_map.rb +64 -0
- data/lib/active_record/type/unsigned_integer.rb +15 -0
- data/lib/active_record/type/value.rb +110 -0
- data/lib/active_record/type.rb +23 -0
- data/lib/active_record/validations/associated.rb +27 -18
- data/lib/active_record/validations/presence.rb +67 -0
- data/lib/active_record/validations/uniqueness.rb +125 -66
- data/lib/active_record/validations.rb +37 -30
- data/lib/active_record/version.rb +5 -7
- data/lib/active_record.rb +80 -25
- data/lib/rails/generators/active_record/migration/migration_generator.rb +54 -9
- data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb +19 -0
- data/lib/rails/generators/active_record/migration/templates/migration.rb +25 -11
- data/lib/rails/generators/active_record/migration.rb +11 -8
- data/lib/rails/generators/active_record/model/model_generator.rb +17 -4
- data/lib/rails/generators/active_record/model/templates/model.rb +5 -2
- data/lib/rails/generators/active_record/model/templates/module.rb +1 -1
- data/lib/rails/generators/active_record.rb +3 -11
- metadata +132 -53
- data/examples/associations.png +0 -0
- data/lib/active_record/associations/has_and_belongs_to_many_association.rb +0 -62
- data/lib/active_record/associations/join_helper.rb +0 -55
- data/lib/active_record/associations/preloader/has_and_belongs_to_many.rb +0 -60
- data/lib/active_record/connection_adapters/abstract/connection_specification.rb +0 -135
- data/lib/active_record/connection_adapters/sqlite_adapter.rb +0 -556
- data/lib/active_record/dynamic_finder_match.rb +0 -56
- data/lib/active_record/dynamic_scope_match.rb +0 -23
- data/lib/active_record/identity_map.rb +0 -163
- data/lib/active_record/named_scope.rb +0 -200
- data/lib/active_record/observer.rb +0 -121
- data/lib/active_record/session_store.rb +0 -358
- data/lib/active_record/test_case.rb +0 -69
- data/lib/rails/generators/active_record/model/templates/migration.rb +0 -17
- data/lib/rails/generators/active_record/observer/observer_generator.rb +0 -15
- data/lib/rails/generators/active_record/observer/templates/observer.rb +0 -4
- data/lib/rails/generators/active_record/session_migration/session_migration_generator.rb +0 -25
- data/lib/rails/generators/active_record/session_migration/templates/migration.rb +0 -16
@@ -1,39 +1,42 @@
|
|
1
|
-
|
2
|
-
require '
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
require 'arel/collectors/bind'
|
3
3
|
|
4
4
|
module ActiveRecord
|
5
5
|
# = Active Record Relation
|
6
6
|
class Relation
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
SINGLE_VALUE_METHODS = [:limit, :offset, :lock, :readonly, :from, :reorder, :reverse_order]
|
7
|
+
MULTI_VALUE_METHODS = [:includes, :eager_load, :preload, :select, :group,
|
8
|
+
:order, :joins, :where, :having, :bind, :references,
|
9
|
+
:extending, :unscope]
|
11
10
|
|
12
|
-
|
11
|
+
SINGLE_VALUE_METHODS = [:limit, :offset, :lock, :readonly, :from, :reordering,
|
12
|
+
:reverse_order, :distinct, :create_with, :uniq]
|
13
|
+
INVALID_METHODS_FOR_DELETE_ALL = [:limit, :distinct, :offset, :group, :having]
|
13
14
|
|
14
|
-
|
15
|
-
|
16
|
-
|
15
|
+
VALUE_METHODS = MULTI_VALUE_METHODS + SINGLE_VALUE_METHODS
|
16
|
+
|
17
|
+
include FinderMethods, Calculations, SpawnMethods, QueryMethods, Batches, Explain, Delegation
|
17
18
|
|
18
19
|
attr_reader :table, :klass, :loaded
|
19
|
-
|
20
|
+
alias :model :klass
|
20
21
|
alias :loaded? :loaded
|
21
|
-
alias :default_scoped? :default_scoped
|
22
|
-
|
23
|
-
def initialize(klass, table)
|
24
|
-
@klass, @table = klass, table
|
25
22
|
|
26
|
-
|
27
|
-
@
|
28
|
-
@
|
23
|
+
def initialize(klass, table, values = {})
|
24
|
+
@klass = klass
|
25
|
+
@table = table
|
26
|
+
@values = values
|
27
|
+
@offsets = {}
|
28
|
+
@loaded = false
|
29
|
+
end
|
29
30
|
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
@
|
31
|
+
def initialize_copy(other)
|
32
|
+
# This method is a hot spot, so for now, use Hash[] to dup the hash.
|
33
|
+
# https://bugs.ruby-lang.org/issues/7166
|
34
|
+
@values = Hash[@values]
|
35
|
+
@values[:bind] = @values[:bind].dup if @values.key? :bind
|
36
|
+
reset
|
34
37
|
end
|
35
38
|
|
36
|
-
def insert(values)
|
39
|
+
def insert(values) # :nodoc:
|
37
40
|
primary_key_value = nil
|
38
41
|
|
39
42
|
if primary_key && Hash === values
|
@@ -50,16 +53,7 @@ module ActiveRecord
|
|
50
53
|
im = arel.create_insert
|
51
54
|
im.into @table
|
52
55
|
|
53
|
-
|
54
|
-
|
55
|
-
substitutes = values.sort_by { |arel_attr,_| arel_attr.name }
|
56
|
-
binds = substitutes.map do |arel_attr, value|
|
57
|
-
[@klass.columns_hash[arel_attr.name], value]
|
58
|
-
end
|
59
|
-
|
60
|
-
substitutes.each_with_index do |tuple, i|
|
61
|
-
tuple[1] = conn.substitute_at(binds[i][0], i)
|
62
|
-
end
|
56
|
+
substitutes, binds = substitute_values values
|
63
57
|
|
64
58
|
if values.empty? # empty insert
|
65
59
|
im.values = Arel.sql(connection.empty_insert_statement_value)
|
@@ -67,7 +61,7 @@ module ActiveRecord
|
|
67
61
|
im.insert substitutes
|
68
62
|
end
|
69
63
|
|
70
|
-
|
64
|
+
@klass.connection.insert(
|
71
65
|
im,
|
72
66
|
'SQL',
|
73
67
|
primary_key,
|
@@ -76,81 +70,207 @@ module ActiveRecord
|
|
76
70
|
binds)
|
77
71
|
end
|
78
72
|
|
79
|
-
def
|
80
|
-
|
73
|
+
def _update_record(values, id, id_was) # :nodoc:
|
74
|
+
substitutes, binds = substitute_values values
|
75
|
+
|
76
|
+
scope = @klass.unscoped
|
77
|
+
|
78
|
+
if @klass.finder_needs_type_condition?
|
79
|
+
scope.unscope!(where: @klass.inheritance_column)
|
80
|
+
end
|
81
|
+
|
82
|
+
relation = scope.where(@klass.primary_key => (id_was || id))
|
83
|
+
bvs = binds + relation.bind_values
|
84
|
+
um = relation
|
85
|
+
.arel
|
86
|
+
.compile_update(substitutes, @klass.primary_key)
|
87
|
+
|
88
|
+
@klass.connection.update(
|
89
|
+
um,
|
90
|
+
'SQL',
|
91
|
+
bvs,
|
92
|
+
)
|
81
93
|
end
|
82
94
|
|
83
|
-
def
|
84
|
-
|
85
|
-
|
95
|
+
def substitute_values(values) # :nodoc:
|
96
|
+
binds = values.map do |arel_attr, value|
|
97
|
+
[@klass.columns_hash[arel_attr.name], value]
|
98
|
+
end
|
99
|
+
|
100
|
+
substitutes = values.each_with_index.map do |(arel_attr, _), i|
|
101
|
+
[arel_attr, @klass.connection.substitute_at(binds[i][0])]
|
102
|
+
end
|
103
|
+
|
104
|
+
[substitutes, binds]
|
105
|
+
end
|
106
|
+
|
107
|
+
# Initializes new record from relation while maintaining the current
|
108
|
+
# scope.
|
109
|
+
#
|
110
|
+
# Expects arguments in the same format as +Base.new+.
|
111
|
+
#
|
112
|
+
# users = User.where(name: 'DHH')
|
113
|
+
# user = users.new # => #<User id: nil, name: "DHH", created_at: nil, updated_at: nil>
|
114
|
+
#
|
115
|
+
# You can also pass a block to new with the new record as argument:
|
116
|
+
#
|
117
|
+
# user = users.new { |user| user.name = 'Oscar' }
|
118
|
+
# user.name # => Oscar
|
119
|
+
def new(*args, &block)
|
120
|
+
scoping { @klass.new(*args, &block) }
|
86
121
|
end
|
87
122
|
|
88
123
|
alias build new
|
89
124
|
|
125
|
+
# Tries to create a new record with the same scoped attributes
|
126
|
+
# defined in the relation. Returns the initialized object if validation fails.
|
127
|
+
#
|
128
|
+
# Expects arguments in the same format as +Base.create+.
|
129
|
+
#
|
130
|
+
# ==== Examples
|
131
|
+
# users = User.where(name: 'Oscar')
|
132
|
+
# users.create # #<User id: 3, name: "oscar", ...>
|
133
|
+
#
|
134
|
+
# users.create(name: 'fxn')
|
135
|
+
# users.create # #<User id: 4, name: "fxn", ...>
|
136
|
+
#
|
137
|
+
# users.create { |user| user.name = 'tenderlove' }
|
138
|
+
# # #<User id: 5, name: "tenderlove", ...>
|
139
|
+
#
|
140
|
+
# users.create(name: nil) # validation on name
|
141
|
+
# # #<User id: nil, name: nil, ...>
|
90
142
|
def create(*args, &block)
|
91
143
|
scoping { @klass.create(*args, &block) }
|
92
144
|
end
|
93
145
|
|
146
|
+
# Similar to #create, but calls +create!+ on the base class. Raises
|
147
|
+
# an exception if a validation error occurs.
|
148
|
+
#
|
149
|
+
# Expects arguments in the same format as <tt>Base.create!</tt>.
|
94
150
|
def create!(*args, &block)
|
95
151
|
scoping { @klass.create!(*args, &block) }
|
96
152
|
end
|
97
153
|
|
98
|
-
def
|
99
|
-
|
100
|
-
Array.method_defined?(method) ||
|
101
|
-
@klass.respond_to?(method, include_private) ||
|
102
|
-
super
|
154
|
+
def first_or_create(attributes = nil, &block) # :nodoc:
|
155
|
+
first || create(attributes, &block)
|
103
156
|
end
|
104
157
|
|
105
|
-
def
|
106
|
-
|
158
|
+
def first_or_create!(attributes = nil, &block) # :nodoc:
|
159
|
+
first || create!(attributes, &block)
|
160
|
+
end
|
107
161
|
|
108
|
-
|
162
|
+
def first_or_initialize(attributes = nil, &block) # :nodoc:
|
163
|
+
first || new(attributes, &block)
|
164
|
+
end
|
109
165
|
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
166
|
+
# Finds the first record with the given attributes, or creates a record
|
167
|
+
# with the attributes if one is not found:
|
168
|
+
#
|
169
|
+
# # Find the first user named "Penélope" or create a new one.
|
170
|
+
# User.find_or_create_by(first_name: 'Penélope')
|
171
|
+
# # => #<User id: 1, first_name: "Penélope", last_name: nil>
|
172
|
+
#
|
173
|
+
# # Find the first user named "Penélope" or create a new one.
|
174
|
+
# # We already have one so the existing record will be returned.
|
175
|
+
# User.find_or_create_by(first_name: 'Penélope')
|
176
|
+
# # => #<User id: 1, first_name: "Penélope", last_name: nil>
|
177
|
+
#
|
178
|
+
# # Find the first user named "Scarlett" or create a new one with
|
179
|
+
# # a particular last name.
|
180
|
+
# User.create_with(last_name: 'Johansson').find_or_create_by(first_name: 'Scarlett')
|
181
|
+
# # => #<User id: 2, first_name: "Scarlett", last_name: "Johansson">
|
182
|
+
#
|
183
|
+
# This method accepts a block, which is passed down to +create+. The last example
|
184
|
+
# above can be alternatively written this way:
|
185
|
+
#
|
186
|
+
# # Find the first user named "Scarlett" or create a new one with a
|
187
|
+
# # different last name.
|
188
|
+
# User.find_or_create_by(first_name: 'Scarlett') do |user|
|
189
|
+
# user.last_name = 'Johansson'
|
190
|
+
# end
|
191
|
+
# # => #<User id: 2, first_name: "Scarlett", last_name: "Johansson">
|
192
|
+
#
|
193
|
+
# This method always returns a record, but if creation was attempted and
|
194
|
+
# failed due to validation errors it won't be persisted, you get what
|
195
|
+
# +create+ returns in such situation.
|
196
|
+
#
|
197
|
+
# Please note *this method is not atomic*, it runs first a SELECT, and if
|
198
|
+
# there are no results an INSERT is attempted. If there are other threads
|
199
|
+
# or processes there is a race condition between both calls and it could
|
200
|
+
# be the case that you end up with two similar records.
|
201
|
+
#
|
202
|
+
# Whether that is a problem or not depends on the logic of the
|
203
|
+
# application, but in the particular case in which rows have a UNIQUE
|
204
|
+
# constraint an exception may be raised, just retry:
|
205
|
+
#
|
206
|
+
# begin
|
207
|
+
# CreditAccount.find_or_create_by(user_id: user.id)
|
208
|
+
# rescue ActiveRecord::RecordNotUnique
|
209
|
+
# retry
|
210
|
+
# end
|
211
|
+
#
|
212
|
+
def find_or_create_by(attributes, &block)
|
213
|
+
find_by(attributes) || create(attributes, &block)
|
214
|
+
end
|
118
215
|
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
216
|
+
# Like <tt>find_or_create_by</tt>, but calls <tt>create!</tt> so an exception
|
217
|
+
# is raised if the created record is invalid.
|
218
|
+
def find_or_create_by!(attributes, &block)
|
219
|
+
find_by(attributes) || create!(attributes, &block)
|
220
|
+
end
|
124
221
|
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
else
|
130
|
-
@records = default_scoped.to_a
|
131
|
-
end
|
222
|
+
# Like <tt>find_or_create_by</tt>, but calls <tt>new</tt> instead of <tt>create</tt>.
|
223
|
+
def find_or_initialize_by(attributes, &block)
|
224
|
+
find_by(attributes) || new(attributes, &block)
|
225
|
+
end
|
132
226
|
|
133
|
-
|
227
|
+
# Runs EXPLAIN on the query or queries triggered by this relation and
|
228
|
+
# returns the result as a string. The string is formatted imitating the
|
229
|
+
# ones printed by the database shell.
|
230
|
+
#
|
231
|
+
# Note that this method actually runs the queries, since the results of some
|
232
|
+
# are needed by the next ones when eager loading is going on.
|
233
|
+
#
|
234
|
+
# Please see further details in the
|
235
|
+
# {Active Record Query Interface guide}[http://guides.rubyonrails.org/active_record_querying.html#running-explain].
|
236
|
+
def explain
|
237
|
+
#TODO: Fix for binds.
|
238
|
+
exec_explain(collecting_queries_for_explain { exec_queries })
|
239
|
+
end
|
240
|
+
|
241
|
+
# Converts relation objects to Array.
|
242
|
+
def to_a
|
243
|
+
load
|
134
244
|
@records
|
135
245
|
end
|
136
246
|
|
247
|
+
# Serializes the relation objects Array.
|
248
|
+
def encode_with(coder)
|
249
|
+
coder.represent_seq(nil, to_a)
|
250
|
+
end
|
251
|
+
|
137
252
|
def as_json(options = nil) #:nodoc:
|
138
253
|
to_a.as_json(options)
|
139
254
|
end
|
140
255
|
|
141
256
|
# Returns size of the records.
|
142
257
|
def size
|
143
|
-
loaded? ? @records.length : count
|
258
|
+
loaded? ? @records.length : count(:all)
|
144
259
|
end
|
145
260
|
|
146
261
|
# Returns true if there are no records.
|
147
262
|
def empty?
|
148
263
|
return @records.empty? if loaded?
|
149
264
|
|
150
|
-
|
151
|
-
|
265
|
+
if limit_value == 0
|
266
|
+
true
|
267
|
+
else
|
268
|
+
c = count(:all)
|
269
|
+
c.respond_to?(:zero?) ? c.zero? : c.empty?
|
270
|
+
end
|
152
271
|
end
|
153
272
|
|
273
|
+
# Returns true if there are any records.
|
154
274
|
def any?
|
155
275
|
if block_given?
|
156
276
|
to_a.any? { |*block_args| yield(*block_args) }
|
@@ -159,80 +279,70 @@ module ActiveRecord
|
|
159
279
|
end
|
160
280
|
end
|
161
281
|
|
282
|
+
# Returns true if there is more than one record.
|
162
283
|
def many?
|
163
284
|
if block_given?
|
164
285
|
to_a.many? { |*block_args| yield(*block_args) }
|
165
286
|
else
|
166
|
-
|
287
|
+
limit_value ? to_a.many? : size > 1
|
167
288
|
end
|
168
289
|
end
|
169
290
|
|
170
291
|
# Scope all queries to the current scope.
|
171
292
|
#
|
172
|
-
#
|
173
|
-
#
|
174
|
-
# Comment.where(:post_id => 1).scoping do
|
175
|
-
# Comment.first # SELECT * FROM comments WHERE post_id = 1
|
293
|
+
# Comment.where(post_id: 1).scoping do
|
294
|
+
# Comment.first
|
176
295
|
# end
|
296
|
+
# # => SELECT "comments".* FROM "comments" WHERE "comments"."post_id" = 1 ORDER BY "comments"."id" ASC LIMIT 1
|
177
297
|
#
|
178
298
|
# Please check unscoped if you want to remove all previous scopes (including
|
179
299
|
# the default_scope) during the execution of a block.
|
180
300
|
def scoping
|
181
|
-
|
301
|
+
previous, klass.current_scope = klass.current_scope, self
|
302
|
+
yield
|
303
|
+
ensure
|
304
|
+
klass.current_scope = previous
|
182
305
|
end
|
183
306
|
|
184
|
-
# Updates all records with details given
|
185
|
-
#
|
186
|
-
#
|
187
|
-
#
|
307
|
+
# Updates all records in the current relation with details given. This method constructs a single SQL UPDATE
|
308
|
+
# 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. Values passed to `update_all` will not go through
|
310
|
+
# ActiveRecord's type-casting behavior. It should receive only values that can be passed as-is to the SQL
|
311
|
+
# database.
|
188
312
|
#
|
189
313
|
# ==== Parameters
|
190
314
|
#
|
191
315
|
# * +updates+ - A string, array, or hash representing the SET part of an SQL statement.
|
192
|
-
# * +conditions+ - A string, array, or hash representing the WHERE part of an SQL statement.
|
193
|
-
# See conditions in the intro.
|
194
|
-
# * +options+ - Additional options are <tt>:limit</tt> and <tt>:order</tt>, see the examples for usage.
|
195
316
|
#
|
196
317
|
# ==== Examples
|
197
318
|
#
|
198
319
|
# # Update all customers with the given attributes
|
199
|
-
# Customer.update_all :
|
320
|
+
# Customer.update_all wants_email: true
|
200
321
|
#
|
201
322
|
# # Update all books with 'Rails' in their title
|
202
|
-
# Book.
|
203
|
-
#
|
204
|
-
# # Update all avatars migrated more than a week ago
|
205
|
-
# Avatar.update_all ['migrated_at = ?', Time.now.utc], ['migrated_at > ?', 1.week.ago]
|
323
|
+
# Book.where('title LIKE ?', '%Rails%').update_all(author: 'David')
|
206
324
|
#
|
207
325
|
# # Update all books that match conditions, but limit it to 5 ordered by date
|
208
|
-
# Book.
|
209
|
-
|
210
|
-
|
211
|
-
# Book.where('title LIKE ?', '%Rails%').update_all(:author => 'David')
|
212
|
-
#
|
213
|
-
# # The same idea applies to limit and order
|
214
|
-
# Book.where('title LIKE ?', '%Rails%').order(:created_at).limit(5).update_all(:author => 'David')
|
215
|
-
def update_all(updates, conditions = nil, options = {})
|
216
|
-
IdentityMap.repository[symbolized_base_class].clear if IdentityMap.enabled?
|
217
|
-
if conditions || options.present?
|
218
|
-
where(conditions).apply_finder_options(options.slice(:limit, :order)).update_all(updates)
|
219
|
-
else
|
220
|
-
stmt = Arel::UpdateManager.new(arel.engine)
|
326
|
+
# Book.where('title LIKE ?', '%Rails%').order(:created_at).limit(5).update_all(author: 'David')
|
327
|
+
def update_all(updates)
|
328
|
+
raise ArgumentError, "Empty list of attributes to change" if updates.blank?
|
221
329
|
|
222
|
-
|
223
|
-
stmt.table(table)
|
224
|
-
stmt.key = table[primary_key]
|
330
|
+
stmt = Arel::UpdateManager.new(arel.engine)
|
225
331
|
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
stmt.take(arel.limit)
|
230
|
-
stmt.order(*arel.orders)
|
231
|
-
stmt.wheres = arel.constraints
|
232
|
-
end
|
332
|
+
stmt.set Arel.sql(@klass.send(:sanitize_sql_for_assignment, updates))
|
333
|
+
stmt.table(table)
|
334
|
+
stmt.key = table[primary_key]
|
233
335
|
|
234
|
-
|
336
|
+
if joins_values.any?
|
337
|
+
@klass.connection.join_to_update(stmt, arel)
|
338
|
+
else
|
339
|
+
stmt.take(arel.limit)
|
340
|
+
stmt.order(*arel.orders)
|
341
|
+
stmt.wheres = arel.constraints
|
235
342
|
end
|
343
|
+
|
344
|
+
bvs = arel.bind_values + bind_values
|
345
|
+
@klass.connection.update stmt, 'SQL', bvs
|
236
346
|
end
|
237
347
|
|
238
348
|
# Updates an object (or multiple objects) and saves it to the database, if validations pass.
|
@@ -246,29 +356,26 @@ module ActiveRecord
|
|
246
356
|
# ==== Examples
|
247
357
|
#
|
248
358
|
# # Updates one record
|
249
|
-
# Person.update(15, :
|
359
|
+
# Person.update(15, user_name: 'Samuel', group: 'expert')
|
250
360
|
#
|
251
361
|
# # Updates multiple records
|
252
362
|
# people = { 1 => { "first_name" => "David" }, 2 => { "first_name" => "Jeremy" } }
|
253
363
|
# Person.update(people.keys, people.values)
|
254
364
|
def update(id, attributes)
|
255
365
|
if id.is_a?(Array)
|
256
|
-
idx
|
257
|
-
id.collect { |one_id| idx += 1; update(one_id, attributes[idx]) }
|
366
|
+
id.map.with_index { |one_id, idx| update(one_id, attributes[idx]) }
|
258
367
|
else
|
259
368
|
object = find(id)
|
260
|
-
object.
|
369
|
+
object.update(attributes)
|
261
370
|
object
|
262
371
|
end
|
263
372
|
end
|
264
373
|
|
265
374
|
# Destroys the records matching +conditions+ by instantiating each
|
266
375
|
# record and calling its +destroy+ method. Each object's callbacks are
|
267
|
-
# executed (including <tt>:dependent</tt> association options
|
268
|
-
# +before_destroy+/+after_destroy+ Observer methods). Returns the
|
376
|
+
# executed (including <tt>:dependent</tt> association options). Returns the
|
269
377
|
# collection of objects that were destroyed; each will be frozen, to
|
270
|
-
# reflect that no changes should be made (since they can't be
|
271
|
-
# persisted).
|
378
|
+
# reflect that no changes should be made (since they can't be persisted).
|
272
379
|
#
|
273
380
|
# Note: Instantiation, callback execution, and deletion of each
|
274
381
|
# record can be time consuming when you're removing many records at
|
@@ -287,8 +394,8 @@ module ActiveRecord
|
|
287
394
|
# ==== Examples
|
288
395
|
#
|
289
396
|
# Person.destroy_all("last_login < '2004-04-04'")
|
290
|
-
# Person.destroy_all(:
|
291
|
-
# Person.where(:
|
397
|
+
# Person.destroy_all(status: "inactive")
|
398
|
+
# Person.where(age: 0..18).destroy_all
|
292
399
|
def destroy_all(conditions = nil)
|
293
400
|
if conditions
|
294
401
|
where(conditions).destroy_all
|
@@ -297,8 +404,8 @@ module ActiveRecord
|
|
297
404
|
end
|
298
405
|
end
|
299
406
|
|
300
|
-
# Destroy an object (or multiple objects) that has the given id
|
301
|
-
# therefore all callbacks and filters are fired off before the object is deleted.
|
407
|
+
# Destroy an object (or multiple objects) that has the given id. The object is instantiated first,
|
408
|
+
# therefore all callbacks and filters are fired off before the object is deleted. This method is
|
302
409
|
# less efficient than ActiveRecord#delete but allows cleanup methods and other actions to be run.
|
303
410
|
#
|
304
411
|
# This essentially finds the object (or multiple objects) with the given id, creates a new object
|
@@ -324,32 +431,51 @@ module ActiveRecord
|
|
324
431
|
end
|
325
432
|
end
|
326
433
|
|
327
|
-
# Deletes the records matching +conditions+ without instantiating the records
|
328
|
-
# calling the +destroy+ method nor invoking callbacks. This
|
329
|
-
# goes straight to the database, much more
|
330
|
-
#
|
331
|
-
#
|
332
|
-
#
|
333
|
-
# ==== Parameters
|
334
|
-
#
|
335
|
-
# * +conditions+ - Conditions are specified the same way as with +find+ method.
|
336
|
-
#
|
337
|
-
# ==== Example
|
434
|
+
# Deletes the records matching +conditions+ without instantiating the records
|
435
|
+
# first, and hence not calling the +destroy+ method nor invoking callbacks. This
|
436
|
+
# is a single SQL DELETE statement that goes straight to the database, much more
|
437
|
+
# efficient than +destroy_all+. Be careful with relations though, in particular
|
438
|
+
# <tt>:dependent</tt> rules defined on associations are not honored. Returns the
|
439
|
+
# number of rows affected.
|
338
440
|
#
|
339
441
|
# Post.delete_all("person_id = 5 AND (category = 'Something' OR category = 'Else')")
|
340
442
|
# Post.delete_all(["person_id = ? AND (category = ? OR category = ?)", 5, 'Something', 'Else'])
|
341
|
-
# Post.where(:
|
443
|
+
# Post.where(person_id: 5).where(category: ['Something', 'Else']).delete_all
|
342
444
|
#
|
343
445
|
# Both calls delete the affected posts all at once with a single DELETE statement.
|
344
446
|
# If you need to destroy dependent associations or call your <tt>before_*</tt> or
|
345
447
|
# +after_destroy+ callbacks, use the +destroy_all+ method instead.
|
448
|
+
#
|
449
|
+
# If an invalid method is supplied, +delete_all+ raises an ActiveRecord error:
|
450
|
+
#
|
451
|
+
# Post.limit(100).delete_all
|
452
|
+
# # => ActiveRecord::ActiveRecordError: delete_all doesn't support limit
|
346
453
|
def delete_all(conditions = nil)
|
347
|
-
|
454
|
+
invalid_methods = INVALID_METHODS_FOR_DELETE_ALL.select { |method|
|
455
|
+
if MULTI_VALUE_METHODS.include?(method)
|
456
|
+
send("#{method}_values").any?
|
457
|
+
else
|
458
|
+
send("#{method}_value")
|
459
|
+
end
|
460
|
+
}
|
461
|
+
if invalid_methods.any?
|
462
|
+
raise ActiveRecordError.new("delete_all doesn't support #{invalid_methods.join(', ')}")
|
463
|
+
end
|
464
|
+
|
348
465
|
if conditions
|
349
466
|
where(conditions).delete_all
|
350
467
|
else
|
351
|
-
|
352
|
-
|
468
|
+
stmt = Arel::DeleteManager.new(arel.engine)
|
469
|
+
stmt.from(table)
|
470
|
+
|
471
|
+
if joins_values.any?
|
472
|
+
@klass.connection.join_to_delete(stmt, arel, table[primary_key])
|
473
|
+
else
|
474
|
+
stmt.wheres = arel.constraints
|
475
|
+
end
|
476
|
+
|
477
|
+
bvs = arel.bind_values + bind_values
|
478
|
+
affected = @klass.connection.delete(stmt, 'SQL', bvs)
|
353
479
|
|
354
480
|
reset
|
355
481
|
affected
|
@@ -359,8 +485,7 @@ module ActiveRecord
|
|
359
485
|
# Deletes the row with a primary key matching the +id+ argument, using a
|
360
486
|
# SQL +DELETE+ statement, and returns the number of rows deleted. Active
|
361
487
|
# Record objects are not instantiated, so the object's callbacks are not
|
362
|
-
# executed, including any <tt>:dependent</tt> association options
|
363
|
-
# Observer methods.
|
488
|
+
# executed, including any <tt>:dependent</tt> association options.
|
364
489
|
#
|
365
490
|
# You can delete multiple rows at once by passing an Array of <tt>id</tt>s.
|
366
491
|
#
|
@@ -377,55 +502,110 @@ module ActiveRecord
|
|
377
502
|
# # Delete multiple rows
|
378
503
|
# Todo.delete([2,3,4])
|
379
504
|
def delete(id_or_array)
|
380
|
-
IdentityMap.remove_by_id(self.symbolized_base_class, id_or_array) if IdentityMap.enabled?
|
381
505
|
where(primary_key => id_or_array).delete_all
|
382
506
|
end
|
383
507
|
|
508
|
+
# Causes the records to be loaded from the database if they have not
|
509
|
+
# been loaded already. You can use this if for some reason you need
|
510
|
+
# to explicitly load some records before actually using them. The
|
511
|
+
# return value is the relation itself, not the records.
|
512
|
+
#
|
513
|
+
# Post.where(published: true).load # => #<ActiveRecord::Relation>
|
514
|
+
def load
|
515
|
+
exec_queries unless loaded?
|
516
|
+
|
517
|
+
self
|
518
|
+
end
|
519
|
+
|
520
|
+
# Forces reloading of relation.
|
384
521
|
def reload
|
385
522
|
reset
|
386
|
-
|
387
|
-
self
|
523
|
+
load
|
388
524
|
end
|
389
525
|
|
390
526
|
def reset
|
391
|
-
@
|
527
|
+
@last = @to_sql = @order_clause = @scope_for_create = @arel = @loaded = nil
|
392
528
|
@should_eager_load = @join_dependency = nil
|
393
529
|
@records = []
|
530
|
+
@offsets = {}
|
394
531
|
self
|
395
532
|
end
|
396
533
|
|
534
|
+
# Returns sql statement for the relation.
|
535
|
+
#
|
536
|
+
# User.where(name: 'Oscar').to_sql
|
537
|
+
# # => SELECT "users".* FROM "users" WHERE "users"."name" = 'Oscar'
|
397
538
|
def to_sql
|
398
|
-
@to_sql ||=
|
399
|
-
|
400
|
-
|
401
|
-
|
402
|
-
|
403
|
-
|
539
|
+
@to_sql ||= begin
|
540
|
+
relation = self
|
541
|
+
connection = klass.connection
|
542
|
+
visitor = connection.visitor
|
543
|
+
|
544
|
+
if eager_loading?
|
545
|
+
find_with_associations { |rel| relation = rel }
|
546
|
+
end
|
547
|
+
|
548
|
+
arel = relation.arel
|
549
|
+
binds = (arel.bind_values + relation.bind_values).dup
|
550
|
+
binds.map! { |bv| connection.quote(*bv.reverse) }
|
551
|
+
collect = visitor.accept(arel.ast, Arel::Collectors::Bind.new)
|
552
|
+
collect.substitute_binds(binds).join
|
553
|
+
end
|
554
|
+
end
|
555
|
+
|
556
|
+
# Returns a hash of where conditions.
|
557
|
+
#
|
558
|
+
# User.where(name: 'Oscar').where_values_hash
|
559
|
+
# # => {name: "Oscar"}
|
560
|
+
def where_values_hash(relation_table_name = table_name)
|
561
|
+
equalities = where_values.grep(Arel::Nodes::Equality).find_all { |node|
|
562
|
+
node.left.relation.name == relation_table_name
|
404
563
|
}
|
405
564
|
|
406
|
-
Hash[
|
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
|
+
}]
|
407
577
|
end
|
408
578
|
|
409
579
|
def scope_for_create
|
410
580
|
@scope_for_create ||= where_values_hash.merge(create_with_value)
|
411
581
|
end
|
412
582
|
|
583
|
+
# Returns true if relation needs eager loading.
|
413
584
|
def eager_loading?
|
414
585
|
@should_eager_load ||=
|
415
|
-
|
416
|
-
|
586
|
+
eager_load_values.any? ||
|
587
|
+
includes_values.any? && (joined_includes_values.any? || references_eager_loaded_tables?)
|
417
588
|
end
|
418
589
|
|
419
590
|
# Joins that are also marked for preloading. In which case we should just eager load them.
|
420
591
|
# Note that this is a naive implementation because we could have strings and symbols which
|
421
592
|
# represent the same association, but that aren't matched by this. Also, we could have
|
422
|
-
# nested hashes which partially match, e.g. { :
|
593
|
+
# nested hashes which partially match, e.g. { a: :b } & { a: [:b, :c] }
|
423
594
|
def joined_includes_values
|
424
|
-
|
595
|
+
includes_values & joins_values
|
596
|
+
end
|
597
|
+
|
598
|
+
# +uniq+ and +uniq!+ are silently deprecated. +uniq_value+ delegates to +distinct_value+
|
599
|
+
# to maintain backwards compatibility. Use +distinct_value+ instead.
|
600
|
+
def uniq_value
|
601
|
+
distinct_value
|
425
602
|
end
|
426
603
|
|
604
|
+
# Compares two relations for equality.
|
427
605
|
def ==(other)
|
428
606
|
case other
|
607
|
+
when Associations::CollectionProxy, AssociationRelation
|
608
|
+
self == other.to_a
|
429
609
|
when Relation
|
430
610
|
other.to_sql == to_sql
|
431
611
|
when Array
|
@@ -433,36 +613,48 @@ module ActiveRecord
|
|
433
613
|
end
|
434
614
|
end
|
435
615
|
|
436
|
-
def
|
437
|
-
to_a
|
616
|
+
def pretty_print(q)
|
617
|
+
q.pp(self.to_a)
|
438
618
|
end
|
439
619
|
|
440
|
-
|
441
|
-
|
442
|
-
|
443
|
-
default_scope.default_scoped = false
|
444
|
-
default_scope
|
445
|
-
else
|
446
|
-
self
|
447
|
-
end
|
620
|
+
# Returns true if relation is blank.
|
621
|
+
def blank?
|
622
|
+
to_a.blank?
|
448
623
|
end
|
449
624
|
|
450
|
-
|
625
|
+
def values
|
626
|
+
Hash[@values]
|
627
|
+
end
|
451
628
|
|
452
|
-
def
|
453
|
-
|
454
|
-
|
455
|
-
|
456
|
-
|
457
|
-
elsif arel.respond_to?(method)
|
458
|
-
arel.send(method, *args, &block)
|
459
|
-
else
|
460
|
-
super
|
461
|
-
end
|
629
|
+
def inspect
|
630
|
+
entries = to_a.take([limit_value, 11].compact.min).map!(&:inspect)
|
631
|
+
entries[10] = '...' if entries.size == 11
|
632
|
+
|
633
|
+
"#<#{self.class.name} [#{entries.join(', ')}]>"
|
462
634
|
end
|
463
635
|
|
464
636
|
private
|
465
637
|
|
638
|
+
def exec_queries
|
639
|
+
@records = eager_loading? ? find_with_associations : @klass.find_by_sql(arel, arel.bind_values + bind_values)
|
640
|
+
|
641
|
+
preload = preload_values
|
642
|
+
preload += includes_values unless eager_loading?
|
643
|
+
preloader = build_preloader
|
644
|
+
preload.each do |associations|
|
645
|
+
preloader.preload @records, associations
|
646
|
+
end
|
647
|
+
|
648
|
+
@records.each { |record| record.readonly! } if readonly_value
|
649
|
+
|
650
|
+
@loaded = true
|
651
|
+
@records
|
652
|
+
end
|
653
|
+
|
654
|
+
def build_preloader
|
655
|
+
ActiveRecord::Associations::Preloader.new
|
656
|
+
end
|
657
|
+
|
466
658
|
def references_eager_loaded_tables?
|
467
659
|
joined_tables = arel.join_sources.map do |join|
|
468
660
|
if join.is_a?(Arel::Nodes::StringJoin)
|
@@ -477,7 +669,7 @@ module ActiveRecord
|
|
477
669
|
# always convert table names to downcase as in Oracle quoted table names are in uppercase
|
478
670
|
joined_tables = joined_tables.flatten.compact.map { |t| t.downcase }.uniq
|
479
671
|
|
480
|
-
(
|
672
|
+
(references_values - joined_tables).any?
|
481
673
|
end
|
482
674
|
|
483
675
|
def tables_in_string(string)
|
@@ -486,6 +678,5 @@ module ActiveRecord
|
|
486
678
|
# ignore raw_sql_ that is used by Oracle adapter as alias for limit/offset subqueries
|
487
679
|
string.scan(/([a-zA-Z_][.\w]+).?\./).flatten.map{ |s| s.downcase }.uniq - ['raw_sql_']
|
488
680
|
end
|
489
|
-
|
490
681
|
end
|
491
682
|
end
|