validates_existence 0.4.0 → 0.5.2

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/README.markdown CHANGED
@@ -4,7 +4,31 @@ This plugin library adds ActiveRecord models a way to check if a `:belongs_to` a
4
4
  This is achieved via adding a `validates_existence_of` validator to the base validations module.
5
5
  It also supports `:allow_nil => true/false` and `:polymorphic => true` associations.
6
6
 
7
- ### Example
7
+ Version 0.4.0 also adds Rails 3 support (the appropriate version is used automatically).
8
+ Version 0.5.0 introduces a new option - `:both` and changes the default behaviour of error attaching.
9
+
10
+ #### Changes in 0.5.0
11
+
12
+ In verions prior to 0.5.0 the error message was attached to the field which the validation was defined on.
13
+ For example if the validation was on `:relation_id` field, then the error was accessible via `object.errors.on(:relation_id)`.
14
+ The new default behaviour is attaching the error on both fields: `:relation` and `:relation_id` for convenience.
15
+ This functionality can be controlled through the `:both` option, which accepts true/false value and defaults to true.
16
+
17
+ ### Installation
18
+ First install the gem:
19
+ sudo gem install validates_existence
20
+
21
+ #### Rails 2.x
22
+ # environment.rb
23
+ config.gem "validates_existence", :source => "http://rubygems.org"
24
+
25
+ #### Rails 3
26
+ # Gemfile
27
+ gem "validates_existence", ">= 0.4"
28
+
29
+ ### Example usage
30
+
31
+ #### Rails 2.x
8
32
  class Pony < ActiveRecord::Base
9
33
  belongs_to :wizard
10
34
  belongs_to :person, :polymorphic => true
@@ -12,6 +36,8 @@ It also supports `:allow_nil => true/false` and `:polymorphic => true` associati
12
36
  validates_existence_of :wizard_id
13
37
  validates_existence_of :wizard #works both ways
14
38
 
39
+ validates_existence_of :wizard, :both => false
40
+
15
41
  validates_existence_of :person, :allow_nil => true
16
42
  end
17
43
 
@@ -20,13 +46,25 @@ It also supports `:allow_nil => true/false` and `:polymorphic => true` associati
20
46
  pony.valid?
21
47
 
22
48
  pony.errors.on(:wizard) #=> "does not exist"
49
+
50
+ #### Rails 3
51
+ class Unicorn < ActiveRecord::Base
52
+ belongs_to :wizard
53
+ belongs_to :person, :polymorphic => true
54
+
55
+ validates :wizard, :existence => true
56
+ validates :wizard_id, :existence => true # works both way
57
+ validates :person, :existence => { :allow_nil => true, :both => false }
58
+
59
+ # the old method is supported also
60
+ validates_existence :wizard
61
+ end
23
62
 
24
63
  ## I18N
25
64
 
26
65
  The default error message is `does not exist`.
27
66
  This can be customized via Rails I18N like any other validation error message via `:existence` key.
28
67
 
29
-
30
68
  ### Example
31
69
 
32
70
  This would be your customized en.yaml:
@@ -45,4 +83,4 @@ This plugin is inspired by ideas from **Josh Susser**
45
83
  **Tarmo Lehtpuu** - tarmo.lehtpuu_at_perfectline_d0t_ee
46
84
 
47
85
  ## License
