activerecord 4.1.16 → 4.2.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.

Files changed (167) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +634 -2185
  3. data/README.rdoc +15 -10
  4. data/lib/active_record.rb +2 -1
  5. data/lib/active_record/aggregations.rb +12 -8
  6. data/lib/active_record/associations.rb +58 -33
  7. data/lib/active_record/associations/association.rb +1 -1
  8. data/lib/active_record/associations/association_scope.rb +53 -21
  9. data/lib/active_record/associations/belongs_to_association.rb +15 -5
  10. data/lib/active_record/associations/builder/association.rb +16 -5
  11. data/lib/active_record/associations/builder/belongs_to.rb +7 -29
  12. data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +2 -11
  13. data/lib/active_record/associations/builder/has_one.rb +2 -2
  14. data/lib/active_record/associations/builder/singular_association.rb +8 -1
  15. data/lib/active_record/associations/collection_association.rb +32 -44
  16. data/lib/active_record/associations/collection_proxy.rb +1 -10
  17. data/lib/active_record/associations/has_many_association.rb +60 -14
  18. data/lib/active_record/associations/has_many_through_association.rb +34 -23
  19. data/lib/active_record/associations/has_one_association.rb +0 -1
  20. data/lib/active_record/associations/join_dependency.rb +7 -9
  21. data/lib/active_record/associations/join_dependency/join_association.rb +18 -14
  22. data/lib/active_record/associations/preloader.rb +2 -2
  23. data/lib/active_record/associations/preloader/association.rb +9 -5
  24. data/lib/active_record/associations/preloader/through_association.rb +3 -3
  25. data/lib/active_record/associations/singular_association.rb +16 -1
  26. data/lib/active_record/associations/through_association.rb +6 -22
  27. data/lib/active_record/attribute.rb +131 -0
  28. data/lib/active_record/attribute_assignment.rb +19 -11
  29. data/lib/active_record/attribute_decorators.rb +66 -0
  30. data/lib/active_record/attribute_methods.rb +53 -90
  31. data/lib/active_record/attribute_methods/before_type_cast.rb +2 -2
  32. data/lib/active_record/attribute_methods/dirty.rb +85 -42
  33. data/lib/active_record/attribute_methods/primary_key.rb +6 -8
  34. data/lib/active_record/attribute_methods/read.rb +14 -57
  35. data/lib/active_record/attribute_methods/serialization.rb +12 -146
  36. data/lib/active_record/attribute_methods/time_zone_conversion.rb +32 -40
  37. data/lib/active_record/attribute_methods/write.rb +8 -23
  38. data/lib/active_record/attribute_set.rb +77 -0
  39. data/lib/active_record/attribute_set/builder.rb +32 -0
  40. data/lib/active_record/attributes.rb +122 -0
  41. data/lib/active_record/autosave_association.rb +11 -21
  42. data/lib/active_record/base.rb +9 -19
  43. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +69 -45
  44. data/lib/active_record/connection_adapters/abstract/database_statements.rb +22 -42
  45. data/lib/active_record/connection_adapters/abstract/quoting.rb +59 -60
  46. data/lib/active_record/connection_adapters/abstract/schema_creation.rb +37 -2
  47. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +102 -21
  48. data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +9 -33
  49. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +178 -55
  50. data/lib/active_record/connection_adapters/abstract/transaction.rb +120 -115
  51. data/lib/active_record/connection_adapters/abstract_adapter.rb +143 -57
  52. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +156 -107
  53. data/lib/active_record/connection_adapters/column.rb +13 -244
  54. data/lib/active_record/connection_adapters/connection_specification.rb +6 -20
  55. data/lib/active_record/connection_adapters/mysql2_adapter.rb +12 -15
  56. data/lib/active_record/connection_adapters/mysql_adapter.rb +55 -143
  57. data/lib/active_record/connection_adapters/postgresql/array_parser.rb +15 -27
  58. data/lib/active_record/connection_adapters/postgresql/column.rb +20 -0
  59. data/lib/active_record/connection_adapters/postgresql/database_statements.rb +39 -20
  60. data/lib/active_record/connection_adapters/postgresql/oid.rb +29 -388
  61. data/lib/active_record/connection_adapters/postgresql/oid/array.rb +96 -0
  62. data/lib/active_record/connection_adapters/postgresql/oid/bit.rb +52 -0
  63. data/lib/active_record/connection_adapters/postgresql/oid/bit_varying.rb +13 -0
  64. data/lib/active_record/connection_adapters/postgresql/oid/bytea.rb +14 -0
  65. data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +46 -0
  66. data/lib/active_record/connection_adapters/postgresql/oid/date.rb +11 -0
  67. data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +27 -0
  68. data/lib/active_record/connection_adapters/postgresql/oid/decimal.rb +13 -0
  69. data/lib/active_record/connection_adapters/postgresql/oid/enum.rb +17 -0
  70. data/lib/active_record/connection_adapters/postgresql/oid/float.rb +21 -0
  71. data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +59 -0
  72. data/lib/active_record/connection_adapters/postgresql/oid/inet.rb +13 -0
  73. data/lib/active_record/connection_adapters/postgresql/oid/infinity.rb +13 -0
  74. data/lib/active_record/connection_adapters/postgresql/oid/integer.rb +11 -0
  75. data/lib/active_record/connection_adapters/postgresql/oid/json.rb +35 -0
  76. data/lib/active_record/connection_adapters/postgresql/oid/jsonb.rb +23 -0
  77. data/lib/active_record/connection_adapters/postgresql/oid/money.rb +43 -0
  78. data/lib/active_record/connection_adapters/postgresql/oid/point.rb +43 -0
  79. data/lib/active_record/connection_adapters/postgresql/oid/range.rb +76 -0
  80. data/lib/active_record/connection_adapters/postgresql/oid/specialized_string.rb +15 -0
  81. data/lib/active_record/connection_adapters/postgresql/oid/time.rb +11 -0
  82. data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +85 -0
  83. data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +26 -0
  84. data/lib/active_record/connection_adapters/postgresql/oid/vector.rb +26 -0
  85. data/lib/active_record/connection_adapters/postgresql/oid/xml.rb +28 -0
  86. data/lib/active_record/connection_adapters/postgresql/quoting.rb +42 -122
  87. data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +4 -4
  88. data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +154 -0
  89. data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +86 -34
  90. data/lib/active_record/connection_adapters/postgresql/utils.rb +66 -0
  91. data/lib/active_record/connection_adapters/postgresql_adapter.rb +188 -452
  92. data/lib/active_record/connection_adapters/schema_cache.rb +14 -28
  93. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +54 -47
  94. data/lib/active_record/connection_handling.rb +1 -1
  95. data/lib/active_record/core.rb +119 -22
  96. data/lib/active_record/counter_cache.rb +60 -6
  97. data/lib/active_record/enum.rb +9 -10
  98. data/lib/active_record/errors.rb +27 -26
  99. data/lib/active_record/explain.rb +1 -1
  100. data/lib/active_record/fixtures.rb +52 -45
  101. data/lib/active_record/gem_version.rb +3 -3
  102. data/lib/active_record/inheritance.rb +33 -8
  103. data/lib/active_record/integration.rb +4 -4
  104. data/lib/active_record/locking/optimistic.rb +34 -16
  105. data/lib/active_record/migration.rb +22 -32
  106. data/lib/active_record/migration/command_recorder.rb +19 -2
  107. data/lib/active_record/migration/join_table.rb +1 -1
  108. data/lib/active_record/model_schema.rb +39 -48
  109. data/lib/active_record/nested_attributes.rb +8 -18
  110. data/lib/active_record/persistence.rb +39 -22
  111. data/lib/active_record/query_cache.rb +3 -3
  112. data/lib/active_record/querying.rb +1 -8
  113. data/lib/active_record/railtie.rb +17 -10
  114. data/lib/active_record/railties/databases.rake +47 -42
  115. data/lib/active_record/readonly_attributes.rb +0 -1
  116. data/lib/active_record/reflection.rb +225 -92
  117. data/lib/active_record/relation.rb +35 -11
  118. data/lib/active_record/relation/batches.rb +0 -2
  119. data/lib/active_record/relation/calculations.rb +28 -32
  120. data/lib/active_record/relation/delegation.rb +1 -1
  121. data/lib/active_record/relation/finder_methods.rb +42 -20
  122. data/lib/active_record/relation/merger.rb +0 -1
  123. data/lib/active_record/relation/predicate_builder.rb +1 -22
  124. data/lib/active_record/relation/predicate_builder/array_handler.rb +16 -11
  125. data/lib/active_record/relation/predicate_builder/relation_handler.rb +0 -4
  126. data/lib/active_record/relation/query_methods.rb +98 -62
  127. data/lib/active_record/relation/spawn_methods.rb +6 -7
  128. data/lib/active_record/result.rb +16 -9
  129. data/lib/active_record/sanitization.rb +8 -1
  130. data/lib/active_record/schema.rb +0 -1
  131. data/lib/active_record/schema_dumper.rb +51 -9
  132. data/lib/active_record/schema_migration.rb +4 -0
  133. data/lib/active_record/scoping/default.rb +5 -4
  134. data/lib/active_record/serializers/xml_serializer.rb +3 -7
  135. data/lib/active_record/statement_cache.rb +79 -5
  136. data/lib/active_record/store.rb +5 -5
  137. data/lib/active_record/tasks/database_tasks.rb +37 -5
  138. data/lib/active_record/tasks/mysql_database_tasks.rb +10 -16
  139. data/lib/active_record/tasks/postgresql_database_tasks.rb +2 -2
  140. data/lib/active_record/timestamp.rb +9 -7
  141. data/lib/active_record/transactions.rb +35 -21
  142. data/lib/active_record/type.rb +20 -0
  143. data/lib/active_record/type/binary.rb +40 -0
  144. data/lib/active_record/type/boolean.rb +19 -0
  145. data/lib/active_record/type/date.rb +46 -0
  146. data/lib/active_record/type/date_time.rb +43 -0
  147. data/lib/active_record/type/decimal.rb +40 -0
  148. data/lib/active_record/type/decimal_without_scale.rb +11 -0
  149. data/lib/active_record/type/float.rb +19 -0
  150. data/lib/active_record/type/hash_lookup_type_map.rb +19 -0
  151. data/lib/active_record/type/integer.rb +23 -0
  152. data/lib/active_record/type/mutable.rb +16 -0
  153. data/lib/active_record/type/numeric.rb +36 -0
  154. data/lib/active_record/type/serialized.rb +51 -0
  155. data/lib/active_record/type/string.rb +36 -0
  156. data/lib/active_record/type/text.rb +11 -0
  157. data/lib/active_record/type/time.rb +26 -0
  158. data/lib/active_record/type/time_value.rb +38 -0
  159. data/lib/active_record/type/type_map.rb +48 -0
  160. data/lib/active_record/type/value.rb +101 -0
  161. data/lib/active_record/validations.rb +21 -16
  162. data/lib/active_record/validations/uniqueness.rb +9 -23
  163. data/lib/rails/generators/active_record/migration/migration_generator.rb +8 -4
  164. data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb +1 -1
  165. data/lib/rails/generators/active_record/model/templates/model.rb +1 -1
  166. metadata +71 -14
  167. data/lib/active_record/connection_adapters/postgresql/cast.rb +0 -168
