activerecord 4.2.0 → 5.0.0
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 +1537 -789
- 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/aggregations.rb +37 -23
- data/lib/active_record/association_relation.rb +16 -3
- data/lib/active_record/associations/alias_tracker.rb +19 -16
- data/lib/active_record/associations/association.rb +23 -9
- data/lib/active_record/associations/association_scope.rb +74 -102
- data/lib/active_record/associations/belongs_to_association.rb +26 -29
- 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 +12 -20
- data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +22 -15
- 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 +3 -10
- data/lib/active_record/associations/collection_association.rb +61 -33
- data/lib/active_record/associations/collection_proxy.rb +81 -35
- data/lib/active_record/associations/foreign_association.rb +11 -0
- data/lib/active_record/associations/has_many_association.rb +21 -57
- data/lib/active_record/associations/has_many_through_association.rb +15 -45
- data/lib/active_record/associations/has_one_association.rb +13 -5
- data/lib/active_record/associations/join_dependency/join_association.rb +20 -8
- data/lib/active_record/associations/join_dependency.rb +37 -21
- data/lib/active_record/associations/preloader/association.rb +51 -53
- data/lib/active_record/associations/preloader/collection_association.rb +0 -6
- 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/through_association.rb +27 -14
- data/lib/active_record/associations/preloader.rb +18 -8
- data/lib/active_record/associations/singular_association.rb +8 -8
- data/lib/active_record/associations/through_association.rb +22 -9
- data/lib/active_record/associations.rb +321 -212
- data/lib/active_record/attribute/user_provided_default.rb +28 -0
- data/lib/active_record/attribute.rb +79 -15
- data/lib/active_record/attribute_assignment.rb +20 -141
- data/lib/active_record/attribute_decorators.rb +6 -5
- data/lib/active_record/attribute_methods/before_type_cast.rb +6 -1
- data/lib/active_record/attribute_methods/dirty.rb +51 -81
- data/lib/active_record/attribute_methods/primary_key.rb +2 -2
- 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 +65 -14
- data/lib/active_record/attribute_methods/write.rb +14 -38
- data/lib/active_record/attribute_methods.rb +70 -45
- data/lib/active_record/attribute_mutation_tracker.rb +70 -0
- data/lib/active_record/attribute_set/builder.rb +37 -15
- data/lib/active_record/attribute_set.rb +34 -3
- data/lib/active_record/attributes.rb +199 -73
- data/lib/active_record/autosave_association.rb +73 -25
- data/lib/active_record/base.rb +35 -27
- 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 +40 -0
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +457 -181
- data/lib/active_record/connection_adapters/abstract/database_limits.rb +3 -3
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +83 -59
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +3 -3
- data/lib/active_record/connection_adapters/abstract/quoting.rb +74 -9
- data/lib/active_record/connection_adapters/abstract/savepoints.rb +4 -4
- data/lib/active_record/connection_adapters/abstract/schema_creation.rb +61 -39
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +246 -185
- data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +72 -17
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +438 -136
- data/lib/active_record/connection_adapters/abstract/transaction.rb +53 -40
- data/lib/active_record/connection_adapters/abstract_adapter.rb +166 -66
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +429 -335
- 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 +125 -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 +26 -177
- data/lib/active_record/connection_adapters/postgresql/column.rb +5 -10
- data/lib/active_record/connection_adapters/postgresql/database_statements.rb +11 -73
- data/lib/active_record/connection_adapters/postgresql/explain_pretty_printer.rb +42 -0
- data/lib/active_record/connection_adapters/postgresql/oid/array.rb +27 -56
- data/lib/active_record/connection_adapters/postgresql/oid/bit.rb +2 -2
- data/lib/active_record/connection_adapters/postgresql/oid/bytea.rb +2 -1
- data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +3 -1
- data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +7 -13
- data/lib/active_record/connection_adapters/postgresql/oid/enum.rb +3 -1
- data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +3 -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/type_map_initializer.rb +17 -5
- 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/oid.rb +1 -6
- data/lib/active_record/connection_adapters/postgresql/quoting.rb +26 -18
- 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 +248 -154
- data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +35 -0
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +258 -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 +150 -209
- data/lib/active_record/connection_adapters/statement_pool.rb +31 -12
- data/lib/active_record/connection_handling.rb +38 -15
- data/lib/active_record/core.rb +109 -114
- data/lib/active_record/counter_cache.rb +14 -25
- data/lib/active_record/dynamic_matchers.rb +1 -20
- data/lib/active_record/enum.rb +115 -79
- data/lib/active_record/errors.rb +88 -48
- data/lib/active_record/explain_registry.rb +1 -1
- data/lib/active_record/explain_subscriber.rb +2 -2
- data/lib/active_record/fixture_set/file.rb +26 -5
- data/lib/active_record/fixtures.rb +84 -46
- data/lib/active_record/gem_version.rb +2 -2
- data/lib/active_record/inheritance.rb +32 -40
- data/lib/active_record/integration.rb +4 -4
- data/lib/active_record/internal_metadata.rb +56 -0
- data/lib/active_record/legacy_yaml_adapter.rb +46 -0
- data/lib/active_record/locale/en.yml +3 -2
- data/lib/active_record/locking/optimistic.rb +27 -25
- data/lib/active_record/locking/pessimistic.rb +1 -1
- data/lib/active_record/log_subscriber.rb +43 -21
- data/lib/active_record/migration/command_recorder.rb +59 -18
- data/lib/active_record/migration/compatibility.rb +126 -0
- data/lib/active_record/migration.rb +372 -114
- data/lib/active_record/model_schema.rb +128 -38
- data/lib/active_record/nested_attributes.rb +71 -32
- data/lib/active_record/no_touching.rb +1 -1
- data/lib/active_record/null_relation.rb +16 -8
- data/lib/active_record/persistence.rb +124 -80
- data/lib/active_record/query_cache.rb +15 -18
- data/lib/active_record/querying.rb +10 -9
- data/lib/active_record/railtie.rb +28 -19
- data/lib/active_record/railties/controller_runtime.rb +1 -1
- data/lib/active_record/railties/databases.rake +67 -51
- data/lib/active_record/readonly_attributes.rb +1 -1
- data/lib/active_record/reflection.rb +318 -139
- data/lib/active_record/relation/batches/batch_enumerator.rb +67 -0
- data/lib/active_record/relation/batches.rb +139 -34
- data/lib/active_record/relation/calculations.rb +80 -102
- data/lib/active_record/relation/delegation.rb +7 -20
- data/lib/active_record/relation/finder_methods.rb +167 -97
- data/lib/active_record/relation/from_clause.rb +32 -0
- data/lib/active_record/relation/merger.rb +38 -41
- data/lib/active_record/relation/predicate_builder/array_handler.rb +12 -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/predicate_builder.rb +124 -82
- data/lib/active_record/relation/query_attribute.rb +19 -0
- data/lib/active_record/relation/query_methods.rb +323 -257
- data/lib/active_record/relation/record_fetch_warning.rb +49 -0
- data/lib/active_record/relation/spawn_methods.rb +11 -10
- 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/relation.rb +176 -115
- data/lib/active_record/result.rb +4 -3
- data/lib/active_record/runtime_registry.rb +1 -1
- data/lib/active_record/sanitization.rb +95 -66
- data/lib/active_record/schema.rb +26 -22
- data/lib/active_record/schema_dumper.rb +62 -38
- data/lib/active_record/schema_migration.rb +11 -17
- data/lib/active_record/scoping/default.rb +24 -9
- data/lib/active_record/scoping/named.rb +49 -28
- data/lib/active_record/scoping.rb +32 -15
- data/lib/active_record/secure_token.rb +38 -0
- data/lib/active_record/serialization.rb +2 -4
- data/lib/active_record/statement_cache.rb +16 -14
- data/lib/active_record/store.rb +8 -3
- data/lib/active_record/suppressor.rb +58 -0
- data/lib/active_record/table_metadata.rb +68 -0
- data/lib/active_record/tasks/database_tasks.rb +59 -42
- data/lib/active_record/tasks/mysql_database_tasks.rb +32 -26
- data/lib/active_record/tasks/postgresql_database_tasks.rb +29 -9
- 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 +58 -0
- data/lib/active_record/transactions.rb +159 -67
- data/lib/active_record/type/adapter_specific_registry.rb +130 -0
- data/lib/active_record/type/date.rb +2 -41
- data/lib/active_record/type/date_time.rb +2 -38
- data/lib/active_record/type/hash_lookup_type_map.rb +8 -2
- data/lib/active_record/type/internal/abstract_json.rb +29 -0
- data/lib/active_record/type/internal/timezone.rb +15 -0
- data/lib/active_record/type/serialized.rb +21 -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.rb +66 -17
- data/lib/active_record/type_caster/connection.rb +29 -0
- data/lib/active_record/type_caster/map.rb +19 -0
- data/lib/active_record/type_caster.rb +7 -0
- 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 +29 -18
- data/lib/active_record/validations.rb +33 -32
- data/lib/active_record.rb +9 -2
- data/lib/rails/generators/active_record/migration/migration_generator.rb +7 -4
- data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb +8 -6
- data/lib/rails/generators/active_record/migration/templates/migration.rb +8 -7
- data/lib/rails/generators/active_record/migration.rb +7 -0
- data/lib/rails/generators/active_record/model/model_generator.rb +32 -15
- 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 +60 -34
- data/lib/active_record/connection_adapters/mysql_adapter.rb +0 -491
- 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 -30
- data/lib/active_record/type/decimal.rb +0 -40
- 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 -55
- 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 -36
- 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 -101
@@ -1,14 +1,14 @@
|
|
1
1
|
module ActiveRecord
|
2
2
|
module ConnectionHandling
|
3
|
-
RAILS_ENV = -> { (Rails.env if defined?(Rails)) || ENV["RAILS_ENV"] || ENV["RACK_ENV"] }
|
3
|
+
RAILS_ENV = -> { (Rails.env if defined?(Rails.env)) || ENV["RAILS_ENV"] || ENV["RACK_ENV"] }
|
4
4
|
DEFAULT_ENV = -> { RAILS_ENV.call || "default_env" }
|
5
5
|
|
6
6
|
# Establishes the connection to the database. Accepts a hash as input where
|
7
7
|
# the <tt>:adapter</tt> key must be specified with the name of a database adapter (in lower-case)
|
8
|
-
# example for regular databases (MySQL,
|
8
|
+
# example for regular databases (MySQL, PostgreSQL, etc):
|
9
9
|
#
|
10
10
|
# ActiveRecord::Base.establish_connection(
|
11
|
-
# adapter: "
|
11
|
+
# adapter: "mysql2",
|
12
12
|
# host: "localhost",
|
13
13
|
# username: "myuser",
|
14
14
|
# password: "mypass",
|
@@ -35,26 +35,30 @@ module ActiveRecord
|
|
35
35
|
# "postgres://myuser:mypass@localhost/somedatabase"
|
36
36
|
# )
|
37
37
|
#
|
38
|
-
# In case
|
39
|
-
# automatically loads the contents of config/database.yml into it),
|
38
|
+
# In case {ActiveRecord::Base.configurations}[rdoc-ref:Core.configurations]
|
39
|
+
# is set (Rails automatically loads the contents of config/database.yml into it),
|
40
40
|
# a symbol can also be given as argument, representing a key in the
|
41
41
|
# configuration hash:
|
42
42
|
#
|
43
43
|
# ActiveRecord::Base.establish_connection(:production)
|
44
44
|
#
|
45
|
-
# The exceptions AdapterNotSpecified, AdapterNotFound and ArgumentError
|
45
|
+
# The exceptions AdapterNotSpecified, AdapterNotFound and +ArgumentError+
|
46
46
|
# may be returned on an error.
|
47
47
|
def establish_connection(spec = nil)
|
48
|
+
raise RuntimeError, "Anonymous class is not allowed." unless name
|
49
|
+
|
48
50
|
spec ||= DEFAULT_ENV.call.to_sym
|
49
51
|
resolver = ConnectionAdapters::ConnectionSpecification::Resolver.new configurations
|
50
|
-
|
52
|
+
# TODO: uses name on establish_connection, for backwards compatibility
|
53
|
+
spec = resolver.spec(spec, self == Base ? "primary" : name)
|
51
54
|
|
52
55
|
unless respond_to?(spec.adapter_method)
|
53
56
|
raise AdapterNotFound, "database configuration specifies nonexistent #{spec.config[:adapter]} adapter"
|
54
57
|
end
|
55
58
|
|
56
|
-
remove_connection
|
57
|
-
|
59
|
+
remove_connection(spec.name)
|
60
|
+
self.connection_specification_name = spec.name
|
61
|
+
connection_handler.establish_connection spec
|
58
62
|
end
|
59
63
|
|
60
64
|
class MergeAndResolveDefaultUrlConfig # :nodoc:
|
@@ -87,8 +91,19 @@ module ActiveRecord
|
|
87
91
|
retrieve_connection
|
88
92
|
end
|
89
93
|
|
94
|
+
attr_writer :connection_specification_name
|
95
|
+
|
96
|
+
# Return the specification id from this class otherwise look it up
|
97
|
+
# in the parent.
|
98
|
+
def connection_specification_name
|
99
|
+
if !defined?(@connection_specification_name) || @connection_specification_name.nil?
|
100
|
+
return self == Base ? "primary" : superclass.connection_specification_name
|
101
|
+
end
|
102
|
+
@connection_specification_name
|
103
|
+
end
|
104
|
+
|
90
105
|
def connection_id
|
91
|
-
ActiveRecord::RuntimeRegistry.connection_id
|
106
|
+
ActiveRecord::RuntimeRegistry.connection_id ||= Thread.current.object_id
|
92
107
|
end
|
93
108
|
|
94
109
|
def connection_id=(connection_id)
|
@@ -106,20 +121,28 @@ module ActiveRecord
|
|
106
121
|
end
|
107
122
|
|
108
123
|
def connection_pool
|
109
|
-
connection_handler.retrieve_connection_pool(
|
124
|
+
connection_handler.retrieve_connection_pool(connection_specification_name) or raise ConnectionNotEstablished
|
110
125
|
end
|
111
126
|
|
112
127
|
def retrieve_connection
|
113
|
-
connection_handler.retrieve_connection(
|
128
|
+
connection_handler.retrieve_connection(connection_specification_name)
|
114
129
|
end
|
115
130
|
|
116
131
|
# Returns +true+ if Active Record is connected.
|
117
132
|
def connected?
|
118
|
-
connection_handler.connected?(
|
133
|
+
connection_handler.connected?(connection_specification_name)
|
119
134
|
end
|
120
135
|
|
121
|
-
def remove_connection(
|
122
|
-
|
136
|
+
def remove_connection(name = nil)
|
137
|
+
name ||= @connection_specification_name if defined?(@connection_specification_name)
|
138
|
+
# if removing a connection that have a pool, we reset the
|
139
|
+
# connection_specification_name so it will use the parent
|
140
|
+
# pool.
|
141
|
+
if connection_handler.retrieve_connection_pool(name)
|
142
|
+
self.connection_specification_name = nil
|
143
|
+
end
|
144
|
+
|
145
|
+
connection_handler.remove_connection(name)
|
123
146
|
end
|
124
147
|
|
125
148
|
def clear_cache! # :nodoc:
|
data/lib/active_record/core.rb
CHANGED
@@ -70,6 +70,14 @@ module ActiveRecord
|
|
70
70
|
mattr_accessor :schema_format, instance_writer: false
|
71
71
|
self.schema_format = :ruby
|
72
72
|
|
73
|
+
##
|
74
|
+
# :singleton-method:
|
75
|
+
# Specifies if an error should be raised on query limit or order being
|
76
|
+
# ignored when doing batch queries. Useful in applications where the
|
77
|
+
# limit or scope being ignored is error-worthy, rather than a warning.
|
78
|
+
mattr_accessor :error_on_ignored_order_or_limit, instance_writer: false
|
79
|
+
self.error_on_ignored_order_or_limit = false
|
80
|
+
|
73
81
|
##
|
74
82
|
# :singleton-method:
|
75
83
|
# Specify whether or not to use timestamps for migration versions
|
@@ -85,17 +93,30 @@ module ActiveRecord
|
|
85
93
|
mattr_accessor :dump_schema_after_migration, instance_writer: false
|
86
94
|
self.dump_schema_after_migration = true
|
87
95
|
|
96
|
+
##
|
97
|
+
# :singleton-method:
|
98
|
+
# Specifies which database schemas to dump when calling db:structure:dump.
|
99
|
+
# If the value is :schema_search_path (the default), any schemas listed in
|
100
|
+
# schema_search_path are dumped. Use :all to dump all schemas regardless
|
101
|
+
# of schema_search_path, or a string of comma separated schemas for a
|
102
|
+
# custom list.
|
103
|
+
mattr_accessor :dump_schemas, instance_writer: false
|
104
|
+
self.dump_schemas = :schema_search_path
|
105
|
+
|
106
|
+
##
|
107
|
+
# :singleton-method:
|
108
|
+
# Specify a threshold for the size of query result sets. If the number of
|
109
|
+
# records in the set exceeds the threshold, a warning is logged. This can
|
110
|
+
# be used to identify queries which load thousands of records and
|
111
|
+
# potentially cause memory bloat.
|
112
|
+
mattr_accessor :warn_on_records_fetched_greater_than, instance_writer: false
|
113
|
+
self.warn_on_records_fetched_greater_than = nil
|
114
|
+
|
88
115
|
mattr_accessor :maintain_test_schema, instance_accessor: false
|
89
116
|
|
90
|
-
|
91
|
-
ActiveSupport::Deprecation.warn(<<-MSG.squish)
|
92
|
-
Implicit join references were removed with Rails 4.1.
|
93
|
-
Make sure to remove this configuration because it does nothing.
|
94
|
-
MSG
|
95
|
-
end
|
117
|
+
mattr_accessor :belongs_to_required_by_default, instance_accessor: false
|
96
118
|
|
97
119
|
class_attribute :default_connection_handler, instance_writer: false
|
98
|
-
class_attribute :find_by_statement_cache
|
99
120
|
|
100
121
|
def self.connection_handler
|
101
122
|
ActiveRecord::RuntimeRegistry.connection_handler || default_connection_handler
|
@@ -114,23 +135,22 @@ module ActiveRecord
|
|
114
135
|
super
|
115
136
|
end
|
116
137
|
|
117
|
-
def initialize_find_by_cache
|
118
|
-
|
138
|
+
def initialize_find_by_cache # :nodoc:
|
139
|
+
@find_by_statement_cache = { true => {}.extend(Mutex_m), false => {}.extend(Mutex_m) }
|
119
140
|
end
|
120
141
|
|
121
|
-
def inherited(child_class)
|
142
|
+
def inherited(child_class) # :nodoc:
|
143
|
+
# initialize cache at class definition for thread safety
|
122
144
|
child_class.initialize_find_by_cache
|
123
145
|
super
|
124
146
|
end
|
125
147
|
|
126
|
-
def find(*ids)
|
148
|
+
def find(*ids) # :nodoc:
|
127
149
|
# We don't have cache keys for this stuff yet
|
128
150
|
return super unless ids.length == 1
|
129
|
-
# Allow symbols to super to maintain compatibility for deprecated finders until Rails 5
|
130
|
-
return super if ids.first.kind_of?(Symbol)
|
131
151
|
return super if block_given? ||
|
132
152
|
primary_key.nil? ||
|
133
|
-
|
153
|
+
scope_attributes? ||
|
134
154
|
columns_hash.include?(inheritance_column) ||
|
135
155
|
ids.first.kind_of?(Array)
|
136
156
|
|
@@ -139,63 +159,60 @@ module ActiveRecord
|
|
139
159
|
id = id.id
|
140
160
|
ActiveSupport::Deprecation.warn(<<-MSG.squish)
|
141
161
|
You are passing an instance of ActiveRecord::Base to `find`.
|
142
|
-
Please pass the id of the object by calling `.id
|
162
|
+
Please pass the id of the object by calling `.id`.
|
143
163
|
MSG
|
144
164
|
end
|
165
|
+
|
145
166
|
key = primary_key
|
146
167
|
|
147
|
-
|
148
|
-
|
149
|
-
where(key => params.bind).limit(1)
|
150
|
-
}
|
168
|
+
statement = cached_find_by_statement(key) { |params|
|
169
|
+
where(key => params.bind).limit(1)
|
151
170
|
}
|
152
|
-
record =
|
171
|
+
record = statement.execute([id], self, connection).first
|
153
172
|
unless record
|
154
|
-
raise RecordNotFound
|
173
|
+
raise RecordNotFound.new("Couldn't find #{name} with '#{primary_key}'=#{id}",
|
174
|
+
name, primary_key, id)
|
155
175
|
end
|
156
176
|
record
|
157
177
|
rescue RangeError
|
158
|
-
raise RecordNotFound
|
178
|
+
raise RecordNotFound.new("Couldn't find #{name} with an out of range value for '#{primary_key}'",
|
179
|
+
name, primary_key)
|
159
180
|
end
|
160
181
|
|
161
|
-
def find_by(*args)
|
162
|
-
return super if
|
163
|
-
return super if default_scopes.any?
|
182
|
+
def find_by(*args) # :nodoc:
|
183
|
+
return super if scope_attributes? || !(Hash === args.first) || reflect_on_all_aggregations.any?
|
164
184
|
|
165
185
|
hash = args.first
|
166
186
|
|
167
187
|
return super if hash.values.any? { |v|
|
168
|
-
v.nil? || Array === v || Hash === v
|
188
|
+
v.nil? || Array === v || Hash === v || Relation === v
|
169
189
|
}
|
170
190
|
|
171
191
|
# We can't cache Post.find_by(author: david) ...yet
|
172
192
|
return super unless hash.keys.all? { |k| columns_hash.has_key?(k.to_s) }
|
173
193
|
|
174
|
-
|
194
|
+
keys = hash.keys
|
175
195
|
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
wheres = key.each_with_object({}) { |param,o|
|
180
|
-
o[param] = params.bind
|
181
|
-
}
|
182
|
-
klass.where(wheres).limit(1)
|
196
|
+
statement = cached_find_by_statement(keys) { |params|
|
197
|
+
wheres = keys.each_with_object({}) { |param, o|
|
198
|
+
o[param] = params.bind
|
183
199
|
}
|
200
|
+
where(wheres).limit(1)
|
184
201
|
}
|
185
202
|
begin
|
186
|
-
|
187
|
-
rescue TypeError
|
188
|
-
raise ActiveRecord::StatementInvalid
|
203
|
+
statement.execute(hash.values, self, connection).first
|
204
|
+
rescue TypeError
|
205
|
+
raise ActiveRecord::StatementInvalid
|
189
206
|
rescue RangeError
|
190
207
|
nil
|
191
208
|
end
|
192
209
|
end
|
193
210
|
|
194
|
-
def find_by!(*args)
|
195
|
-
find_by(*args) or raise RecordNotFound.new("Couldn't find #{name}")
|
211
|
+
def find_by!(*args) # :nodoc:
|
212
|
+
find_by(*args) or raise RecordNotFound.new("Couldn't find #{name}", name)
|
196
213
|
end
|
197
214
|
|
198
|
-
def initialize_generated_modules
|
215
|
+
def initialize_generated_modules # :nodoc:
|
199
216
|
generated_association_methods
|
200
217
|
end
|
201
218
|
|
@@ -216,7 +233,7 @@ module ActiveRecord
|
|
216
233
|
elsif !connected?
|
217
234
|
"#{super} (call '#{super}.connection' to establish a connection)"
|
218
235
|
elsif table_exists?
|
219
|
-
attr_list =
|
236
|
+
attr_list = attribute_types.map { |name, type| "#{name}: #{type.type}" } * ', '
|
220
237
|
"#{super}(#{attr_list})"
|
221
238
|
else
|
222
239
|
"#{super}(Table doesn't exist)"
|
@@ -234,30 +251,54 @@ module ActiveRecord
|
|
234
251
|
# scope :published_and_commented, -> { published.and(self.arel_table[:comments_count].gt(0)) }
|
235
252
|
# end
|
236
253
|
def arel_table # :nodoc:
|
237
|
-
@arel_table ||= Arel::Table.new(table_name,
|
254
|
+
@arel_table ||= Arel::Table.new(table_name, type_caster: type_caster)
|
238
255
|
end
|
239
256
|
|
240
257
|
# Returns the Arel engine.
|
241
258
|
def arel_engine # :nodoc:
|
242
259
|
@arel_engine ||=
|
243
|
-
if Base == self || connection_handler.retrieve_connection_pool(
|
260
|
+
if Base == self || connection_handler.retrieve_connection_pool(connection_specification_name)
|
244
261
|
self
|
245
262
|
else
|
246
263
|
superclass.arel_engine
|
247
264
|
end
|
248
265
|
end
|
249
266
|
|
267
|
+
def arel_attribute(name, table = arel_table) # :nodoc:
|
268
|
+
name = attribute_alias(name) if attribute_alias?(name)
|
269
|
+
table[name]
|
270
|
+
end
|
271
|
+
|
272
|
+
def predicate_builder # :nodoc:
|
273
|
+
@predicate_builder ||= PredicateBuilder.new(table_metadata)
|
274
|
+
end
|
275
|
+
|
276
|
+
def type_caster # :nodoc:
|
277
|
+
TypeCaster::Map.new(self)
|
278
|
+
end
|
279
|
+
|
250
280
|
private
|
251
281
|
|
252
|
-
def
|
253
|
-
|
282
|
+
def cached_find_by_statement(key, &block) # :nodoc:
|
283
|
+
cache = @find_by_statement_cache[connection.prepared_statements]
|
284
|
+
cache[key] || cache.synchronize {
|
285
|
+
cache[key] ||= StatementCache.create(connection, &block)
|
286
|
+
}
|
287
|
+
end
|
288
|
+
|
289
|
+
def relation # :nodoc:
|
290
|
+
relation = Relation.create(self, arel_table, predicate_builder)
|
254
291
|
|
255
|
-
if finder_needs_type_condition?
|
292
|
+
if finder_needs_type_condition? && !ignore_default_scope?
|
256
293
|
relation.where(type_condition).create_with(inheritance_column.to_sym => sti_name)
|
257
294
|
else
|
258
295
|
relation
|
259
296
|
end
|
260
297
|
end
|
298
|
+
|
299
|
+
def table_metadata # :nodoc:
|
300
|
+
TableMetadata.new(self, arel_table)
|
301
|
+
end
|
261
302
|
end
|
262
303
|
|
263
304
|
# New objects can be instantiated as either empty (pass no construction parameter) or pre-set with
|
@@ -268,32 +309,35 @@ module ActiveRecord
|
|
268
309
|
# ==== Example:
|
269
310
|
# # Instantiates a single new object
|
270
311
|
# User.new(first_name: 'Jamie')
|
271
|
-
def initialize(attributes = nil
|
272
|
-
@attributes = self.class._default_attributes.
|
312
|
+
def initialize(attributes = nil)
|
313
|
+
@attributes = self.class._default_attributes.deep_dup
|
314
|
+
self.class.define_attribute_methods
|
273
315
|
|
274
316
|
init_internals
|
275
317
|
initialize_internals_callback
|
276
318
|
|
277
|
-
|
278
|
-
# +options+ argument is only needed to make protected_attributes gem easier to hook.
|
279
|
-
# Remove it when we drop support to this gem.
|
280
|
-
init_attributes(attributes, options) if attributes
|
319
|
+
assign_attributes(attributes) if attributes
|
281
320
|
|
282
321
|
yield self if block_given?
|
283
322
|
_run_initialize_callbacks
|
284
323
|
end
|
285
324
|
|
286
|
-
# Initialize an empty model object from +coder+. +coder+
|
287
|
-
# the
|
288
|
-
#
|
325
|
+
# Initialize an empty model object from +coder+. +coder+ should be
|
326
|
+
# the result of previously encoding an Active Record model, using
|
327
|
+
# #encode_with.
|
289
328
|
#
|
290
329
|
# class Post < ActiveRecord::Base
|
291
330
|
# end
|
292
331
|
#
|
332
|
+
# old_post = Post.new(title: "hello world")
|
333
|
+
# coder = {}
|
334
|
+
# old_post.encode_with(coder)
|
335
|
+
#
|
293
336
|
# post = Post.allocate
|
294
|
-
# post.init_with(
|
337
|
+
# post.init_with(coder)
|
295
338
|
# post.title # => 'hello world'
|
296
339
|
def init_with(coder)
|
340
|
+
coder = LegacyYamlAdapter.convert(self.class, coder)
|
297
341
|
@attributes = coder['attributes']
|
298
342
|
|
299
343
|
init_internals
|
@@ -336,14 +380,11 @@ module ActiveRecord
|
|
336
380
|
|
337
381
|
##
|
338
382
|
def initialize_dup(other) # :nodoc:
|
339
|
-
@attributes = @attributes.
|
383
|
+
@attributes = @attributes.deep_dup
|
340
384
|
@attributes.reset(self.class.primary_key)
|
341
385
|
|
342
386
|
_run_initialize_callbacks
|
343
387
|
|
344
|
-
@aggregation_cache = {}
|
345
|
-
@association_cache = {}
|
346
|
-
|
347
388
|
@new_record = true
|
348
389
|
@destroyed = false
|
349
390
|
|
@@ -352,7 +393,7 @@ module ActiveRecord
|
|
352
393
|
|
353
394
|
# Populate +coder+ with attributes about this record that should be
|
354
395
|
# serialized. The structure of +coder+ defined in this method is
|
355
|
-
# guaranteed to match the structure of +coder+ passed to the
|
396
|
+
# guaranteed to match the structure of +coder+ passed to the #init_with
|
356
397
|
# method.
|
357
398
|
#
|
358
399
|
# Example:
|
@@ -367,6 +408,7 @@ module ActiveRecord
|
|
367
408
|
coder['raw_attributes'] = attributes_before_type_cast
|
368
409
|
coder['attributes'] = @attributes
|
369
410
|
coder['new_record'] = new_record?
|
411
|
+
coder['active_record_yaml_version'] = 1
|
370
412
|
end
|
371
413
|
|
372
414
|
# Returns true if +comparison_object+ is the same exact object, or +comparison_object+
|
@@ -449,9 +491,10 @@ module ActiveRecord
|
|
449
491
|
"#<#{self.class} #{inspection}>"
|
450
492
|
end
|
451
493
|
|
452
|
-
# Takes a PP and prettily prints this record to it, allowing you to get a nice result from
|
494
|
+
# Takes a PP and prettily prints this record to it, allowing you to get a nice result from <tt>pp record</tt>
|
453
495
|
# when pp is required.
|
454
496
|
def pretty_print(pp)
|
497
|
+
return super if custom_inspect_method_defined?
|
455
498
|
pp.object_address_group(self) do
|
456
499
|
if defined?(@attributes) && @attributes
|
457
500
|
column_names = self.class.column_names.select { |name| has_attribute?(name) || new_record? }
|
@@ -477,51 +520,8 @@ module ActiveRecord
|
|
477
520
|
Hash[methods.map! { |method| [method, public_send(method)] }].with_indifferent_access
|
478
521
|
end
|
479
522
|
|
480
|
-
def set_transaction_state(state) # :nodoc:
|
481
|
-
@transaction_state = state
|
482
|
-
end
|
483
|
-
|
484
|
-
def has_transactional_callbacks? # :nodoc:
|
485
|
-
!_rollback_callbacks.empty? || !_commit_callbacks.empty? || !_create_callbacks.empty?
|
486
|
-
end
|
487
|
-
|
488
523
|
private
|
489
524
|
|
490
|
-
# Updates the attributes on this particular ActiveRecord object so that
|
491
|
-
# if it is associated with a transaction, then the state of the AR object
|
492
|
-
# will be updated to reflect the current state of the transaction
|
493
|
-
#
|
494
|
-
# The @transaction_state variable stores the states of the associated
|
495
|
-
# transaction. This relies on the fact that a transaction can only be in
|
496
|
-
# one rollback or commit (otherwise a list of states would be required)
|
497
|
-
# Each AR object inside of a transaction carries that transaction's
|
498
|
-
# TransactionState.
|
499
|
-
#
|
500
|
-
# This method checks to see if the ActiveRecord object's state reflects
|
501
|
-
# the TransactionState, and rolls back or commits the ActiveRecord object
|
502
|
-
# as appropriate.
|
503
|
-
#
|
504
|
-
# Since ActiveRecord objects can be inside multiple transactions, this
|
505
|
-
# method recursively goes through the parent of the TransactionState and
|
506
|
-
# checks if the ActiveRecord object reflects the state of the object.
|
507
|
-
def sync_with_transaction_state
|
508
|
-
update_attributes_from_transaction_state(@transaction_state, 0)
|
509
|
-
end
|
510
|
-
|
511
|
-
def update_attributes_from_transaction_state(transaction_state, depth)
|
512
|
-
if transaction_state && transaction_state.finalized? && !has_transactional_callbacks?
|
513
|
-
unless @reflects_state[depth]
|
514
|
-
restore_transaction_record_state if transaction_state.rolledback?
|
515
|
-
clear_transaction_record_state
|
516
|
-
@reflects_state[depth] = true
|
517
|
-
end
|
518
|
-
|
519
|
-
if transaction_state.parent && !@reflects_state[depth+1]
|
520
|
-
update_attributes_from_transaction_state(transaction_state.parent, depth+1)
|
521
|
-
end
|
522
|
-
end
|
523
|
-
end
|
524
|
-
|
525
525
|
# Under Ruby 1.9, Array#flatten will call #to_ary (recursively) on each of the elements
|
526
526
|
# of the array, and then rescues from the possible NoMethodError. If those elements are
|
527
527
|
# ActiveRecord::Base's, then this triggers the various method_missing's that we have,
|
@@ -535,8 +535,6 @@ module ActiveRecord
|
|
535
535
|
end
|
536
536
|
|
537
537
|
def init_internals
|
538
|
-
@aggregation_cache = {}
|
539
|
-
@association_cache = {}
|
540
538
|
@readonly = false
|
541
539
|
@destroyed = false
|
542
540
|
@marked_for_destruction = false
|
@@ -545,22 +543,19 @@ module ActiveRecord
|
|
545
543
|
@txn = nil
|
546
544
|
@_start_transaction_state = {}
|
547
545
|
@transaction_state = nil
|
548
|
-
@reflects_state = [false]
|
549
546
|
end
|
550
547
|
|
551
548
|
def initialize_internals_callback
|
552
549
|
end
|
553
550
|
|
554
|
-
# This method is needed to make protected_attributes gem easier to hook.
|
555
|
-
# Remove it when we drop support to this gem.
|
556
|
-
def init_attributes(attributes, options)
|
557
|
-
assign_attributes(attributes)
|
558
|
-
end
|
559
|
-
|
560
551
|
def thaw
|
561
552
|
if frozen?
|
562
553
|
@attributes = @attributes.dup
|
563
554
|
end
|
564
555
|
end
|
556
|
+
|
557
|
+
def custom_inspect_method_defined?
|
558
|
+
self.class.instance_method(:inspect).owner != ActiveRecord::Base.instance_method(:inspect).owner
|
559
|
+
end
|
565
560
|
end
|
566
561
|
end
|
@@ -37,23 +37,22 @@ module ActiveRecord
|
|
37
37
|
reflection = child_class._reflections.values.find { |e| e.belongs_to? && e.foreign_key.to_s == foreign_key && e.options[:counter_cache].present? }
|
38
38
|
counter_name = reflection.counter_cache_column
|
39
39
|
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
connection.update stmt
|
40
|
+
unscoped.where(primary_key => object.id).update_all(
|
41
|
+
counter_name => object.send(counter_association).count(:all)
|
42
|
+
)
|
44
43
|
end
|
45
44
|
return true
|
46
45
|
end
|
47
46
|
|
48
47
|
# A generic "counter updater" implementation, intended primarily to be
|
49
|
-
# used by increment_counter and decrement_counter, but which may also
|
48
|
+
# used by #increment_counter and #decrement_counter, but which may also
|
50
49
|
# be useful on its own. It simply does a direct SQL update for the record
|
51
50
|
# with the given ID, altering the given hash of counters by the amount
|
52
51
|
# given by the corresponding value:
|
53
52
|
#
|
54
53
|
# ==== Parameters
|
55
54
|
#
|
56
|
-
# * +id+ - The id of the object you wish to update a counter on or an
|
55
|
+
# * +id+ - The id of the object you wish to update a counter on or an array of ids.
|
57
56
|
# * +counters+ - A Hash containing the names of the fields
|
58
57
|
# to update as keys and the amount to update the field by as values.
|
59
58
|
#
|
@@ -87,52 +86,42 @@ module ActiveRecord
|
|
87
86
|
# Increment a numeric field by one, via a direct SQL update.
|
88
87
|
#
|
89
88
|
# This method is used primarily for maintaining counter_cache columns that are
|
90
|
-
# used to store aggregate values. For example, a DiscussionBoard may cache
|
89
|
+
# used to store aggregate values. For example, a +DiscussionBoard+ may cache
|
91
90
|
# posts_count and comments_count to avoid running an SQL query to calculate the
|
92
91
|
# number of posts and comments there are, each time it is displayed.
|
93
92
|
#
|
94
93
|
# ==== Parameters
|
95
94
|
#
|
96
95
|
# * +counter_name+ - The name of the field that should be incremented.
|
97
|
-
# * +id+ - The id of the object that should be incremented or an
|
96
|
+
# * +id+ - The id of the object that should be incremented or an array of ids.
|
98
97
|
#
|
99
98
|
# ==== Examples
|
100
99
|
#
|
101
|
-
# # Increment the
|
102
|
-
# DiscussionBoard.increment_counter(:
|
100
|
+
# # Increment the posts_count column for the record with an id of 5
|
101
|
+
# DiscussionBoard.increment_counter(:posts_count, 5)
|
103
102
|
def increment_counter(counter_name, id)
|
104
103
|
update_counters(id, counter_name => 1)
|
105
104
|
end
|
106
105
|
|
107
106
|
# Decrement a numeric field by one, via a direct SQL update.
|
108
107
|
#
|
109
|
-
# This works the same as increment_counter but reduces the column value by
|
108
|
+
# This works the same as #increment_counter but reduces the column value by
|
110
109
|
# 1 instead of increasing it.
|
111
110
|
#
|
112
111
|
# ==== Parameters
|
113
112
|
#
|
114
113
|
# * +counter_name+ - The name of the field that should be decremented.
|
115
|
-
# * +id+ - The id of the object that should be decremented or an
|
114
|
+
# * +id+ - The id of the object that should be decremented or an array of ids.
|
116
115
|
#
|
117
116
|
# ==== Examples
|
118
117
|
#
|
119
|
-
# # Decrement the
|
120
|
-
# DiscussionBoard.decrement_counter(:
|
118
|
+
# # Decrement the posts_count column for the record with an id of 5
|
119
|
+
# DiscussionBoard.decrement_counter(:posts_count, 5)
|
121
120
|
def decrement_counter(counter_name, id)
|
122
121
|
update_counters(id, counter_name => -1)
|
123
122
|
end
|
124
123
|
end
|
125
124
|
|
126
|
-
protected
|
127
|
-
|
128
|
-
def actually_destroyed?
|
129
|
-
@_actually_destroyed
|
130
|
-
end
|
131
|
-
|
132
|
-
def clear_destroy_state
|
133
|
-
@_actually_destroyed = nil
|
134
|
-
end
|
135
|
-
|
136
125
|
private
|
137
126
|
|
138
127
|
def _create_record(*)
|
@@ -167,7 +156,7 @@ module ActiveRecord
|
|
167
156
|
|
168
157
|
def each_counter_cached_associations
|
169
158
|
_reflections.each do |name, reflection|
|
170
|
-
yield association(name) if reflection.belongs_to? && reflection.counter_cache_column
|
159
|
+
yield association(name.to_sym) if reflection.belongs_to? && reflection.counter_cache_column
|
171
160
|
end
|
172
161
|
end
|
173
162
|
|
@@ -1,10 +1,5 @@
|
|
1
1
|
module ActiveRecord
|
2
2
|
module DynamicMatchers #:nodoc:
|
3
|
-
# This code in this file seems to have a lot of indirection, but the indirection
|
4
|
-
# is there to provide extension points for the activerecord-deprecated_finders
|
5
|
-
# gem. When we stop supporting activerecord-deprecated_finders (from Rails 5),
|
6
|
-
# then we can remove the indirection.
|
7
|
-
|
8
3
|
def respond_to?(name, include_private = false)
|
9
4
|
if self == Base
|
10
5
|
super
|
@@ -72,26 +67,14 @@ module ActiveRecord
|
|
72
67
|
CODE
|
73
68
|
end
|
74
69
|
|
75
|
-
|
76
|
-
raise NotImplementedError
|
77
|
-
end
|
78
|
-
end
|
70
|
+
private
|
79
71
|
|
80
|
-
module Finder
|
81
|
-
# Extended in activerecord-deprecated_finders
|
82
72
|
def body
|
83
|
-
result
|
84
|
-
end
|
85
|
-
|
86
|
-
# Extended in activerecord-deprecated_finders
|
87
|
-
def result
|
88
73
|
"#{finder}(#{attributes_hash})"
|
89
74
|
end
|
90
75
|
|
91
76
|
# The parameters in the signature may have reserved Ruby words, in order
|
92
77
|
# to prevent errors, we start each param name with `_`.
|
93
|
-
#
|
94
|
-
# Extended in activerecord-deprecated_finders
|
95
78
|
def signature
|
96
79
|
attribute_names.map { |name| "_#{name}" }.join(', ')
|
97
80
|
end
|
@@ -109,7 +92,6 @@ module ActiveRecord
|
|
109
92
|
|
110
93
|
class FindBy < Method
|
111
94
|
Method.matchers << self
|
112
|
-
include Finder
|
113
95
|
|
114
96
|
def self.prefix
|
115
97
|
"find_by"
|
@@ -122,7 +104,6 @@ module ActiveRecord
|
|
122
104
|
|
123
105
|
class FindByBang < Method
|
124
106
|
Method.matchers << self
|
125
|
-
include Finder
|
126
107
|
|
127
108
|
def self.prefix
|
128
109
|
"find_by"
|