48
- Copyright 2009 by PerfectLine LLC (<http://www.perfectline.co.uk>) and is released under the MIT license.
86
+ Copyright 2010 by PerfectLine LLC (<http://www.perfectline.co.uk>) and is released under the MIT license.
@@ -1,40 +1,40 @@
1
- module Perfectline
2
- module ValidatesExistence
3
-
4
- def validates_existence_of(*attr_names)
5
- configuration = {:message => "does not exist", :on => :save}
6
- configuration.update(attr_names.extract_options!.symbolize_keys)
7
-
8
- send(validation_method(configuration[:on] || :save), configuration) do |record|
9
-
10
- attr_names.each do |attr|
11
- association = reflect_on_association(attr.to_s.sub(/_id$/, '').to_sym)
12
-
13
- if association.nil? || association.macro != :belongs_to
14
- raise ArgumentError, "Can not validate existence on #{attribute}, not a belongs_to association."
15
- end
16
-
17
- value = record.__send__(association.primary_key_name)
18
- next if value.nil? && configuration[:allow_nil]
19
-
20
- if association.options.has_key?(:foreign_type)
21
- foreign_type = record.__send__(association.options[:foreign_type])
22
-
23
- if not foreign_type.blank?
24
- association_class = foreign_type.constantize
25
- else
26
- record.errors.add(attr, :existence, :default => configuration[:message]) and next
27
- end
28
- else
29
- association_class = association.klass
30
- end
31
-
32
- unless association_class.exists?(value)
33
- record.errors.add(attr, :existence, :default => configuration[:message])
34
- end
35
- end
36
- end
37
- end
38
-
39
- end
1
+ module Perfectline
2
+ module ValidatesExistence
3
+
4
+ def validates_existence_of(*attribute_names)
5
+ options = attribute_names.extract_options!.symbolize_keys
6
+ options[:message] ||= :existence
7
+ options[:both] = true unless options.has_key?(:both)
8
+
9
+ validates_each(attribute_names, options) do |record, attribute, value|
10
+ normalized = attribute.to_s.sub(/_id$/, "").to_sym
11
+ association = record.class.reflect_on_association(normalized)
12
+
13
+ if association.nil? or !association.belongs_to?
14
+ raise ArgumentError, "Cannot validate existence on #{normalized}, not a :belongs_to association"
15
+ end
16
+
17
+ target_class = nil
18
+
19
+ # dealing with polymorphic belongs_to
20
+ if association.options.has_key?(:foreign_type)
21
+ foreign_type = record.__send__(association.options.fetch(:foreign_type))
22
+ target_class = foreign_type.constantize unless foreign_type.nil?
23
+ else
24
+ target_class = association.klass
25
+ end
26
+
27
+ if target_class.nil? or !target_class.exists?(value)
28
+ record.errors.add(attribute, options[:message], :default => "does not exist")
29
+
30
+ # add the error on both :relation and :relation_id
31
+ if options[:both]
32
+ normalized = attribute.to_s.ends_with?("_id") ? normalized : "#{attribute}_id"
33
+ record.errors.add(normalized, options[:message], :default => "does not exist")
34
+ end
35
+ end
36
+ end
37
+ end
38
+
39
+ end
40
40
  end
@@ -1,54 +1,55 @@
1
- module Perfectline
2
- module ValidatesExistence
3
-
4
- module InstanceMethods
5
- class ExistenceValidator < ActiveModel::EachValidator
6
-
7
- def initialize(options)
8
- # set the default message if its unspecified
9
- options[:message] ||= :existence
10
- super(options)
11
- end
12
-
13
- def validate_each(record, attribute, value)
14
- normalized = attribute.to_s.sub(/_id$/, "").to_sym
15
- association = record.class.reflect_on_association(normalized)
16
-
17
- if association.nil? or !association.belongs_to?
18
- raise ArgumentError, "Cannot validate existence on #{normalized}, not a :belongs_to association"
19
- end
20
-
21
- target_class = nil
22
-
23
- # dealing with polymorphic belongs_to
24
- if association.options.has_key?(:foreign_type)
25
- foreign_type = record.__send__(association.options.fetch(:foreign_type))
26
- target_class = foreign_type.constantize unless foreign_type.nil?
27
- else
28
- target_class = association.klass
29
- end
30
-
31
- if target_class.nil? or !target_class.exists?(value)
32
- record.errors.add(attribute, options[:message], :default => "does not exist")
33
-
34
- # add the error on both :relation and :relation_id
35
- if options[:both]
36
- normalized = attribute.to_s.ends_with?("_id") ? normalized : "#{attribute}_id"
37
- record.errors.add(normalized, options[:message], :default => "does not exist")
38
- end
39
- end
40
- end
41
-
42
- end
43
- end
44
-
45
- module ClassMethods
46
-
47
- def validates_existence_of(*attr_names)
48
- validates_with ExistenceValidator, _merge_attributes(attr_names)
49
- end
50
-
51
- end
52
-
53
- end
1
+ module Perfectline
2
+ module ValidatesExistence
3
+
4
+ module InstanceMethods
5
+ class ExistenceValidator < ActiveModel::EachValidator
6
+
7
+ def initialize(options)
8
+ # set the default message if its unspecified
9
+ options[:message] ||= :existence
10
+ options[:both] ||= true
11
+ super(options)
12
+ end
13
+
14
+ def validate_each(record, attribute, value)
15
+ normalized = attribute.to_s.sub(/_id$/, "").to_sym
16
+ association = record.class.reflect_on_association(normalized)
17
+
18
+ if association.nil? or !association.belongs_to?
19
+ raise ArgumentError, "Cannot validate existence on #{normalized}, not a :belongs_to association"
20
+ end
21
+
22
+ target_class = nil
23
+
24
+ # dealing with polymorphic belongs_to
25
+ if association.options.has_key?(:foreign_type)
26
+ foreign_type = record.__send__(association.options.fetch(:foreign_type))
27
+ target_class = foreign_type.constantize unless foreign_type.nil?
28
+ else
29
+ target_class = association.klass
30
+ end
31
+
32
+ if target_class.nil? or !target_class.exists?(value)
33
+ record.errors.add(attribute, options[:message], :default => "does not exist")
34
+
35
+ # add the error on both :relation and :relation_id
36
+ if options[:both]
37
+ normalized = attribute.to_s.ends_with?("_id") ? normalized : "#{attribute}_id"
38
+ record.errors.add(normalized, options[:message], :default => "does not exist")
39
+ end
40
+ end
41
+ end
42
+
43
+ end
44
+ end
45
+
46
+ module ClassMethods
47
+
48
+ def validates_existence_of(*attr_names)
49
+ validates_with ExistenceValidator, _merge_attributes(attr_names)
50
+ end
51
+
52
+ end
53
+
54
+ end
54
55
  end
@@ -1,11 +1,11 @@
1
- if Rails::VERSION::MAJOR >= 3
2
- require "active_model"
3
- require "rails3/validator"
4
-
5
- ActiveModel::Validations.__send__(:include, Perfectline::ValidatesExistence::InstanceMethods)
6
- ActiveModel::Validations.__send__(:extend, Perfectline::ValidatesExistence::ClassMethods)
7
- else
8
- require "rails2/validator"
9
-
10
- ActiveRecord::Base.__send__(:extend, Perfectline::ValidatesExistence)
1
+ if Rails::VERSION::MAJOR >= 3
2
+ require "active_model"
3
+ require "rails3/validator"
4
+
5
+ ActiveModel::Validations.__send__(:include, Perfectline::ValidatesExistence::InstanceMethods)
6
+ ActiveModel::Validations.__send__(:extend, Perfectline::ValidatesExistence::ClassMethods)
7
+ else
8
+ require "rails2/validator"
9
+
10
+ ActiveRecord::Base.__send__(:extend, Perfectline::ValidatesExistence)
11
11
  end
data/test/models/user.rb CHANGED
@@ -2,6 +2,6 @@ class User < ActiveRecord::Base
2
2
 
3
3
  belongs_to :name
4
4
 
5
- validates_existence_of :name
5
+ validates_existence_of :name, :both => false
6
6
 
7
7
  end
@@ -0,0 +1,7 @@
1
+ class UserWithBoth < ActiveRecord::Base
2
+ self.table_name = "users"
3
+
4
+ belongs_to :name
5
+
6
+ validates_existence_of :name, :both => false
7
+ end
@@ -0,0 +1,7 @@
1
+ class UserWithHasMany < ActiveRecord::Base
2
+ self.table_name = "users"
3
+
4
+ has_many :names
5
+
6
+ validates_existence_of :names
7
+ end
data/test/test_helper.rb CHANGED
@@ -9,7 +9,7 @@ require 'active_record/base'
9
9
 
10
10
  ActiveRecord::Migration.verbose = false
11
11
  ActiveRecord::Base.establish_connection(
12
- "adapter" => "sqlite3",
12
+ "adapter" => "sqlite3",
13
13
  "database" => ":memory:"
14
14
  )
15
15
 
@@ -19,4 +19,6 @@ autoload :Name, File.join(File.dirname(__FILE__), 'models', 'nam
19
19
  autoload :User, File.join(File.dirname(__FILE__), 'models', 'user.rb')
20
20
  autoload :UserWithAllowNil, File.join(File.dirname(__FILE__), 'models', 'user_with_allow_nil.rb')
21
21
  autoload :UserWithPoly, File.join(File.dirname(__FILE__), 'models', 'user_with_poly.rb')
22
- autoload :UserWithPolyAllowNil, File.join(File.dirname(__FILE__), 'models', 'user_with_poly_allow_nil.rb')
22
+ autoload :UserWithPolyAllowNil, File.join(File.dirname(__FILE__), 'models', 'user_with_poly_allow_nil.rb')
23
+ autoload :UserWithHasMany, File.join(File.dirname(__FILE__), 'models', 'user_with_has_many.rb')
24
+ autoload :UserWithBoth, File.join(File.dirname(__FILE__), 'models', 'user_with_both.rb')
@@ -23,7 +23,10 @@ class TestValidatesExistence < Test::Unit::TestCase
23
23
  end
24
24
 
25
25
  def test_save_with_no_relation
26
- assert_equal User.new.save, false
26
+ user = User.new
27
+ assert_equal user.save, false
28
+ assert_not_nil user.errors.on(:name)
29
+ assert_not_nil user.errors.on(:name)
27
30
  end
28
31
 
29
32
  def test_save_with_relation
@@ -52,6 +55,19 @@ class TestValidatesExistence < Test::Unit::TestCase
52
55
  assert_equal UserWithPolyAllowNil.new.save, true
53
56
  end
54
57
 
58
+ def test_argument_error
59
+ assert_raise ArgumentError do
60
+ UserWithHasMany.new.save
61
+ end
62
+ end
63
+
64
+ def test_errors_on_one_field
65
+ user = UserWithBoth.new
66
+ user.save
67
+ assert_not_nil user.errors.on(:name)
68
+ assert_nil user.errors.on(:name_id)
69
+ end
70
+
55
71
  end
56
72
 
57
73
 
metadata CHANGED
@@ -4,9 +4,9 @@ version: !ruby/object:Gem::Version
4
4
  prerelease: false
5
5
  segments:
6
6
  - 0
7
- - 4
8
- - 0
9
- version: 0.4.0
7
+ - 5
8
+ - 2
9
+ version: 0.5.2
10
10
  platform: ruby
11
11
  authors:
12
12
  - Tanel Suurhans
@@ -15,7 +15,7 @@ autorequire:
15
15
  bindir: bin
16
16
  cert_chain: []
17
17
 
18
- date: 2010-04-14 00:00:00 +03:00
18
+ date: 2010-04-15 00:00:00 +03:00
19
19
  default_executable:
20
20
  dependencies: []
21
21
 
@@ -70,6 +70,8 @@ test_files:
70
70
  - test/models/name.rb
71
71
  - test/models/user.rb
72
72
  - test/models/user_with_allow_nil.rb
73
+ - test/models/user_with_both.rb
74
+ - test/models/user_with_has_many.rb
73
75
  - test/models/user_with_poly.rb
74
76
  - test/models/user_with_poly_allow_nil.rb
75
77
  - test/test_helper.rb