@@ -0,0 +1,16 @@
1
+ module ActiveRecord
2
+ module Type
3
+ module Mutable # :nodoc:
4
+ def type_cast_from_user(value)
5
+ type_cast_from_database(type_cast_for_database(value))
6
+ end
7
+
8
+ # +raw_old_value+ will be the `_before_type_cast` version of the
9
+ # value (likely a string). +new_value+ will be the current, type
10
+ # cast value.
11
+ def changed_in_place?(raw_old_value, new_value)
12
+ raw_old_value != type_cast_for_database(new_value)
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,36 @@
1
+ module ActiveRecord
2
+ module Type
3
+ module Numeric # :nodoc:
4
+ def number?
5
+ true
6
+ end
7
+
8
+ def type_cast(value)
9
+ value = case value
10
+ when true then 1
11
+ when false then 0
12
+ when ::String then value.presence
13
+ else value
14
+ end
15
+ super(value)
16
+ end
17
+
18
+ def changed?(old_value, _new_value, new_value_before_type_cast) # :nodoc:
19
+ super || number_to_non_number?(old_value, new_value_before_type_cast)
20
+ end
21
+
22
+ private
23
+
24
+ def number_to_non_number?(old_value, new_value_before_type_cast)
25
+ old_value != nil && non_numeric_string?(new_value_before_type_cast)
26
+ end
27
+
28
+ def non_numeric_string?(value)
29
+ # 'wibble'.to_i will give zero, we want to make sure
30
+ # that we aren't marking int zero to string zero as
31
+ # changed.
32
+ value.to_s !~ /\A\d+\.?\d*\z/
33
+ end
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,51 @@
1
+ module ActiveRecord
2
+ module Type
3
+ class Serialized < SimpleDelegator # :nodoc:
4
+ include Mutable
5
+
6
+ attr_reader :subtype, :coder
7
+
8
+ def initialize(subtype, coder)
9
+ @subtype = subtype
10
+ @coder = coder
11
+ super(subtype)
12
+ end
13
+
14
+ def type_cast_from_database(value)
15
+ if default_value?(value)
16
+ value
17
+ else
18
+ coder.load(super)
19
+ end
20
+ end
21
+
22
+ def type_cast_for_database(value)
23
+ return if value.nil?
24
+ unless default_value?(value)
25
+ super coder.dump(value)
26
+ end
27
+ end
28
+
29
+ def accessor
30
+ ActiveRecord::Store::IndifferentHashAccessor
31
+ end
32
+
33
+ def init_with(coder)
34
+ @subtype = coder['subtype']
35
+ @coder = coder['coder']
36
+ __setobj__(@subtype)
37
+ end
38
+
39
+ def encode_with(coder)
40
+ coder['subtype'] = @subtype
41
+ coder['coder'] = @coder
42
+ end
43
+
44
+ private
45
+
46
+ def default_value?(value)
47
+ value == coder.load(nil)
48
+ end
49
+ end
50
+ end
51
+ end
@@ -0,0 +1,36 @@
1
+ module ActiveRecord
2
+ module Type
3
+ class String < Value # :nodoc:
4
+ def type
5
+ :string
6
+ end
7
+
8
+ def changed_in_place?(raw_old_value, new_value)
9
+ if new_value.is_a?(::String)
10
+ raw_old_value != new_value
11
+ end
12
+ end
13
+
14
+ def type_cast_for_database(value)
15
+ case value
16
+ when ::Numeric, ActiveSupport::Duration then value.to_s
17
+ when ::String then ::String.new(value)
18
+ when true then "1"
19
+ when false then "0"
20
+ else super
21
+ end
22
+ end
23
+
24
+ private
25
+
26
+ def cast_value(value)
27
+ case value
28
+ when true then "1"
29
+ when false then "0"
30
+ # String.new is slightly faster than dup
31
+ else ::String.new(value.to_s)
32
+ end
33
+ end
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,11 @@
1
+ require 'active_record/type/string'
2
+
3
+ module ActiveRecord
4
+ module Type
5
+ class Text < String # :nodoc:
6
+ def type
7
+ :text
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,26 @@
1
+ module ActiveRecord
2
+ module Type
3
+ class Time < Value # :nodoc:
4
+ include TimeValue
5
+
6
+ def type
7
+ :time
8
+ end
9
+
10
+ private
11
+
12
+ def cast_value(value)
13
+ return value unless value.is_a?(::String)
14
+ return if value.empty?
15
+
16
+ dummy_time_value = "2000-01-01 #{value}"
17
+
18
+ fast_string_to_time(dummy_time_value) || begin
19
+ time_hash = ::Date._parse(dummy_time_value)
20
+ return if time_hash[:hour].nil?
21
+ new_time(*time_hash.values_at(:year, :mon, :mday, :hour, :min, :sec, :sec_fraction))
22
+ end
23
+ end
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,38 @@
1
+ module ActiveRecord
2
+ module Type
3
+ module TimeValue # :nodoc:
4
+ def klass
5
+ ::Time
6
+ end
7
+
8
+ def type_cast_for_schema(value)
9
+ "'#{value.to_s(:db)}'"
10
+ end
11
+
12
+ private
13
+
14
+ def new_time(year, mon, mday, hour, min, sec, microsec, offset = nil)
15
+ # Treat 0000-00-00 00:00:00 as nil.
16
+ return if year.nil? || (year == 0 && mon == 0 && mday == 0)
17
+
18
+ if offset
19
+ time = ::Time.utc(year, mon, mday, hour, min, sec, microsec) rescue nil
20
+ return unless time
21
+
22
+ time -= offset
23
+ Base.default_timezone == :utc ? time : time.getlocal
24
+ else
25
+ ::Time.public_send(Base.default_timezone, year, mon, mday, hour, min, sec, microsec) rescue nil
26
+ end
27
+ end
28
+
29
+ # Doesn't handle time zones.
30
+ def fast_string_to_time(string)
31
+ if string =~ ConnectionAdapters::Column::Format::ISO_DATETIME
32
+ microsec = ($7.to_r * 1_000_000).to_i
33
+ new_time $1.to_i, $2.to_i, $3.to_i, $4.to_i, $5.to_i, $6.to_i, microsec
34
+ end
35
+ end
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,48 @@
1
+ module ActiveRecord
2
+ module Type
3
+ class TypeMap # :nodoc:
4
+ def initialize
5
+ @mapping = {}
6
+ end
7
+
8
+ def lookup(lookup_key, *args)
9
+ matching_pair = @mapping.reverse_each.detect do |key, _|
10
+ key === lookup_key
11
+ end
12
+
13
+ if matching_pair
14
+ matching_pair.last.call(lookup_key, *args)
15
+ else
16
+ default_value
17
+ end
18
+ end
19
+
20
+ def register_type(key, value = nil, &block)
21
+ raise ::ArgumentError unless value || block
22
+
23
+ if block
24
+ @mapping[key] = block
25
+ else
26
+ @mapping[key] = proc { value }
27
+ end
28
+ end
29
+
30
+ def alias_type(key, target_key)
31
+ register_type(key) do |sql_type, *args|
32
+ metadata = sql_type[/\(.*\)/, 0]
33
+ lookup("#{target_key}#{metadata}", *args)
34
+ end
35
+ end
36
+
37
+ def clear
38
+ @mapping.clear
39
+ end
40
+
41
+ private
42
+
43
+ def default_value
44
+ @default_value ||= Value.new
45
+ end
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,101 @@
1
+ module ActiveRecord
2
+ module Type
3
+ class Value # :nodoc:
4
+ attr_reader :precision, :scale, :limit
5
+
6
+ # Valid options are +precision+, +scale+, and +limit+. They are only
7
+ # used when dumping schema.
8
+ def initialize(options = {})
9
+ options.assert_valid_keys(:precision, :scale, :limit)
10
+ @precision = options[:precision]
11
+ @scale = options[:scale]
12
+ @limit = options[:limit]
13
+ end
14
+
15
+ # The simplified type that this object represents. Returns a symbol such
16
+ # as +:string+ or +:integer+
17
+ def type; end
18
+
19
+ # Type casts a string from the database into the appropriate ruby type.
20
+ # Classes which do not need separate type casting behavior for database
21
+ # and user provided values should override +cast_value+ instead.
22
+ def type_cast_from_database(value)
23
+ type_cast(value)
24
+ end
25
+
26
+ # Type casts a value from user input (e.g. from a setter). This value may
27
+ # be a string from the form builder, or an already type cast value
28
+ # provided manually to a setter.
29
+ #
30
+ # Classes which do not need separate type casting behavior for database
31
+ # and user provided values should override +type_cast+ or +cast_value+
32
+ # instead.
33
+ def type_cast_from_user(value)
34
+ type_cast(value)
35
+ end
36
+
37
+ # Cast a value from the ruby type to a type that the database knows how
38
+ # to understand. The returned value from this method should be a
39
+ # +String+, +Numeric+, +Date+, +Time+, +Symbol+, +true+, +false+, or
40
+ # +nil+
41
+ def type_cast_for_database(value)
42
+ value
43
+ end
44
+
45
+ # Type cast a value for schema dumping. This method is private, as we are
46
+ # hoping to remove it entirely.
47
+ def type_cast_for_schema(value) # :nodoc:
48
+ value.inspect
49
+ end
50
+
51
+ # These predicates are not documented, as I need to look further into
52
+ # their use, and see if they can be removed entirely.
53
+ def number? # :nodoc:
54
+ false
55
+ end
56
+
57
+ def binary? # :nodoc:
58
+ false
59
+ end
60
+
61
+ def klass # :nodoc:
62
+ end
63
+
64
+ # Determines whether a value has changed for dirty checking. +old_value+
65
+ # and +new_value+ will always be type-cast. Types should not need to
66
+ # override this method.
67
+ def changed?(old_value, new_value, _new_value_before_type_cast)
68
+ old_value != new_value
69
+ end
70
+
71
+ # Determines whether the mutable value has been modified since it was
72
+ # read. Returns +false+ by default. This method should not be overridden
73
+ # directly. Types which return a mutable value should include
74
+ # +Type::Mutable+, which will define this method.
75
+ def changed_in_place?(*)
76
+ false
77
+ end
78
+
79
+ def ==(other)
80
+ self.class == other.class &&
81
+ precision == other.precision &&
82
+ scale == other.scale &&
83
+ limit == other.limit
84
+ end
85
+
86
+ private
87
+
88
+ def type_cast(value)
89
+ cast_value(value) unless value.nil?
90
+ end
91
+
92
+ # Convenience method for types which do not need separate type casting
93
+ # behavior for user and database inputs. Called by
94
+ # `type_cast_from_database` and `type_cast_from_user` for all values
95
+ # except `nil`.
96
+ def cast_value(value) # :doc:
97
+ value
98
+ end
99
+ end
100
+ end
101
+ end
@@ -29,21 +29,6 @@ module ActiveRecord
29
29
  extend ActiveSupport::Concern
