activerecord 3.2.22.5 → 4.0.0.beta1
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 +1024 -543
- data/MIT-LICENSE +1 -1
- data/README.rdoc +20 -29
- data/examples/performance.rb +1 -1
- data/lib/active_record.rb +55 -44
- data/lib/active_record/aggregations.rb +40 -34
- data/lib/active_record/associations.rb +204 -276
- data/lib/active_record/associations/alias_tracker.rb +1 -1
- data/lib/active_record/associations/association.rb +30 -35
- data/lib/active_record/associations/association_scope.rb +40 -40
- data/lib/active_record/associations/belongs_to_association.rb +15 -2
- data/lib/active_record/associations/builder/association.rb +81 -28
- data/lib/active_record/associations/builder/belongs_to.rb +35 -57
- data/lib/active_record/associations/builder/collection_association.rb +54 -40
- data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +23 -41
- data/lib/active_record/associations/builder/has_many.rb +8 -64
- data/lib/active_record/associations/builder/has_one.rb +13 -50
- data/lib/active_record/associations/builder/singular_association.rb +13 -13
- data/lib/active_record/associations/collection_association.rb +92 -88
- data/lib/active_record/associations/collection_proxy.rb +913 -63
- data/lib/active_record/associations/has_and_belongs_to_many_association.rb +12 -10
- data/lib/active_record/associations/has_many_association.rb +35 -9
- data/lib/active_record/associations/has_many_through_association.rb +24 -14
- data/lib/active_record/associations/has_one_association.rb +33 -13
- data/lib/active_record/associations/has_one_through_association.rb +1 -1
- data/lib/active_record/associations/join_dependency.rb +2 -2
- data/lib/active_record/associations/join_dependency/join_association.rb +17 -22
- data/lib/active_record/associations/join_dependency/join_part.rb +1 -1
- data/lib/active_record/associations/join_helper.rb +1 -11
- data/lib/active_record/associations/preloader.rb +14 -17
- data/lib/active_record/associations/preloader/association.rb +29 -33
- data/lib/active_record/associations/preloader/collection_association.rb +1 -1
- data/lib/active_record/associations/preloader/has_and_belongs_to_many.rb +1 -1
- data/lib/active_record/associations/preloader/has_many_through.rb +1 -1
- data/lib/active_record/associations/preloader/has_one.rb +1 -1
- data/lib/active_record/associations/preloader/through_association.rb +13 -17
- data/lib/active_record/associations/singular_association.rb +11 -11
- data/lib/active_record/associations/through_association.rb +2 -2
- data/lib/active_record/attribute_assignment.rb +133 -153
- data/lib/active_record/attribute_methods.rb +196 -93
- data/lib/active_record/attribute_methods/before_type_cast.rb +44 -5
- data/lib/active_record/attribute_methods/dirty.rb +31 -28
- data/lib/active_record/attribute_methods/primary_key.rb +38 -30
- data/lib/active_record/attribute_methods/query.rb +5 -4
- data/lib/active_record/attribute_methods/read.rb +62 -91
- data/lib/active_record/attribute_methods/serialization.rb +97 -66
- data/lib/active_record/attribute_methods/time_zone_conversion.rb +39 -45
- data/lib/active_record/attribute_methods/write.rb +32 -39
- data/lib/active_record/autosave_association.rb +56 -70
- data/lib/active_record/base.rb +53 -450
- data/lib/active_record/callbacks.rb +53 -18
- data/lib/active_record/coders/yaml_column.rb +11 -9
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +353 -197
- data/lib/active_record/connection_adapters/abstract/database_limits.rb +9 -0
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +130 -131
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +24 -19
- data/lib/active_record/connection_adapters/abstract/quoting.rb +23 -3
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +101 -91
- data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +59 -0
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +225 -96
- data/lib/active_record/connection_adapters/abstract/transaction.rb +203 -0
- data/lib/active_record/connection_adapters/abstract_adapter.rb +99 -46
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +114 -36
- data/lib/active_record/connection_adapters/column.rb +46 -24
- data/lib/active_record/connection_adapters/connection_specification.rb +96 -0
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +16 -32
- data/lib/active_record/connection_adapters/mysql_adapter.rb +181 -64
- data/lib/active_record/connection_adapters/postgresql/array_parser.rb +97 -0
- data/lib/active_record/connection_adapters/postgresql/cast.rb +132 -0
- data/lib/active_record/connection_adapters/postgresql/database_statements.rb +242 -0
- data/lib/active_record/connection_adapters/postgresql/oid.rb +347 -0
- data/lib/active_record/connection_adapters/postgresql/quoting.rb +158 -0
- data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +30 -0
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +448 -0
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +454 -885
- data/lib/active_record/connection_adapters/schema_cache.rb +48 -16
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +574 -13
- data/lib/active_record/connection_handling.rb +98 -0
- data/lib/active_record/core.rb +428 -0
- data/lib/active_record/counter_cache.rb +106 -108
- data/lib/active_record/dynamic_matchers.rb +110 -63
- data/lib/active_record/errors.rb +25 -8
- data/lib/active_record/explain.rb +8 -58
- data/lib/active_record/explain_subscriber.rb +6 -3
- data/lib/active_record/fixture_set/file.rb +56 -0
- data/lib/active_record/fixtures.rb +146 -148
- data/lib/active_record/inheritance.rb +77 -59
- data/lib/active_record/integration.rb +5 -5
- data/lib/active_record/locale/en.yml +8 -1
- data/lib/active_record/locking/optimistic.rb +38 -42
- data/lib/active_record/locking/pessimistic.rb +4 -4
- data/lib/active_record/log_subscriber.rb +19 -9
- data/lib/active_record/migration.rb +318 -153
- data/lib/active_record/migration/command_recorder.rb +90 -31
- data/lib/active_record/migration/join_table.rb +15 -0
- data/lib/active_record/model_schema.rb +69 -92
- data/lib/active_record/nested_attributes.rb +113 -148
- data/lib/active_record/null_relation.rb +65 -0
- data/lib/active_record/persistence.rb +188 -97
- data/lib/active_record/query_cache.rb +18 -36
- data/lib/active_record/querying.rb +19 -15
- data/lib/active_record/railtie.rb +91 -36
- data/lib/active_record/railties/console_sandbox.rb +0 -2
- data/lib/active_record/railties/controller_runtime.rb +2 -2
- data/lib/active_record/railties/databases.rake +90 -309
- data/lib/active_record/railties/jdbcmysql_error.rb +1 -1
- data/lib/active_record/readonly_attributes.rb +7 -3
- data/lib/active_record/reflection.rb +72 -56
- data/lib/active_record/relation.rb +241 -157
- data/lib/active_record/relation/batches.rb +25 -22
- data/lib/active_record/relation/calculations.rb +143 -121
- data/lib/active_record/relation/delegation.rb +96 -18
- data/lib/active_record/relation/finder_methods.rb +117 -183
- data/lib/active_record/relation/merger.rb +133 -0
- data/lib/active_record/relation/predicate_builder.rb +90 -42
- data/lib/active_record/relation/query_methods.rb +666 -136
- data/lib/active_record/relation/spawn_methods.rb +43 -150
- data/lib/active_record/result.rb +33 -6
- data/lib/active_record/sanitization.rb +24 -50
- data/lib/active_record/schema.rb +19 -12
- data/lib/active_record/schema_dumper.rb +31 -39
- data/lib/active_record/schema_migration.rb +36 -0
- data/lib/active_record/scoping.rb +0 -124
- data/lib/active_record/scoping/default.rb +48 -45
- data/lib/active_record/scoping/named.rb +74 -103
- data/lib/active_record/serialization.rb +6 -2
- data/lib/active_record/serializers/xml_serializer.rb +9 -15
- data/lib/active_record/store.rb +119 -15
- data/lib/active_record/tasks/database_tasks.rb +158 -0
- data/lib/active_record/tasks/mysql_database_tasks.rb +138 -0
- data/lib/active_record/tasks/postgresql_database_tasks.rb +90 -0
- data/lib/active_record/tasks/sqlite_database_tasks.rb +51 -0
- data/lib/active_record/test_case.rb +61 -38
- data/lib/active_record/timestamp.rb +8 -9
- data/lib/active_record/transactions.rb +65 -51
- data/lib/active_record/validations.rb +17 -15
- data/lib/active_record/validations/associated.rb +20 -14
- data/lib/active_record/validations/presence.rb +65 -0
- data/lib/active_record/validations/uniqueness.rb +93 -52
- data/lib/active_record/version.rb +4 -4
- data/lib/rails/generators/active_record.rb +3 -5
- data/lib/rails/generators/active_record/migration/migration_generator.rb +37 -7
- data/lib/rails/generators/active_record/migration/templates/migration.rb +20 -15
- data/lib/rails/generators/active_record/model/model_generator.rb +4 -3
- data/lib/rails/generators/active_record/model/templates/model.rb +1 -6
- data/lib/rails/generators/active_record/model/templates/module.rb +1 -1
- metadata +53 -46
- data/lib/active_record/attribute_methods/deprecated_underscore_read.rb +0 -32
- data/lib/active_record/connection_adapters/abstract/connection_specification.rb +0 -191
- data/lib/active_record/connection_adapters/sqlite_adapter.rb +0 -583
- data/lib/active_record/dynamic_finder_match.rb +0 -68
- data/lib/active_record/dynamic_scope_match.rb +0 -23
- data/lib/active_record/fixtures/file.rb +0 -65
- data/lib/active_record/identity_map.rb +0 -162
- data/lib/active_record/observer.rb +0 -121
- data/lib/active_record/session_store.rb +0 -360
- data/lib/rails/generators/active_record/migration.rb +0 -15
- 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 -12
@@ -1,123 +1,121 @@
|
|
1
1
|
module ActiveRecord
|
2
2
|
# = Active Record Counter Cache
|
3
3
|
module CounterCache
|
4
|
-
|
5
|
-
# count query. This is useful when adding new counter caches, or if the
|
6
|
-
# counter has been corrupted or modified directly by SQL.
|
7
|
-
#
|
8
|
-
# ==== Parameters
|
9
|
-
#
|
10
|
-
# * +id+ - The id of the object you wish to reset a counter on.
|
11
|
-
# * +counters+ - One or more counter names to reset
|
12
|
-
#
|
13
|
-
# ==== Examples
|
14
|
-
#
|
15
|
-
# # For Post with id #1 records reset the comments_count
|
16
|
-
# Post.reset_counters(1, :comments)
|
17
|
-
def reset_counters(id, *counters)
|
18
|
-
object = find(id)
|
19
|
-
counters.each do |association|
|
20
|
-
has_many_association = reflect_on_association(association.to_sym)
|
4
|
+
extend ActiveSupport::Concern
|
21
5
|
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
6
|
+
module ClassMethods
|
7
|
+
# Resets one or more counter caches to their correct value using an SQL
|
8
|
+
# count query. This is useful when adding new counter caches, or if the
|
9
|
+
# counter has been corrupted or modified directly by SQL.
|
10
|
+
#
|
11
|
+
# ==== Parameters
|
12
|
+
#
|
13
|
+
# * +id+ - The id of the object you wish to reset a counter on.
|
14
|
+
# * +counters+ - One or more counter names to reset
|
15
|
+
#
|
16
|
+
# ==== Examples
|
17
|
+
#
|
18
|
+
# # For Post with id #1 records reset the comments_count
|
19
|
+
# Post.reset_counters(1, :comments)
|
20
|
+
def reset_counters(id, *counters)
|
21
|
+
object = find(id)
|
22
|
+
counters.each do |association|
|
23
|
+
has_many_association = reflect_on_association(association.to_sym)
|
31
24
|
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
reflection = belongs_to.find { |e| e.foreign_key.to_s == foreign_key && e.options[:counter_cache].present? }
|
36
|
-
counter_name = reflection.counter_cache_column
|
25
|
+
if has_many_association.is_a? ActiveRecord::Reflection::ThroughReflection
|
26
|
+
has_many_association = has_many_association.through_reflection
|
27
|
+
end
|
37
28
|
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
return true
|
44
|
-
end
|
29
|
+
foreign_key = has_many_association.foreign_key.to_s
|
30
|
+
child_class = has_many_association.klass
|
31
|
+
belongs_to = child_class.reflect_on_all_associations(:belongs_to)
|
32
|
+
reflection = belongs_to.find { |e| e.foreign_key.to_s == foreign_key && e.options[:counter_cache].present? }
|
33
|
+
counter_name = reflection.counter_cache_column
|
45
34
|
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
# ==== Parameters
|
53
|
-
#
|
54
|
-
# * +id+ - The id of the object you wish to update a counter on or an Array of ids.
|
55
|
-
# * +counters+ - An Array of Hashes containing the names of the fields
|
56
|
-
# to update as keys and the amount to update the field by as values.
|
57
|
-
#
|
58
|
-
# ==== Examples
|
59
|
-
#
|
60
|
-
# # For the Post with id of 5, decrement the comment_count by 1, and
|
61
|
-
# # increment the action_count by 1
|
62
|
-
# Post.update_counters 5, :comment_count => -1, :action_count => 1
|
63
|
-
# # Executes the following SQL:
|
64
|
-
# # UPDATE posts
|
65
|
-
# # SET comment_count = COALESCE(comment_count, 0) - 1,
|
66
|
-
# # action_count = COALESCE(action_count, 0) + 1
|
67
|
-
# # WHERE id = 5
|
68
|
-
#
|
69
|
-
# # For the Posts with id of 10 and 15, increment the comment_count by 1
|
70
|
-
# Post.update_counters [10, 15], :comment_count => 1
|
71
|
-
# # Executes the following SQL:
|
72
|
-
# # UPDATE posts
|
73
|
-
# # SET comment_count = COALESCE(comment_count, 0) + 1
|
74
|
-
# # WHERE id IN (10, 15)
|
75
|
-
def update_counters(id, counters)
|
76
|
-
updates = counters.map do |counter_name, value|
|
77
|
-
operator = value < 0 ? '-' : '+'
|
78
|
-
quoted_column = connection.quote_column_name(counter_name)
|
79
|
-
"#{quoted_column} = COALESCE(#{quoted_column}, 0) #{operator} #{value.abs}"
|
35
|
+
stmt = unscoped.where(arel_table[primary_key].eq(object.id)).arel.compile_update({
|
36
|
+
arel_table[counter_name] => object.send(association).count
|
37
|
+
})
|
38
|
+
connection.update stmt
|
39
|
+
end
|
40
|
+
return true
|
80
41
|
end
|
81
42
|
|
82
|
-
|
43
|
+
# A generic "counter updater" implementation, intended primarily to be
|
44
|
+
# used by increment_counter and decrement_counter, but which may also
|
45
|
+
# be useful on its own. It simply does a direct SQL update for the record
|
46
|
+
# with the given ID, altering the given hash of counters by the amount
|
47
|
+
# given by the corresponding value:
|
48
|
+
#
|
49
|
+
# ==== Parameters
|
50
|
+
#
|
51
|
+
# * +id+ - The id of the object you wish to update a counter on or an Array of ids.
|
52
|
+
# * +counters+ - An Array of Hashes containing the names of the fields
|
53
|
+
# to update as keys and the amount to update the field by as values.
|
54
|
+
#
|
55
|
+
# ==== Examples
|
56
|
+
#
|
57
|
+
# # For the Post with id of 5, decrement the comment_count by 1, and
|
58
|
+
# # increment the action_count by 1
|
59
|
+
# Post.update_counters 5, comment_count: -1, action_count: 1
|
60
|
+
# # Executes the following SQL:
|
61
|
+
# # UPDATE posts
|
62
|
+
# # SET comment_count = COALESCE(comment_count, 0) - 1,
|
63
|
+
# # action_count = COALESCE(action_count, 0) + 1
|
64
|
+
# # WHERE id = 5
|
65
|
+
#
|
66
|
+
# # For the Posts with id of 10 and 15, increment the comment_count by 1
|
67
|
+
# Post.update_counters [10, 15], comment_count: 1
|
68
|
+
# # Executes the following SQL:
|
69
|
+
# # UPDATE posts
|
70
|
+
# # SET comment_count = COALESCE(comment_count, 0) + 1
|
71
|
+
# # WHERE id IN (10, 15)
|
72
|
+
def update_counters(id, counters)
|
73
|
+
updates = counters.map do |counter_name, value|
|
74
|
+
operator = value < 0 ? '-' : '+'
|
75
|
+
quoted_column = connection.quote_column_name(counter_name)
|
76
|
+
"#{quoted_column} = COALESCE(#{quoted_column}, 0) #{operator} #{value.abs}"
|
77
|
+
end
|
83
78
|
|
84
|
-
|
85
|
-
|
79
|
+
where(primary_key => id).update_all updates.join(', ')
|
80
|
+
end
|
86
81
|
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
82
|
+
# Increment a numeric field by one, via a direct SQL update.
|
83
|
+
#
|
84
|
+
# This method is used primarily for maintaining counter_cache columns used to
|
85
|
+
# store aggregate values. For example, a DiscussionBoard may cache posts_count
|
86
|
+
# and comments_count to avoid running an SQL query to calculate the number of
|
87
|
+
# posts and comments there are each time it is displayed.
|
88
|
+
#
|
89
|
+
# ==== Parameters
|
90
|
+
#
|
91
|
+
# * +counter_name+ - The name of the field that should be incremented.
|
92
|
+
# * +id+ - The id of the object that should be incremented or an Array of ids.
|
93
|
+
#
|
94
|
+
# ==== Examples
|
95
|
+
#
|
96
|
+
# # Increment the post_count column for the record with an id of 5
|
97
|
+
# DiscussionBoard.increment_counter(:post_count, 5)
|
98
|
+
def increment_counter(counter_name, id)
|
99
|
+
update_counters(id, counter_name => 1)
|
100
|
+
end
|
105
101
|
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
102
|
+
# Decrement a numeric field by one, via a direct SQL update.
|
103
|
+
#
|
104
|
+
# This works the same as increment_counter but reduces the column value by
|
105
|
+
# 1 instead of increasing it.
|
106
|
+
#
|
107
|
+
# ==== Parameters
|
108
|
+
#
|
109
|
+
# * +counter_name+ - The name of the field that should be decremented.
|
110
|
+
# * +id+ - The id of the object that should be decremented or an Array of ids.
|
111
|
+
#
|
112
|
+
# ==== Examples
|
113
|
+
#
|
114
|
+
# # Decrement the post_count column for the record with an id of 5
|
115
|
+
# DiscussionBoard.decrement_counter(:post_count, 5)
|
116
|
+
def decrement_counter(counter_name, id)
|
117
|
+
update_counters(id, counter_name => -1)
|
118
|
+
end
|
121
119
|
end
|
122
120
|
end
|
123
121
|
end
|
@@ -1,84 +1,131 @@
|
|
1
1
|
module ActiveRecord
|
2
|
-
module DynamicMatchers
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
return true if all_attributes_exists?(match.attribute_names)
|
8
|
-
end
|
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.
|
9
7
|
|
10
|
-
|
8
|
+
def respond_to?(name, include_private = false)
|
9
|
+
match = Method.match(self, name)
|
10
|
+
match && match.valid? || super
|
11
11
|
end
|
12
12
|
|
13
13
|
private
|
14
14
|
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
#
|
22
|
-
# Each dynamic finder using <tt>scoped_by_*</tt> is also defined in the class after it
|
23
|
-
# is first invoked, so that future attempts to use it do not run through method_missing.
|
24
|
-
def method_missing(method_id, *arguments, &block)
|
25
|
-
if match = (DynamicFinderMatch.match(method_id) || DynamicScopeMatch.match(method_id))
|
26
|
-
attribute_names = match.attribute_names
|
27
|
-
super unless all_attributes_exists?(attribute_names)
|
28
|
-
if !(match.is_a?(DynamicFinderMatch) && match.instantiator? && arguments.first.is_a?(Hash)) && arguments.size < attribute_names.size
|
29
|
-
method_trace = "#{__FILE__}:#{__LINE__}:in `#{method_id}'"
|
30
|
-
backtrace = [method_trace] + caller
|
31
|
-
raise ArgumentError, "wrong number of arguments (#{arguments.size} for #{attribute_names.size})", backtrace
|
32
|
-
end
|
33
|
-
if match.respond_to?(:scope?) && match.scope?
|
34
|
-
self.class_eval <<-METHOD, __FILE__, __LINE__ + 1
|
35
|
-
def self.#{method_id}(*args) # def self.scoped_by_user_name_and_password(*args)
|
36
|
-
attributes = Hash[[:#{attribute_names.join(',:')}].zip(args)] # attributes = Hash[[:user_name, :password].zip(args)]
|
37
|
-
#
|
38
|
-
scoped(:conditions => attributes) # scoped(:conditions => attributes)
|
39
|
-
end # end
|
40
|
-
METHOD
|
41
|
-
send(method_id, *arguments)
|
42
|
-
elsif match.finder?
|
43
|
-
options = if arguments.length > attribute_names.size
|
44
|
-
arguments.extract_options!
|
45
|
-
else
|
46
|
-
{}
|
47
|
-
end
|
48
|
-
|
49
|
-
relation = options.any? ? scoped(options) : scoped
|
50
|
-
relation.send :find_by_attributes, match, attribute_names, *arguments, &block
|
51
|
-
elsif match.instantiator?
|
52
|
-
scoped.send :find_or_instantiator_by_attributes, match, attribute_names, *arguments, &block
|
53
|
-
end
|
15
|
+
def method_missing(name, *arguments, &block)
|
16
|
+
match = Method.match(self, name)
|
17
|
+
|
18
|
+
if match && match.valid?
|
19
|
+
match.define
|
20
|
+
send(name, *arguments, &block)
|
54
21
|
else
|
55
22
|
super
|
56
23
|
end
|
57
24
|
end
|
58
25
|
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
26
|
+
class Method
|
27
|
+
@matchers = []
|
28
|
+
|
29
|
+
class << self
|
30
|
+
attr_reader :matchers
|
31
|
+
|
32
|
+
def match(model, name)
|
33
|
+
klass = matchers.find { |k| name =~ k.pattern }
|
34
|
+
klass.new(model, name) if klass
|
35
|
+
end
|
36
|
+
|
37
|
+
def pattern
|
38
|
+
/^#{prefix}_([_a-zA-Z]\w*)#{suffix}$/
|
39
|
+
end
|
40
|
+
|
41
|
+
def prefix
|
42
|
+
raise NotImplementedError
|
68
43
|
end
|
69
|
-
|
44
|
+
|
45
|
+
def suffix
|
46
|
+
''
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
attr_reader :model, :name, :attribute_names
|
51
|
+
|
52
|
+
def initialize(model, name)
|
53
|
+
@model = model
|
54
|
+
@name = name.to_s
|
55
|
+
@attribute_names = @name.match(self.class.pattern)[1].split('_and_')
|
56
|
+
@attribute_names.map! { |n| @model.attribute_aliases[n] || n }
|
57
|
+
end
|
58
|
+
|
59
|
+
def valid?
|
60
|
+
attribute_names.all? { |name| model.columns_hash[name] || model.reflect_on_aggregation(name.to_sym) }
|
61
|
+
end
|
62
|
+
|
63
|
+
def define
|
64
|
+
model.class_eval <<-CODE, __FILE__, __LINE__ + 1
|
65
|
+
def self.#{name}(#{signature})
|
66
|
+
#{body}
|
67
|
+
end
|
68
|
+
CODE
|
69
|
+
end
|
70
|
+
|
71
|
+
def body
|
72
|
+
raise NotImplementedError
|
73
|
+
end
|
70
74
|
end
|
71
75
|
|
72
|
-
|
73
|
-
|
74
|
-
|
76
|
+
module Finder
|
77
|
+
# Extended in activerecord-deprecated_finders
|
78
|
+
def body
|
79
|
+
result
|
80
|
+
end
|
81
|
+
|
82
|
+
# Extended in activerecord-deprecated_finders
|
83
|
+
def result
|
84
|
+
"#{finder}(#{attributes_hash})"
|
85
|
+
end
|
86
|
+
|
87
|
+
# Extended in activerecord-deprecated_finders
|
88
|
+
def signature
|
89
|
+
attribute_names.join(', ')
|
90
|
+
end
|
91
|
+
|
92
|
+
def attributes_hash
|
93
|
+
"{" + attribute_names.map { |name| ":#{name} => #{name}" }.join(',') + "}"
|
94
|
+
end
|
95
|
+
|
96
|
+
def finder
|
97
|
+
raise NotImplementedError
|
98
|
+
end
|
75
99
|
end
|
76
100
|
|
77
|
-
|
78
|
-
|
79
|
-
|
101
|
+
class FindBy < Method
|
102
|
+
Method.matchers << self
|
103
|
+
include Finder
|
104
|
+
|
105
|
+
def self.prefix
|
106
|
+
"find_by"
|
107
|
+
end
|
108
|
+
|
109
|
+
def finder
|
110
|
+
"find_by"
|
111
|
+
end
|
80
112
|
end
|
81
113
|
|
114
|
+
class FindByBang < Method
|
115
|
+
Method.matchers << self
|
116
|
+
include Finder
|
117
|
+
|
118
|
+
def self.prefix
|
119
|
+
"find_by"
|
120
|
+
end
|
121
|
+
|
122
|
+
def self.suffix
|
123
|
+
"!"
|
124
|
+
end
|
82
125
|
|
126
|
+
def finder
|
127
|
+
"find_by!"
|
128
|
+
end
|
129
|
+
end
|
83
130
|
end
|
84
131
|
end
|
data/lib/active_record/errors.rb
CHANGED
@@ -22,7 +22,7 @@ module ActiveRecord
|
|
22
22
|
# end
|
23
23
|
#
|
24
24
|
# # Comments are not patches, this assignment raises AssociationTypeMismatch.
|
25
|
-
# @ticket.patches << Comment.new(:
|
25
|
+
# @ticket.patches << Comment.new(content: "Please attach tests to your patch.")
|
26
26
|
class AssociationTypeMismatch < ActiveRecordError
|
27
27
|
end
|
28
28
|
|
@@ -53,6 +53,10 @@ module ActiveRecord
|
|
53
53
|
class RecordNotSaved < ActiveRecordError
|
54
54
|
end
|
55
55
|
|
56
|
+
# Raised by ActiveRecord::Base.destroy! when a call to destroy would return false.
|
57
|
+
class RecordNotDestroyed < ActiveRecordError
|
58
|
+
end
|
59
|
+
|
56
60
|
# Raised when SQL statement cannot be executed by the database (for example, it's often the case for
|
57
61
|
# MySQL when Ruby driver used is too old).
|
58
62
|
class StatementInvalid < ActiveRecordError
|
@@ -102,13 +106,11 @@ module ActiveRecord
|
|
102
106
|
attr_reader :record, :attempted_action
|
103
107
|
|
104
108
|
def initialize(record, attempted_action)
|
109
|
+
super("Attempted to #{attempted_action} a stale object: #{record.class.name}")
|
105
110
|
@record = record
|
106
111
|
@attempted_action = attempted_action
|
107
112
|
end
|
108
113
|
|
109
|
-
def message
|
110
|
-
"Attempted to #{attempted_action} a stale object: #{record.class.name}"
|
111
|
-
end
|
112
114
|
end
|
113
115
|
|
114
116
|
# Raised when association is being configured improperly or
|
@@ -164,9 +166,9 @@ module ActiveRecord
|
|
164
166
|
class AttributeAssignmentError < ActiveRecordError
|
165
167
|
attr_reader :exception, :attribute
|
166
168
|
def initialize(message, exception, attribute)
|
169
|
+
super(message)
|
167
170
|
@exception = exception
|
168
171
|
@attribute = attribute
|
169
|
-
@message = message
|
170
172
|
end
|
171
173
|
end
|
172
174
|
|
@@ -185,11 +187,26 @@ module ActiveRecord
|
|
185
187
|
attr_reader :model
|
186
188
|
|
187
189
|
def initialize(model)
|
190
|
+
super("Unknown primary key for table #{model.table_name} in model #{model}.")
|
188
191
|
@model = model
|
189
192
|
end
|
190
193
|
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
+
end
|
195
|
+
|
196
|
+
# Raised when a relation cannot be mutated because it's already loaded.
|
197
|
+
#
|
198
|
+
# class Task < ActiveRecord::Base
|
199
|
+
# end
|
200
|
+
#
|
201
|
+
# relation = Task.all
|
202
|
+
# relation.loaded? # => true
|
203
|
+
#
|
204
|
+
# # Methods which try to mutate a loaded relation fail.
|
205
|
+
# relation.where!(title: 'TODO') # => ActiveRecord::ImmutableRelation
|
206
|
+
# relation.limit!(5) # => ActiveRecord::ImmutableRelation
|
207
|
+
class ImmutableRelation < ActiveRecordError
|
208
|
+
end
|
209
|
+
|
210
|
+
class TransactionIsolationError < ActiveRecordError
|
194
211
|
end
|
195
212
|
end
|