validates_existence 0.4.0 → 0.5.2

Sign up to get free protection for your applications and to get access to all the features.
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