30
30
  include ActiveModel::Validations
31
31
 
32
- module ClassMethods
33
- # Creates an object just like Base.create but calls <tt>save!</tt> instead of +save+
34
- # so an exception is raised if the record is invalid.
35
- def create!(attributes = nil, &block)
36
- if attributes.is_a?(Array)
37
- attributes.collect { |attr| create!(attr, &block) }
38
- else
39
- object = new(attributes)
40
- yield(object) if block_given?
41
- object.save!
42
- object
43
- end
44
- end
45
- end
46
-
47
32
  # The validation process on save can be skipped by passing <tt>validate: false</tt>.
48
33
  # The regular Base#save method is replaced with this when the validations
49
34
  # module is mixed in, which it is by default.
@@ -54,12 +39,14 @@ module ActiveRecord
54
39
  # Attempts to save the record just like Base#save but will raise a +RecordInvalid+
55
40
  # exception instead of returning +false+ if the record is not valid.
56
41
  def save!(options={})
57
- perform_validations(options) ? super : raise(RecordInvalid.new(self))
42
+ perform_validations(options) ? super : raise_record_invalid
58
43
  end
59
44
 
60
45
  # Runs all the validations within the specified context. Returns +true+ if
61
46
  # no errors are found, +false+ otherwise.
62
47
  #
