cassandra_object 0.6.0.pre
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/lib/cassandra_object/associations/one_to_many.rb +136 -0
- data/lib/cassandra_object/associations/one_to_one.rb +77 -0
- data/lib/cassandra_object/associations.rb +35 -0
- data/lib/cassandra_object/attributes.rb +93 -0
- data/lib/cassandra_object/base.rb +104 -0
- data/lib/cassandra_object/callbacks.rb +10 -0
- data/lib/cassandra_object/collection.rb +8 -0
- data/lib/cassandra_object/cursor.rb +86 -0
- data/lib/cassandra_object/dirty.rb +27 -0
- data/lib/cassandra_object/identity/abstract_key_factory.rb +36 -0
- data/lib/cassandra_object/identity/key.rb +20 -0
- data/lib/cassandra_object/identity/natural_key_factory.rb +51 -0
- data/lib/cassandra_object/identity/uuid_key_factory.rb +37 -0
- data/lib/cassandra_object/identity.rb +61 -0
- data/lib/cassandra_object/indexes.rb +129 -0
- data/lib/cassandra_object/legacy_callbacks.rb +33 -0
- data/lib/cassandra_object/migrations.rb +72 -0
- data/lib/cassandra_object/mocking.rb +15 -0
- data/lib/cassandra_object/persistence.rb +193 -0
- data/lib/cassandra_object/serialization.rb +6 -0
- data/lib/cassandra_object/type_registration.rb +7 -0
- data/lib/cassandra_object/types.rb +128 -0
- data/lib/cassandra_object/validation.rb +58 -0
- data/lib/cassandra_object.rb +30 -0
- data/vendor/active_support_shims.rb +4 -0
- data/vendor/activemodel/CHANGELOG +13 -0
- data/vendor/activemodel/CHANGES +12 -0
- data/vendor/activemodel/MIT-LICENSE +21 -0
- data/vendor/activemodel/README +21 -0
- data/vendor/activemodel/Rakefile +52 -0
- data/vendor/activemodel/activemodel.gemspec +19 -0
- data/vendor/activemodel/examples/validations.rb +29 -0
- data/vendor/activemodel/lib/active_model/attribute_methods.rb +291 -0
- data/vendor/activemodel/lib/active_model/callbacks.rb +91 -0
- data/vendor/activemodel/lib/active_model/conversion.rb +8 -0
- data/vendor/activemodel/lib/active_model/deprecated_error_methods.rb +33 -0
- data/vendor/activemodel/lib/active_model/dirty.rb +126 -0
- data/vendor/activemodel/lib/active_model/errors.rb +162 -0
- data/vendor/activemodel/lib/active_model/lint.rb +91 -0
- data/vendor/activemodel/lib/active_model/locale/en.yml +27 -0
- data/vendor/activemodel/lib/active_model/naming.rb +45 -0
- data/vendor/activemodel/lib/active_model/observing.rb +191 -0
- data/vendor/activemodel/lib/active_model/railtie.rb +2 -0
- data/vendor/activemodel/lib/active_model/serialization.rb +30 -0
- data/vendor/activemodel/lib/active_model/serializers/json.rb +96 -0
- data/vendor/activemodel/lib/active_model/serializers/xml.rb +204 -0
- data/vendor/activemodel/lib/active_model/state_machine/event.rb +62 -0
- data/vendor/activemodel/lib/active_model/state_machine/machine.rb +75 -0
- data/vendor/activemodel/lib/active_model/state_machine/state.rb +47 -0
- data/vendor/activemodel/lib/active_model/state_machine/state_transition.rb +40 -0
- data/vendor/activemodel/lib/active_model/state_machine.rb +70 -0
- data/vendor/activemodel/lib/active_model/test_case.rb +18 -0
- data/vendor/activemodel/lib/active_model/translation.rb +44 -0
- data/vendor/activemodel/lib/active_model/validations/acceptance.rb +55 -0
- data/vendor/activemodel/lib/active_model/validations/confirmation.rb +47 -0
- data/vendor/activemodel/lib/active_model/validations/exclusion.rb +42 -0
- data/vendor/activemodel/lib/active_model/validations/format.rb +64 -0
- data/vendor/activemodel/lib/active_model/validations/inclusion.rb +42 -0
- data/vendor/activemodel/lib/active_model/validations/length.rb +117 -0
- data/vendor/activemodel/lib/active_model/validations/numericality.rb +111 -0
- data/vendor/activemodel/lib/active_model/validations/presence.rb +42 -0
- data/vendor/activemodel/lib/active_model/validations/with.rb +59 -0
- data/vendor/activemodel/lib/active_model/validations.rb +120 -0
- data/vendor/activemodel/lib/active_model/validator.rb +110 -0
- data/vendor/activemodel/lib/active_model/version.rb +9 -0
- data/vendor/activemodel/lib/active_model.rb +61 -0
- data/vendor/activemodel/test/cases/attribute_methods_test.rb +46 -0
- data/vendor/activemodel/test/cases/callbacks_test.rb +70 -0
- data/vendor/activemodel/test/cases/helper.rb +23 -0
- data/vendor/activemodel/test/cases/lint_test.rb +28 -0
- data/vendor/activemodel/test/cases/naming_test.rb +28 -0
- data/vendor/activemodel/test/cases/observing_test.rb +133 -0
- data/vendor/activemodel/test/cases/serializeration/json_serialization_test.rb +83 -0
- data/vendor/activemodel/test/cases/serializeration/xml_serialization_test.rb +110 -0
- data/vendor/activemodel/test/cases/state_machine/event_test.rb +49 -0
- data/vendor/activemodel/test/cases/state_machine/machine_test.rb +43 -0
- data/vendor/activemodel/test/cases/state_machine/state_test.rb +72 -0
- data/vendor/activemodel/test/cases/state_machine/state_transition_test.rb +84 -0
- data/vendor/activemodel/test/cases/state_machine_test.rb +312 -0
- data/vendor/activemodel/test/cases/tests_database.rb +37 -0
- data/vendor/activemodel/test/cases/translation_test.rb +45 -0
- data/vendor/activemodel/test/cases/validations/acceptance_validation_test.rb +71 -0
- data/vendor/activemodel/test/cases/validations/conditional_validation_test.rb +141 -0
- data/vendor/activemodel/test/cases/validations/confirmation_validation_test.rb +58 -0
- data/vendor/activemodel/test/cases/validations/exclusion_validation_test.rb +47 -0
- data/vendor/activemodel/test/cases/validations/format_validation_test.rb +118 -0
- data/vendor/activemodel/test/cases/validations/i18n_generate_message_validation_test.rb +175 -0
- data/vendor/activemodel/test/cases/validations/i18n_validation_test.rb +527 -0
- data/vendor/activemodel/test/cases/validations/inclusion_validation_test.rb +71 -0
- data/vendor/activemodel/test/cases/validations/length_validation_test.rb +437 -0
- data/vendor/activemodel/test/cases/validations/numericality_validation_test.rb +180 -0
- data/vendor/activemodel/test/cases/validations/presence_validation_test.rb +70 -0
- data/vendor/activemodel/test/cases/validations/with_validation_test.rb +166 -0
- data/vendor/activemodel/test/cases/validations_test.rb +215 -0
- data/vendor/activemodel/test/config.rb +3 -0
- data/vendor/activemodel/test/fixtures/topics.yml +41 -0
- data/vendor/activemodel/test/models/contact.rb +7 -0
- data/vendor/activemodel/test/models/custom_reader.rb +17 -0
- data/vendor/activemodel/test/models/developer.rb +6 -0
- data/vendor/activemodel/test/models/person.rb +9 -0
- data/vendor/activemodel/test/models/reply.rb +34 -0
- data/vendor/activemodel/test/models/topic.rb +9 -0
- data/vendor/activemodel/test/models/track_back.rb +4 -0
- data/vendor/activemodel/test/schema.rb +14 -0
- data/vendor/activesupport/lib/active_support/autoload.rb +48 -0
- data/vendor/activesupport/lib/active_support/concern.rb +25 -0
- data/vendor/activesupport/lib/active_support/core_ext/array/wrap.rb +20 -0
- data/vendor/activesupport/lib/active_support/core_ext/object/blank.rb +58 -0
- data/vendor/activesupport/lib/active_support/core_ext/object/tap.rb +6 -0
- data/vendor/activesupport/lib/active_support/dependency_module.rb +17 -0
- data/vendor/activesupport/lib/active_support/i18n.rb +2 -0
- data/vendor/activesupport/lib/active_support/locale/en.yml +33 -0
- metadata +230 -0
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
module ActiveModel
|
|
2
|
+
module Validations
|
|
3
|
+
class AcceptanceValidator < EachValidator
|
|
4
|
+
def initialize(options)
|
|
5
|
+
super(options.reverse_merge(:allow_nil => true, :accept => "1"))
|
|
6
|
+
end
|
|
7
|
+
|
|
8
|
+
def validate_each(record, attribute, value)
|
|
9
|
+
unless value == options[:accept]
|
|
10
|
+
record.errors.add(attribute, :accepted, :default => options[:message])
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
module ClassMethods
|
|
16
|
+
# Encapsulates the pattern of wanting to validate the acceptance of a terms of service check box (or similar agreement). Example:
|
|
17
|
+
#
|
|
18
|
+
# class Person < ActiveRecord::Base
|
|
19
|
+
# validates_acceptance_of :terms_of_service
|
|
20
|
+
# validates_acceptance_of :eula, :message => "must be abided"
|
|
21
|
+
# end
|
|
22
|
+
#
|
|
23
|
+
# If the database column does not exist, the +terms_of_service+ attribute is entirely virtual. This check is
|
|
24
|
+
# performed only if +terms_of_service+ is not +nil+ and by default on save.
|
|
25
|
+
#
|
|
26
|
+
# Configuration options:
|
|
27
|
+
# * <tt>:message</tt> - A custom error message (default is: "must be accepted").
|
|
28
|
+
# * <tt>:on</tt> - Specifies when this validation is active (default is <tt>:save</tt>, other options <tt>:create</tt>, <tt>:update</tt>).
|
|
29
|
+
# * <tt>:allow_nil</tt> - Skip validation if attribute is +nil+ (default is true).
|
|
30
|
+
# * <tt>:accept</tt> - Specifies value that is considered accepted. The default value is a string "1", which
|
|
31
|
+
# makes it easy to relate to an HTML checkbox. This should be set to +true+ if you are validating a database
|
|
32
|
+
# column, since the attribute is typecast from "1" to +true+ before validation.
|
|
33
|
+
# * <tt>:if</tt> - Specifies a method, proc or string to call to determine if the validation should
|
|
34
|
+
# occur (e.g. <tt>:if => :allow_validation</tt>, or <tt>:if => Proc.new { |user| user.signup_step > 2 }</tt>). The
|
|
35
|
+
# method, proc or string should return or evaluate to a true or false value.
|
|
36
|
+
# * <tt>:unless</tt> - Specifies a method, proc or string to call to determine if the validation should
|
|
37
|
+
# not occur (e.g. <tt>:unless => :skip_validation</tt>, or <tt>:unless => Proc.new { |user| user.signup_step <= 2 }</tt>). The
|
|
38
|
+
# method, proc or string should return or evaluate to a true or false value.
|
|
39
|
+
def validates_acceptance_of(*attr_names)
|
|
40
|
+
options = attr_names.extract_options!
|
|
41
|
+
|
|
42
|
+
db_cols = begin
|
|
43
|
+
column_names
|
|
44
|
+
rescue Exception # To ignore both statement and connection errors
|
|
45
|
+
[]
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
names = attr_names.reject { |name| db_cols.include?(name.to_s) }
|
|
49
|
+
attr_accessor(*names)
|
|
50
|
+
|
|
51
|
+
validates_with AcceptanceValidator, options.merge(:attributes => attr_names)
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
end
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
module ActiveModel
|
|
2
|
+
module Validations
|
|
3
|
+
class ConfirmationValidator < EachValidator
|
|
4
|
+
def validate_each(record, attribute, value)
|
|
5
|
+
confirmed = record.send(:"#{attribute}_confirmation")
|
|
6
|
+
return if confirmed.nil? || value == confirmed
|
|
7
|
+
record.errors.add(attribute, :confirmation, :default => options[:message])
|
|
8
|
+
end
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
module ClassMethods
|
|
12
|
+
# Encapsulates the pattern of wanting to validate a password or email address field with a confirmation. Example:
|
|
13
|
+
#
|
|
14
|
+
# Model:
|
|
15
|
+
# class Person < ActiveRecord::Base
|
|
16
|
+
# validates_confirmation_of :user_name, :password
|
|
17
|
+
# validates_confirmation_of :email_address, :message => "should match confirmation"
|
|
18
|
+
# end
|
|
19
|
+
#
|
|
20
|
+
# View:
|
|
21
|
+
# <%= password_field "person", "password" %>
|
|
22
|
+
# <%= password_field "person", "password_confirmation" %>
|
|
23
|
+
#
|
|
24
|
+
# The added +password_confirmation+ attribute is virtual; it exists only as an in-memory attribute for validating the password.
|
|
25
|
+
# To achieve this, the validation adds accessors to the model for the confirmation attribute. NOTE: This check is performed
|
|
26
|
+
# only if +password_confirmation+ is not +nil+, and by default only on save. To require confirmation, make sure to add a presence
|
|
27
|
+
# check for the confirmation attribute:
|
|
28
|
+
#
|
|
29
|
+
# validates_presence_of :password_confirmation, :if => :password_changed?
|
|
30
|
+
#
|
|
31
|
+
# Configuration options:
|
|
32
|
+
# * <tt>:message</tt> - A custom error message (default is: "doesn't match confirmation").
|
|
33
|
+
# * <tt>:on</tt> - Specifies when this validation is active (default is <tt>:save</tt>, other options <tt>:create</tt>, <tt>:update</tt>).
|
|
34
|
+
# * <tt>:if</tt> - Specifies a method, proc or string to call to determine if the validation should
|
|
35
|
+
# occur (e.g. <tt>:if => :allow_validation</tt>, or <tt>:if => Proc.new { |user| user.signup_step > 2 }</tt>). The
|
|
36
|
+
# method, proc or string should return or evaluate to a true or false value.
|
|
37
|
+
# * <tt>:unless</tt> - Specifies a method, proc or string to call to determine if the validation should
|
|
38
|
+
# not occur (e.g. <tt>:unless => :skip_validation</tt>, or <tt>:unless => Proc.new { |user| user.signup_step <= 2 }</tt>). The
|
|
39
|
+
# method, proc or string should return or evaluate to a true or false value.
|
|
40
|
+
def validates_confirmation_of(*attr_names)
|
|
41
|
+
options = attr_names.extract_options!
|
|
42
|
+
attr_accessor(*(attr_names.map { |n| :"#{n}_confirmation" }))
|
|
43
|
+
validates_with ConfirmationValidator, options.merge(:attributes => attr_names)
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
end
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
module ActiveModel
|
|
2
|
+
module Validations
|
|
3
|
+
class ExclusionValidator < EachValidator
|
|
4
|
+
def check_validity!
|
|
5
|
+
raise ArgumentError, "An object with the method include? is required must be supplied as the " <<
|
|
6
|
+
":in option of the configuration hash" unless options[:in].respond_to?(:include?)
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
def validate_each(record, attribute, value)
|
|
10
|
+
return unless options[:in].include?(value)
|
|
11
|
+
record.errors.add(attribute, :exclusion, :default => options[:message], :value => value)
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
module ClassMethods
|
|
16
|
+
# Validates that the value of the specified attribute is not in a particular enumerable object.
|
|
17
|
+
#
|
|
18
|
+
# class Person < ActiveRecord::Base
|
|
19
|
+
# validates_exclusion_of :username, :in => %w( admin superuser ), :message => "You don't belong here"
|
|
20
|
+
# validates_exclusion_of :age, :in => 30..60, :message => "This site is only for under 30 and over 60"
|
|
21
|
+
# validates_exclusion_of :format, :in => %w( mov avi ), :message => "extension {{value}} is not allowed"
|
|
22
|
+
# end
|
|
23
|
+
#
|
|
24
|
+
# Configuration options:
|
|
25
|
+
# * <tt>:in</tt> - An enumerable object of items that the value shouldn't be part of.
|
|
26
|
+
# * <tt>:message</tt> - Specifies a custom error message (default is: "is reserved").
|
|
27
|
+
# * <tt>:allow_nil</tt> - If set to true, skips this validation if the attribute is +nil+ (default is +false+).
|
|
28
|
+
# * <tt>:allow_blank</tt> - If set to true, skips this validation if the attribute is blank (default is +false+).
|
|
29
|
+
# * <tt>:if</tt> - Specifies a method, proc or string to call to determine if the validation should
|
|
30
|
+
# occur (e.g. <tt>:if => :allow_validation</tt>, or <tt>:if => Proc.new { |user| user.signup_step > 2 }</tt>). The
|
|
31
|
+
# method, proc or string should return or evaluate to a true or false value.
|
|
32
|
+
# * <tt>:unless</tt> - Specifies a method, proc or string to call to determine if the validation should
|
|
33
|
+
# not occur (e.g. <tt>:unless => :skip_validation</tt>, or <tt>:unless => Proc.new { |user| user.signup_step <= 2 }</tt>). The
|
|
34
|
+
# method, proc or string should return or evaluate to a true or false value.
|
|
35
|
+
def validates_exclusion_of(*attr_names)
|
|
36
|
+
options = attr_names.extract_options!
|
|
37
|
+
options[:in] ||= options.delete(:within)
|
|
38
|
+
validates_with ExclusionValidator, options.merge(:attributes => attr_names)
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
end
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
module ActiveModel
|
|
2
|
+
module Validations
|
|
3
|
+
class FormatValidator < EachValidator
|
|
4
|
+
def validate_each(record, attribute, value)
|
|
5
|
+
if options[:with] && value.to_s !~ options[:with]
|
|
6
|
+
record.errors.add(attribute, :invalid, :default => options[:message], :value => value)
|
|
7
|
+
elsif options[:without] && value.to_s =~ options[:without]
|
|
8
|
+
record.errors.add(attribute, :invalid, :default => options[:message], :value => value)
|
|
9
|
+
end
|
|
10
|
+
end
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
module ClassMethods
|
|
14
|
+
# Validates whether the value of the specified attribute is of the correct form, going by the regular expression provided.
|
|
15
|
+
# You can require that the attribute matches the regular expression:
|
|
16
|
+
#
|
|
17
|
+
# class Person < ActiveRecord::Base
|
|
18
|
+
# validates_format_of :email, :with => /\A([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})\Z/i, :on => :create
|
|
19
|
+
# end
|
|
20
|
+
#
|
|
21
|
+
# Alternatively, you can require that the specified attribute does _not_ match the regular expression:
|
|
22
|
+
#
|
|
23
|
+
# class Person < ActiveRecord::Base
|
|
24
|
+
# validates_format_of :email, :without => /NOSPAM/
|
|
25
|
+
# end
|
|
26
|
+
#
|
|
27
|
+
# Note: use <tt>\A</tt> and <tt>\Z</tt> to match the start and end of the string, <tt>^</tt> and <tt>$</tt> match the start/end of a line.
|
|
28
|
+
#
|
|
29
|
+
# You must pass either <tt>:with</tt> or <tt>:without</tt> as an option. In addition, both must be a regular expression,
|
|
30
|
+
# or else an exception will be raised.
|
|
31
|
+
#
|
|
32
|
+
# Configuration options:
|
|
33
|
+
# * <tt>:message</tt> - A custom error message (default is: "is invalid").
|
|
34
|
+
# * <tt>:allow_nil</tt> - If set to true, skips this validation if the attribute is +nil+ (default is +false+).
|
|
35
|
+
# * <tt>:allow_blank</tt> - If set to true, skips this validation if the attribute is blank (default is +false+).
|
|
36
|
+
# * <tt>:with</tt> - Regular expression that if the attribute matches will result in a successful validation.
|
|
37
|
+
# * <tt>:without</tt> - Regular expression that if the attribute does not match will result in a successful validation.
|
|
38
|
+
# * <tt>:on</tt> - Specifies when this validation is active (default is <tt>:save</tt>, other options <tt>:create</tt>, <tt>:update</tt>).
|
|
39
|
+
# * <tt>:if</tt> - Specifies a method, proc or string to call to determine if the validation should
|
|
40
|
+
# occur (e.g. <tt>:if => :allow_validation</tt>, or <tt>:if => Proc.new { |user| user.signup_step > 2 }</tt>). The
|
|
41
|
+
# method, proc or string should return or evaluate to a true or false value.
|
|
42
|
+
# * <tt>:unless</tt> - Specifies a method, proc or string to call to determine if the validation should
|
|
43
|
+
# not occur (e.g. <tt>:unless => :skip_validation</tt>, or <tt>:unless => Proc.new { |user| user.signup_step <= 2 }</tt>). The
|
|
44
|
+
# method, proc or string should return or evaluate to a true or false value.
|
|
45
|
+
def validates_format_of(*attr_names)
|
|
46
|
+
options = attr_names.extract_options!
|
|
47
|
+
|
|
48
|
+
unless options.include?(:with) ^ options.include?(:without) # ^ == xor, or "exclusive or"
|
|
49
|
+
raise ArgumentError, "Either :with or :without must be supplied (but not both)"
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
if options[:with] && !options[:with].is_a?(Regexp)
|
|
53
|
+
raise ArgumentError, "A regular expression must be supplied as the :with option of the configuration hash"
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
if options[:without] && !options[:without].is_a?(Regexp)
|
|
57
|
+
raise ArgumentError, "A regular expression must be supplied as the :without option of the configuration hash"
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
validates_with FormatValidator, options.merge(:attributes => attr_names)
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
end
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
module ActiveModel
|
|
2
|
+
module Validations
|
|
3
|
+
class InclusionValidator < EachValidator
|
|
4
|
+
def check_validity!
|
|
5
|
+
raise ArgumentError, "An object with the method include? is required must be supplied as the " <<
|
|
6
|
+
":in option of the configuration hash" unless options[:in].respond_to?(:include?)
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
def validate_each(record, attribute, value)
|
|
10
|
+
return if options[:in].include?(value)
|
|
11
|
+
record.errors.add(attribute, :inclusion, :default => options[:message], :value => value)
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
module ClassMethods
|
|
16
|
+
# Validates whether the value of the specified attribute is available in a particular enumerable object.
|
|
17
|
+
#
|
|
18
|
+
# class Person < ActiveRecord::Base
|
|
19
|
+
# validates_inclusion_of :gender, :in => %w( m f )
|
|
20
|
+
# validates_inclusion_of :age, :in => 0..99
|
|
21
|
+
# validates_inclusion_of :format, :in => %w( jpg gif png ), :message => "extension {{value}} is not included in the list"
|
|
22
|
+
# end
|
|
23
|
+
#
|
|
24
|
+
# Configuration options:
|
|
25
|
+
# * <tt>:in</tt> - An enumerable object of available items.
|
|
26
|
+
# * <tt>:message</tt> - Specifies a custom error message (default is: "is not included in the list").
|
|
27
|
+
# * <tt>:allow_nil</tt> - If set to true, skips this validation if the attribute is +nil+ (default is +false+).
|
|
28
|
+
# * <tt>:allow_blank</tt> - If set to true, skips this validation if the attribute is blank (default is +false+).
|
|
29
|
+
# * <tt>:if</tt> - Specifies a method, proc or string to call to determine if the validation should
|
|
30
|
+
# occur (e.g. <tt>:if => :allow_validation</tt>, or <tt>:if => Proc.new { |user| user.signup_step > 2 }</tt>). The
|
|
31
|
+
# method, proc or string should return or evaluate to a true or false value.
|
|
32
|
+
# * <tt>:unless</tt> - Specifies a method, proc or string to call to determine if the validation should
|
|
33
|
+
# not occur (e.g. <tt>:unless => :skip_validation</tt>, or <tt>:unless => Proc.new { |user| user.signup_step <= 2 }</tt>). The
|
|
34
|
+
# method, proc or string should return or evaluate to a true or false value.
|
|
35
|
+
def validates_inclusion_of(*attr_names)
|
|
36
|
+
options = attr_names.extract_options!
|
|
37
|
+
options[:in] ||= options.delete(:within)
|
|
38
|
+
validates_with InclusionValidator, options.merge(:attributes => attr_names)
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
end
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
module ActiveModel
|
|
2
|
+
module Validations
|
|
3
|
+
class LengthValidator < EachValidator
|
|
4
|
+
OPTIONS = [ :is, :within, :in, :minimum, :maximum ].freeze
|
|
5
|
+
MESSAGES = { :is => :wrong_length, :minimum => :too_short, :maximum => :too_long }.freeze
|
|
6
|
+
CHECKS = { :is => :==, :minimum => :>=, :maximum => :<= }.freeze
|
|
7
|
+
|
|
8
|
+
DEFAULT_TOKENIZER = lambda { |value| value.split(//) }
|
|
9
|
+
attr_reader :type
|
|
10
|
+
|
|
11
|
+
def initialize(options)
|
|
12
|
+
@type = (OPTIONS & options.keys).first
|
|
13
|
+
super(options.reverse_merge(:tokenizer => DEFAULT_TOKENIZER))
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def check_validity!
|
|
17
|
+
ensure_one_range_option!
|
|
18
|
+
ensure_argument_types!
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def validate_each(record, attribute, value)
|
|
22
|
+
checks = options.slice(:minimum, :maximum, :is)
|
|
23
|
+
value = options[:tokenizer].call(value) if value.kind_of?(String)
|
|
24
|
+
|
|
25
|
+
if [:within, :in].include?(type)
|
|
26
|
+
range = options[type]
|
|
27
|
+
checks[:minimum], checks[:maximum] = range.begin, range.end
|
|
28
|
+
checks[:maximum] -= 1 if range.exclude_end?
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
checks.each do |key, check_value|
|
|
32
|
+
custom_message = options[:message] || options[MESSAGES[key]]
|
|
33
|
+
validity_check = CHECKS[key]
|
|
34
|
+
|
|
35
|
+
valid_value = if key == :maximum
|
|
36
|
+
value.nil? || value.size.send(validity_check, check_value)
|
|
37
|
+
else
|
|
38
|
+
value && value.size.send(validity_check, check_value)
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
record.errors.add(attribute, MESSAGES[key], :default => custom_message, :count => check_value) unless valid_value
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
protected
|
|
46
|
+
|
|
47
|
+
def ensure_one_range_option! #:nodoc:
|
|
48
|
+
range_options = OPTIONS & options.keys
|
|
49
|
+
|
|
50
|
+
case range_options.size
|
|
51
|
+
when 0
|
|
52
|
+
raise ArgumentError, 'Range unspecified. Specify the :within, :maximum, :minimum, or :is option.'
|
|
53
|
+
when 1
|
|
54
|
+
# Valid number of options; do nothing.
|
|
55
|
+
else
|
|
56
|
+
raise ArgumentError, 'Too many range options specified. Choose only one.'
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
def ensure_argument_types! #:nodoc:
|
|
61
|
+
value = options[type]
|
|
62
|
+
|
|
63
|
+
case type
|
|
64
|
+
when :within, :in
|
|
65
|
+
raise ArgumentError, ":#{type} must be a Range" unless value.is_a?(Range)
|
|
66
|
+
when :is, :minimum, :maximum
|
|
67
|
+
raise ArgumentError, ":#{type} must be a nonnegative Integer" unless value.is_a?(Integer) && value >= 0
|
|
68
|
+
end
|
|
69
|
+
end
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
module ClassMethods
|
|
73
|
+
|
|
74
|
+
# Validates that the specified attribute matches the length restrictions supplied. Only one option can be used at a time:
|
|
75
|
+
#
|
|
76
|
+
# class Person < ActiveRecord::Base
|
|
77
|
+
# validates_length_of :first_name, :maximum=>30
|
|
78
|
+
# validates_length_of :last_name, :maximum=>30, :message=>"less than {{count}} if you don't mind"
|
|
79
|
+
# validates_length_of :fax, :in => 7..32, :allow_nil => true
|
|
80
|
+
# validates_length_of :phone, :in => 7..32, :allow_blank => true
|
|
81
|
+
# validates_length_of :user_name, :within => 6..20, :too_long => "pick a shorter name", :too_short => "pick a longer name"
|
|
82
|
+
# validates_length_of :fav_bra_size, :minimum => 1, :too_short => "please enter at least {{count}} character"
|
|
83
|
+
# validates_length_of :smurf_leader, :is => 4, :message => "papa is spelled with {{count}} characters... don't play me."
|
|
84
|
+
# validates_length_of :essay, :minimum => 100, :too_short => "Your essay must be at least {{count}} words."), :tokenizer => lambda {|str| str.scan(/\w+/) }
|
|
85
|
+
# end
|
|
86
|
+
#
|
|
87
|
+
# Configuration options:
|
|
88
|
+
# * <tt>:minimum</tt> - The minimum size of the attribute.
|
|
89
|
+
# * <tt>:maximum</tt> - The maximum size of the attribute.
|
|
90
|
+
# * <tt>:is</tt> - The exact size of the attribute.
|
|
91
|
+
# * <tt>:within</tt> - A range specifying the minimum and maximum size of the attribute.
|
|
92
|
+
# * <tt>:in</tt> - A synonym(or alias) for <tt>:within</tt>.
|
|
93
|
+
# * <tt>:allow_nil</tt> - Attribute may be +nil+; skip validation.
|
|
94
|
+
# * <tt>:allow_blank</tt> - Attribute may be blank; skip validation.
|
|
95
|
+
# * <tt>:too_long</tt> - The error message if the attribute goes over the maximum (default is: "is too long (maximum is {{count}} characters)").
|
|
96
|
+
# * <tt>:too_short</tt> - The error message if the attribute goes under the minimum (default is: "is too short (min is {{count}} characters)").
|
|
97
|
+
# * <tt>:wrong_length</tt> - The error message if using the <tt>:is</tt> method and the attribute is the wrong size (default is: "is the wrong length (should be {{count}} characters)").
|
|
98
|
+
# * <tt>:message</tt> - The error message to use for a <tt>:minimum</tt>, <tt>:maximum</tt>, or <tt>:is</tt> violation. An alias of the appropriate <tt>too_long</tt>/<tt>too_short</tt>/<tt>wrong_length</tt> message.
|
|
99
|
+
# * <tt>:on</tt> - Specifies when this validation is active (default is <tt>:save</tt>, other options <tt>:create</tt>, <tt>:update</tt>).
|
|
100
|
+
# * <tt>:if</tt> - Specifies a method, proc or string to call to determine if the validation should
|
|
101
|
+
# occur (e.g. <tt>:if => :allow_validation</tt>, or <tt>:if => Proc.new { |user| user.signup_step > 2 }</tt>). The
|
|
102
|
+
# method, proc or string should return or evaluate to a true or false value.
|
|
103
|
+
# * <tt>:unless</tt> - Specifies a method, proc or string to call to determine if the validation should
|
|
104
|
+
# not occur (e.g. <tt>:unless => :skip_validation</tt>, or <tt>:unless => Proc.new { |user| user.signup_step <= 2 }</tt>). The
|
|
105
|
+
# method, proc or string should return or evaluate to a true or false value.
|
|
106
|
+
# * <tt>:tokenizer</tt> - Specifies how to split up the attribute string. (e.g. <tt>:tokenizer => lambda {|str| str.scan(/\w+/)}</tt> to
|
|
107
|
+
# count words as in above example.)
|
|
108
|
+
# Defaults to <tt>lambda{ |value| value.split(//) }</tt> which counts individual characters.
|
|
109
|
+
def validates_length_of(*attr_names)
|
|
110
|
+
options = attr_names.extract_options!
|
|
111
|
+
validates_with LengthValidator, options.merge(:attributes => attr_names)
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
alias_method :validates_size_of, :validates_length_of
|
|
115
|
+
end
|
|
116
|
+
end
|
|
117
|
+
end
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
module ActiveModel
|
|
2
|
+
module Validations
|
|
3
|
+
class NumericalityValidator < EachValidator
|
|
4
|
+
CHECKS = { :greater_than => :>, :greater_than_or_equal_to => :>=,
|
|
5
|
+
:equal_to => :==, :less_than => :<, :less_than_or_equal_to => :<=,
|
|
6
|
+
:odd => :odd?, :even => :even? }.freeze
|
|
7
|
+
|
|
8
|
+
def initialize(options)
|
|
9
|
+
super(options.reverse_merge(:only_integer => false, :allow_nil => false))
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def check_validity!
|
|
13
|
+
options.slice(*CHECKS.keys) do |option, value|
|
|
14
|
+
next if [:odd, :even].include?(option)
|
|
15
|
+
raise ArgumentError, ":#{option} must be a number, a symbol or a proc" unless value.is_a?(Numeric) || value.is_a?(Proc) || value.is_a?(Symbol)
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def validate_each(record, attr_name, value)
|
|
20
|
+
before_type_cast = "#{attr_name}_before_type_cast"
|
|
21
|
+
|
|
22
|
+
raw_value = record.send("#{attr_name}_before_type_cast") if record.respond_to?(before_type_cast.to_sym)
|
|
23
|
+
raw_value ||= value
|
|
24
|
+
|
|
25
|
+
return if options[:allow_nil] && raw_value.nil?
|
|
26
|
+
|
|
27
|
+
unless value = parse_raw_value(raw_value, options)
|
|
28
|
+
record.errors.add(attr_name, :not_a_number, :value => raw_value, :default => options[:message])
|
|
29
|
+
return
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
options.slice(*CHECKS.keys).each do |option, option_value|
|
|
33
|
+
case option
|
|
34
|
+
when :odd, :even
|
|
35
|
+
unless value.to_i.send(CHECKS[option])
|
|
36
|
+
record.errors.add(attr_name, option, :value => value, :default => options[:message])
|
|
37
|
+
end
|
|
38
|
+
else
|
|
39
|
+
option_value = option_value.call(record) if option_value.is_a?(Proc)
|
|
40
|
+
option_value = record.send(option_value) if option_value.is_a?(Symbol)
|
|
41
|
+
|
|
42
|
+
unless value.send(CHECKS[option], option_value)
|
|
43
|
+
record.errors.add(attr_name, option, :default => options[:message], :value => value, :count => option_value)
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
protected
|
|
50
|
+
|
|
51
|
+
def parse_raw_value(raw_value, options)
|
|
52
|
+
if options[:only_integer]
|
|
53
|
+
raw_value.to_i if raw_value.to_s =~ /\A[+-]?\d+\Z/
|
|
54
|
+
else
|
|
55
|
+
begin
|
|
56
|
+
Kernel.Float(raw_value)
|
|
57
|
+
rescue ArgumentError, TypeError
|
|
58
|
+
nil
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
module ClassMethods
|
|
66
|
+
# Validates whether the value of the specified attribute is numeric by trying to convert it to
|
|
67
|
+
# a float with Kernel.Float (if <tt>only_integer</tt> is false) or applying it to the regular expression
|
|
68
|
+
# <tt>/\A[\+\-]?\d+\Z/</tt> (if <tt>only_integer</tt> is set to true).
|
|
69
|
+
#
|
|
70
|
+
# class Person < ActiveRecord::Base
|
|
71
|
+
# validates_numericality_of :value, :on => :create
|
|
72
|
+
# end
|
|
73
|
+
#
|
|
74
|
+
# Configuration options:
|
|
75
|
+
# * <tt>:message</tt> - A custom error message (default is: "is not a number").
|
|
76
|
+
# * <tt>:on</tt> - Specifies when this validation is active (default is <tt>:save</tt>, other options <tt>:create</tt>, <tt>:update</tt>).
|
|
77
|
+
# * <tt>:only_integer</tt> - Specifies whether the value has to be an integer, e.g. an integral value (default is +false+).
|
|
78
|
+
# * <tt>:allow_nil</tt> - Skip validation if attribute is +nil+ (default is +false+). Notice that for fixnum and float columns empty strings are converted to +nil+.
|
|
79
|
+
# * <tt>:greater_than</tt> - Specifies the value must be greater than the supplied value.
|
|
80
|
+
# * <tt>:greater_than_or_equal_to</tt> - Specifies the value must be greater than or equal the supplied value.
|
|
81
|
+
# * <tt>:equal_to</tt> - Specifies the value must be equal to the supplied value.
|
|
82
|
+
# * <tt>:less_than</tt> - Specifies the value must be less than the supplied value.
|
|
83
|
+
# * <tt>:less_than_or_equal_to</tt> - Specifies the value must be less than or equal the supplied value.
|
|
84
|
+
# * <tt>:odd</tt> - Specifies the value must be an odd number.
|
|
85
|
+
# * <tt>:even</tt> - Specifies the value must be an even number.
|
|
86
|
+
# * <tt>:if</tt> - Specifies a method, proc or string to call to determine if the validation should
|
|
87
|
+
# occur (e.g. <tt>:if => :allow_validation</tt>, or <tt>:if => Proc.new { |user| user.signup_step > 2 }</tt>). The
|
|
88
|
+
# method, proc or string should return or evaluate to a true or false value.
|
|
89
|
+
# * <tt>:unless</tt> - Specifies a method, proc or string to call to determine if the validation should
|
|
90
|
+
# not occur (e.g. <tt>:unless => :skip_validation</tt>, or <tt>:unless => Proc.new { |user| user.signup_step <= 2 }</tt>). The
|
|
91
|
+
# method, proc or string should return or evaluate to a true or false value.
|
|
92
|
+
#
|
|
93
|
+
# The following checks can also be supplied with a proc or a symbol which corresponds to a method:
|
|
94
|
+
# * <tt>:greater_than</tt>
|
|
95
|
+
# * <tt>:greater_than_or_equal_to</tt>
|
|
96
|
+
# * <tt>:equal_to</tt>
|
|
97
|
+
# * <tt>:less_than</tt>
|
|
98
|
+
# * <tt>:less_than_or_equal_to</tt>
|
|
99
|
+
#
|
|
100
|
+
# class Person < ActiveRecord::Base
|
|
101
|
+
# validates_numericality_of :width, :less_than => Proc.new { |person| person.height }
|
|
102
|
+
# validates_numericality_of :width, :greater_than => :minimum_weight
|
|
103
|
+
# end
|
|
104
|
+
#
|
|
105
|
+
def validates_numericality_of(*attr_names)
|
|
106
|
+
options = attr_names.extract_options!
|
|
107
|
+
validates_with NumericalityValidator, options.merge(:attributes => attr_names)
|
|
108
|
+
end
|
|
109
|
+
end
|
|
110
|
+
end
|
|
111
|
+
end
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
require 'active_support/core_ext/object/blank'
|
|
2
|
+
|
|
3
|
+
module ActiveModel
|
|
4
|
+
module Validations
|
|
5
|
+
class PresenceValidator < EachValidator
|
|
6
|
+
def validate(record)
|
|
7
|
+
record.errors.add_on_blank(attributes, options[:message])
|
|
8
|
+
end
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
module ClassMethods
|
|
12
|
+
# Validates that the specified attributes are not blank (as defined by Object#blank?). Happens by default on save. Example:
|
|
13
|
+
#
|
|
14
|
+
# class Person < ActiveRecord::Base
|
|
15
|
+
# validates_presence_of :first_name
|
|
16
|
+
# end
|
|
17
|
+
#
|
|
18
|
+
# The first_name attribute must be in the object and it cannot be blank.
|
|
19
|
+
#
|
|
20
|
+
# If you want to validate the presence of a boolean field (where the real values are true and false),
|
|
21
|
+
# you will want to use <tt>validates_inclusion_of :field_name, :in => [true, false]</tt>.
|
|
22
|
+
#
|
|
23
|
+
# This is due to the way Object#blank? handles boolean values: <tt>false.blank? # => true</tt>.
|
|
24
|
+
#
|
|
25
|
+
# Configuration options:
|
|
26
|
+
# * <tt>message</tt> - A custom error message (default is: "can't be blank").
|
|
27
|
+
# * <tt>on</tt> - Specifies when this validation is active (default is <tt>:save</tt>, other options <tt>:create</tt>,
|
|
28
|
+
# <tt>:update</tt>).
|
|
29
|
+
# * <tt>if</tt> - Specifies a method, proc or string to call to determine if the validation should
|
|
30
|
+
# occur (e.g. <tt>:if => :allow_validation</tt>, or <tt>:if => Proc.new { |user| user.signup_step > 2 }</tt>).
|
|
31
|
+
# The method, proc or string should return or evaluate to a true or false value.
|
|
32
|
+
# * <tt>unless</tt> - Specifies a method, proc or string to call to determine if the validation should
|
|
33
|
+
# not occur (e.g. <tt>:unless => :skip_validation</tt>, or <tt>:unless => Proc.new { |user| user.signup_step <= 2 }</tt>).
|
|
34
|
+
# The method, proc or string should return or evaluate to a true or false value.
|
|
35
|
+
#
|
|
36
|
+
def validates_presence_of(*attr_names)
|
|
37
|
+
options = attr_names.extract_options!
|
|
38
|
+
validates_with PresenceValidator, options.merge(:attributes => attr_names)
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
end
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
module ActiveModel
|
|
2
|
+
module Validations
|
|
3
|
+
module ClassMethods
|
|
4
|
+
|
|
5
|
+
# Passes the record off to the class or classes specified and allows them to add errors based on more complex conditions.
|
|
6
|
+
#
|
|
7
|
+
# class Person < ActiveRecord::Base
|
|
8
|
+
# validates_with MyValidator
|
|
9
|
+
# end
|
|
10
|
+
#
|
|
11
|
+
# class MyValidator < ActiveRecord::Validator
|
|
12
|
+
# def validate
|
|
13
|
+
# if some_complex_logic
|
|
14
|
+
# record.errors[:base] << "This record is invalid"
|
|
15
|
+
# end
|
|
16
|
+
# end
|
|
17
|
+
#
|
|
18
|
+
# private
|
|
19
|
+
# def some_complex_logic
|
|
20
|
+
# # ...
|
|
21
|
+
# end
|
|
22
|
+
# end
|
|
23
|
+
#
|
|
24
|
+
# You may also pass it multiple classes, like so:
|
|
25
|
+
#
|
|
26
|
+
# class Person < ActiveRecord::Base
|
|
27
|
+
# validates_with MyValidator, MyOtherValidator, :on => :create
|
|
28
|
+
# end
|
|
29
|
+
#
|
|
30
|
+
# Configuration options:
|
|
31
|
+
# * <tt>on</tt> - Specifies when this validation is active (<tt>:create</tt> or <tt>:update</tt>
|
|
32
|
+
# * <tt>if</tt> - Specifies a method, proc or string to call to determine if the validation should
|
|
33
|
+
# occur (e.g. <tt>:if => :allow_validation</tt>, or <tt>:if => Proc.new { |user| user.signup_step > 2 }</tt>).
|
|
34
|
+
# The method, proc or string should return or evaluate to a true or false value.
|
|
35
|
+
# * <tt>unless</tt> - Specifies a method, proc or string to call to determine if the validation should
|
|
36
|
+
# not occur (e.g. <tt>:unless => :skip_validation</tt>, or <tt>:unless => Proc.new { |user| user.signup_step <= 2 }</tt>).
|
|
37
|
+
# The method, proc or string should return or evaluate to a true or false value.
|
|
38
|
+
#
|
|
39
|
+
# If you pass any additional configuration options, they will be passed to the class and available as <tt>options</tt>:
|
|
40
|
+
#
|
|
41
|
+
# class Person < ActiveRecord::Base
|
|
42
|
+
# validates_with MyValidator, :my_custom_key => "my custom value"
|
|
43
|
+
# end
|
|
44
|
+
#
|
|
45
|
+
# class MyValidator < ActiveRecord::Validator
|
|
46
|
+
# def validate
|
|
47
|
+
# options[:my_custom_key] # => "my custom value"
|
|
48
|
+
# end
|
|
49
|
+
# end
|
|
50
|
+
#
|
|
51
|
+
def validates_with(*args, &block)
|
|
52
|
+
options = args.extract_options!
|
|
53
|
+
args.each { |klass| validate(klass.new(options, &block), options) }
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
|