48
+ # Aliased as validate.
49
+ #
63
50
  # If the argument is +false+ (default is +nil+), the context is set to <tt>:create</tt> if
64
51
  # <tt>new_record?</tt> is +true+, and to <tt>:update</tt> if it is not.
65
52
  #
@@ -71,8 +58,26 @@ module ActiveRecord
71
58
  errors.empty? && output
72
59
  end
73
60
 
61
+ alias_method :validate, :valid?
62
+
63
+ # Runs all the validations within the specified context. Returns +true+ if
64
+ # no errors are found, raises +RecordInvalid+ otherwise.
65
+ #
66
+ # If the argument is +false+ (default is +nil+), the context is set to <tt>:create</tt> if
67
+ # <tt>new_record?</tt> is +true+, and to <tt>:update</tt> if it is not.
68
+ #
69
+ # Validations with no <tt>:on</tt> option will run no matter the context. Validations with
70
+ # some <tt>:on</tt> option will only run in the specified context.
71
+ def validate!(context = nil)
72
+ valid?(context) || raise_record_invalid
73
+ end
74
+
74
75
  protected
75
76
 
77
+ def raise_record_invalid
78
+ raise(RecordInvalid.new(self))
79
+ end
80
+
76
81
  def perform_validations(options={}) # :nodoc:
77
82
  options[:validate] == false || valid?(options[:context])
78
83
  end
@@ -13,8 +13,7 @@ module ActiveRecord
13
13
  def validate_each(record, attribute, value)
14
14
  finder_class = find_finder_class_for(record)
15
15
  table = finder_class.arel_table
16
- value = map_enum_attribute(finder_class,attribute,value)
17
- value = deserialize_attribute(record, attribute, value)
16
+ value = map_enum_attribute(finder_class, attribute, value)
18
17
 
19
18
  relation = build_relation(finder_class, table, attribute, value)
20
19
  relation = relation.and(table[finder_class.primary_key.to_sym].not_eq(record.id)) if record.persisted?
@@ -49,7 +48,7 @@ module ActiveRecord
49
48
  def build_relation(klass, table, attribute, value) #:nodoc:
50
49
  if reflection = klass._reflect_on_association(attribute)
51
50
  attribute = reflection.foreign_key
52
- value = value.attributes[reflection.primary_key_column.name] unless value.nil?
51
+ value = value.attributes[reflection.klass.primary_key] unless value.nil?
53
52
  end
54
53
 
55
54
  attribute_name = attribute.to_s
@@ -62,14 +61,15 @@ module ActiveRecord
62
61
 
63
62
  column = klass.columns_hash[attribute_name]
64
63
  value = klass.connection.type_cast(value, column)
65
- value = value.to_s[0, column.limit] if value && column.limit && column.text?
64
+ if value.is_a?(String) && column.limit
65
+ value = value.to_s[0, column.limit]
66
+ end
66
67
 
67
- if !options[:case_sensitive] && value && column.text?
68
+ if !options[:case_sensitive] && value.is_a?(String)
68
69
  # will use SQL LOWER function before comparison, unless it detects a case insensitive collation
69
70
  klass.connection.case_insensitive_comparison(table, attribute, column, value)
70
71
  else
71
- value = klass.connection.case_sensitive_modifier(value) unless value.nil?
72
- table[attribute].eq(value)
72
+ klass.connection.case_sensitive_comparison(table, attribute, column, value)
73
73
  end
74
74
  end
75
75
 
@@ -81,26 +81,12 @@ module ActiveRecord
81
81
  else
82
82
  scope_value = record.read_attribute(scope_item)
83
83
  end
84
-
85
- # This is basically emulating an Arel::Nodes::Casted
86
- column = record.class.columns_hash[scope_item.to_s]
87
- quoted_value = record.class.connection.quote(scope_value, column)
88
- unless scope_value.nil?
89
- node = Arel::Nodes::SqlLiteral.new(quoted_value)
90
- end
91
-
92
- relation = relation.and(table[scope_item].eq(node))
84
+ relation = relation.and(table[scope_item].eq(scope_value))
93
85
  end
94
86
 
95
87
  relation
96
88
  end
97
89
 
98
- def deserialize_attribute(record, attribute, value)
99
- coder = record.class.serialized_attributes[attribute.to_s]
100
- value = coder.dump value if value && coder
101
- value
102
- end
103
-
104
90
  def map_enum_attribute(klass, attribute, value)
105
91
  mapping = klass.defined_enums[attribute.to_s]
106
92
  value = mapping[value] if value && mapping
@@ -166,7 +152,7 @@ module ActiveRecord
166
152
  # or <tt>if: Proc.new { |user| user.signup_step > 2 }</tt>). The method,
167
153
  # proc or string should return or evaluate to a +true+ or +false+ value.
168
154
  # * <tt>:unless</tt> - Specifies a method, proc or string to call to
169
- # determine if the validation should ot occur (e.g. <tt>unless: :skip_validation</tt>,
155
+ # determine if the validation should not occur (e.g. <tt>unless: :skip_validation</tt>,
170
156
  # or <tt>unless: Proc.new { |user| user.signup_step <= 2 }</tt>). The
171
157
  # method, proc or string should return or evaluate to a +true+ or +false+
172
158
  # value.