shuber-validates_existence 1.0.0
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/CHANGELOG +8 -0
- data/MIT-LICENSE +20 -0
- data/README.markdown +21 -0
- data/Rakefile +22 -0
- data/init.rb +1 -0
- data/lib/validates_existence.rb +46 -0
- data/shoulda_macros/validates_existence.rb +29 -0
- data/test/helpers/table_test_helper.rb +49 -0
- data/test/init.rb +22 -0
- data/test/validates_existence_test.rb +164 -0
- metadata +61 -0
data/CHANGELOG
ADDED
@@ -0,0 +1,8 @@
|
|
1
|
+
2009-01-17 - Sean Huber (shuber@huberry.com)
|
2
|
+
* Add shoulda_macros
|
3
|
+
* Update shoulda_macros
|
4
|
+
* Add gemspec
|
5
|
+
|
6
|
+
2008-08-18 - Sean Huber (shuber@huberry.com)
|
7
|
+
* Added tests
|
8
|
+
* Removed evaluate_condition calls and used validates_each like syntax (could't just use validates_each because we needed to overwrite the :allow_nil and :allow_blank logic to check if the foreign_key was nil/blank, NOT the association)
|
data/MIT-LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2007-2008 Josh Susser (http://www.hasmanythrough.com)
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.markdown
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
# ValidatesExistence
|
2
|
+
|
3
|
+
This plugin adds a new `validates_existence_of` method to `ActiveRecord::Base`.
|
4
|
+
|
5
|
+
The `validates_existence_of` validator checks that a foreign key in a `belongs_to`
|
6
|
+
association points to an existing record. If `:allow_nil => true`, then the key
|
7
|
+
itself may be nil. A non-nil key requires that the foreign object must exist.
|
8
|
+
Works with polymorphic `belongs_to`.
|
9
|
+
|
10
|
+
The default error message is "does not exist".
|
11
|
+
|
12
|
+
## Example
|
13
|
+
|
14
|
+
class Person < ActiveRecord::Base
|
15
|
+
belongs_to :address
|
16
|
+
validates_existence_of :address
|
17
|
+
end
|
18
|
+
|
19
|
+
Note that this validation performs a query to see if the record in question exists.
|
20
|
+
|
21
|
+
*Copyright (c) 2007-2008 Josh Susser. Released under the MIT license.*
|
data/Rakefile
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
require 'rake'
|
2
|
+
require 'rake/testtask'
|
3
|
+
require 'rake/rdoctask'
|
4
|
+
|
5
|
+
desc 'Default: run unit tests.'
|
6
|
+
task :default => :test
|
7
|
+
|
8
|
+
desc 'Test the validates_existence plugin.'
|
9
|
+
Rake::TestTask.new(:test) do |t|
|
10
|
+
t.libs << 'lib'
|
11
|
+
t.pattern = 'test/**/*_test.rb'
|
12
|
+
t.verbose = true
|
13
|
+
end
|
14
|
+
|
15
|
+
desc 'Generate documentation for the validates_existence plugin.'
|
16
|
+
Rake::RDocTask.new(:rdoc) do |rdoc|
|
17
|
+
rdoc.rdoc_dir = 'rdoc'
|
18
|
+
rdoc.title = 'ValidatesExistence'
|
19
|
+
rdoc.options << '--line-numbers' << '--inline-source'
|
20
|
+
rdoc.rdoc_files.include('README')
|
21
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
22
|
+
end
|
data/init.rb
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require 'validates_existence'
|
@@ -0,0 +1,46 @@
|
|
1
|
+
module ActiveRecord
|
2
|
+
module Validations
|
3
|
+
|
4
|
+
def self.included(base)
|
5
|
+
base.extend ClassMethods
|
6
|
+
end
|
7
|
+
|
8
|
+
module ClassMethods
|
9
|
+
|
10
|
+
# The validates_existence_of validator checks that a foreign key in a belongs_to
|
11
|
+
# association points to an exisiting record. If :allow_nil => true, then the key
|
12
|
+
# itself may be nil. A non-nil key requires that the foreign object must exist.
|
13
|
+
# Works with polymorphic belongs_to.
|
14
|
+
def validates_existence_of(*attr_names)
|
15
|
+
configuration = { :message => "does not exist", :on => :save }
|
16
|
+
configuration.update(attr_names.pop) if attr_names.last.is_a?(Hash)
|
17
|
+
|
18
|
+
send(validation_method(configuration[:on]), configuration) do |record|
|
19
|
+
attr_names.each do |attr_name|
|
20
|
+
attr_name = attr_name.to_s.sub(/_id$/, '').to_sym
|
21
|
+
unless (assoc = reflect_on_association(attr_name)) && assoc.macro == :belongs_to
|
22
|
+
raise ArgumentError, "Cannot validate existence of :#{attr_name} because it is not a belongs_to association."
|
23
|
+
end
|
24
|
+
fk_value = record.send assoc.primary_key_name.to_sym
|
25
|
+
unless fk_value.nil? && configuration[:allow_nil] || fk_value.blank? && configuration[:allow_blank]
|
26
|
+
if (foreign_type = assoc.options[:foreign_type]) # polymorphic
|
27
|
+
foreign_type_value = record[assoc.options[:foreign_type]]
|
28
|
+
if !foreign_type_value.blank?
|
29
|
+
assoc_class = foreign_type_value.constantize
|
30
|
+
else
|
31
|
+
record.errors.add(attr_name, configuration[:message])
|
32
|
+
next
|
33
|
+
end
|
34
|
+
else # not polymorphic
|
35
|
+
assoc_class = assoc.klass
|
36
|
+
end
|
37
|
+
record.errors.add(attr_name, configuration[:message]) unless assoc_class && assoc_class.exists?(fk_value)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
end # ClassMethods
|
44
|
+
|
45
|
+
end
|
46
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
class Test::Unit::TestCase
|
2
|
+
|
3
|
+
def self.should_require_existence_of(*attributes)
|
4
|
+
options = attributes.extract_options!
|
5
|
+
klass = model_class
|
6
|
+
|
7
|
+
attributes.each do |attribute|
|
8
|
+
should "require #{attribute} exists" do
|
9
|
+
object = get_instance_of(klass)
|
10
|
+
object.send("#{attribute}_id=", 0)
|
11
|
+
assert !object.valid?, "#{object.class} was saved with a non-existent #{attribute}"
|
12
|
+
assert object.errors.on(attribute), "There are no errors on #{attribute} after being set to a non-existent record"
|
13
|
+
assert_contains(object.errors.on(attribute), 'does not exist', "when set to 0")
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
if options[:allow_nil]
|
18
|
+
attributes.each do |attribute|
|
19
|
+
should "allow #{attribute} to be nil" do
|
20
|
+
object = get_instance_of(klass)
|
21
|
+
object.send("#{attribute}_id=", nil)
|
22
|
+
object.valid?
|
23
|
+
assert !object.errors.on(attribute), "There were errors on #{attribute} after being set to nil"
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
module TableTestHelper
|
2
|
+
|
3
|
+
def create_all_tables
|
4
|
+
create_blogs_table
|
5
|
+
create_posts_table
|
6
|
+
create_comments_table
|
7
|
+
end
|
8
|
+
|
9
|
+
def create_blogs_table
|
10
|
+
silence_stream(STDOUT) do
|
11
|
+
ActiveRecord::Schema.define(:version => 1) do
|
12
|
+
create_table :blogs do |t|
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
def create_posts_table
|
19
|
+
silence_stream(STDOUT) do
|
20
|
+
ActiveRecord::Schema.define(:version => 1) do
|
21
|
+
create_table :posts do |t|
|
22
|
+
t.integer :blog_id
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def create_comments_table
|
29
|
+
silence_stream(STDOUT) do
|
30
|
+
ActiveRecord::Schema.define(:version => 1) do
|
31
|
+
create_table :comments do |t|
|
32
|
+
t.integer :commentable_id
|
33
|
+
t.string :commentable_type
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
def drop_all_tables
|
40
|
+
ActiveRecord::Base.connection.tables.each do |table|
|
41
|
+
drop_table(table)
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
def drop_table(table)
|
46
|
+
ActiveRecord::Base.connection.drop_table(table)
|
47
|
+
end
|
48
|
+
|
49
|
+
end
|
data/test/init.rb
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
# $:.reject! { |path| path.include? 'TextMate' }
|
2
|
+
require 'test/unit'
|
3
|
+
|
4
|
+
# Require and include test helpers
|
5
|
+
#
|
6
|
+
Dir[File.join(File.dirname(__FILE__), 'helpers', '*_test_helper.rb')].each do |helper|
|
7
|
+
require helper
|
8
|
+
/(.*?)_test_helper\.rb/.match File.basename(helper)
|
9
|
+
class_name = $1.split('_').collect{ |name| name.downcase.capitalize }.join('') + 'TestHelper'
|
10
|
+
Test::Unit::TestCase.send :include, Object.const_get(class_name) if Object.const_defined?(class_name)
|
11
|
+
end
|
12
|
+
|
13
|
+
# Load ActiveRecord
|
14
|
+
#
|
15
|
+
require 'rubygems'
|
16
|
+
gem 'activerecord'
|
17
|
+
require 'active_record'
|
18
|
+
ActiveRecord::Base.establish_connection :adapter => 'sqlite3', :dbfile => ':memory:'
|
19
|
+
|
20
|
+
# Require the main init.rb for the plugin
|
21
|
+
#
|
22
|
+
require File.join(File.dirname(File.dirname(__FILE__)), 'init')
|
@@ -0,0 +1,164 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/init'
|
2
|
+
|
3
|
+
|
4
|
+
# Blog
|
5
|
+
|
6
|
+
class Blog < ActiveRecord::Base
|
7
|
+
has_many :posts
|
8
|
+
end
|
9
|
+
|
10
|
+
# Post
|
11
|
+
|
12
|
+
class Post < ActiveRecord::Base
|
13
|
+
belongs_to :blog
|
14
|
+
has_many :comments, :as => :commentable
|
15
|
+
end
|
16
|
+
|
17
|
+
class PostWithRequiredBlog < Post
|
18
|
+
validates_existence_of :blog
|
19
|
+
end
|
20
|
+
|
21
|
+
class PostWithoutRequiredBlog < Post
|
22
|
+
validates_existence_of :blog, :allow_nil => true
|
23
|
+
end
|
24
|
+
|
25
|
+
class PostWithRequiredBlogIf < Post
|
26
|
+
validates_existence_of :blog, :if => :condition
|
27
|
+
attr_accessor :condition
|
28
|
+
end
|
29
|
+
|
30
|
+
class PostWithRequiredBlogUnless < Post
|
31
|
+
validates_existence_of :blog, :unless => :condition
|
32
|
+
attr_accessor :condition
|
33
|
+
end
|
34
|
+
|
35
|
+
# Comment
|
36
|
+
|
37
|
+
class Comment < ActiveRecord::Base
|
38
|
+
belongs_to :commentable, :polymorphic => true
|
39
|
+
end
|
40
|
+
|
41
|
+
class CommentWithRequiredCommentable < Comment
|
42
|
+
validates_existence_of :commentable
|
43
|
+
end
|
44
|
+
|
45
|
+
class CommentWithoutRequiredCommentable < Comment
|
46
|
+
validates_existence_of :commentable, :allow_nil => true
|
47
|
+
end
|
48
|
+
|
49
|
+
|
50
|
+
class ValidatesExistenceTest < Test::Unit::TestCase
|
51
|
+
|
52
|
+
def setup
|
53
|
+
create_all_tables
|
54
|
+
@default_blog = Blog.create
|
55
|
+
@default_post = PostWithoutRequiredBlog.create
|
56
|
+
end
|
57
|
+
|
58
|
+
def teardown
|
59
|
+
drop_all_tables
|
60
|
+
end
|
61
|
+
|
62
|
+
# PostWithRequiredBlog
|
63
|
+
|
64
|
+
def test_should_create_post_with_required_blog_with_valid_blog
|
65
|
+
@post = PostWithRequiredBlog.new :blog_id => @default_blog.id
|
66
|
+
assert @post.save
|
67
|
+
end
|
68
|
+
|
69
|
+
def test_should_not_create_post_with_required_blog_when_blog_is_nil
|
70
|
+
@post = PostWithRequiredBlog.new
|
71
|
+
assert !@post.save
|
72
|
+
assert @post.errors.on(:blog)
|
73
|
+
end
|
74
|
+
|
75
|
+
def test_should_not_create_post_with_required_blog_when_blog_does_not_exist
|
76
|
+
@post = PostWithRequiredBlog.new :blog_id => '2'
|
77
|
+
assert !@post.save
|
78
|
+
assert @post.errors.on(:blog)
|
79
|
+
end
|
80
|
+
|
81
|
+
# PostWithoutRequiredBlog
|
82
|
+
|
83
|
+
def test_should_create_post_without_required_blog_with_valid_blog
|
84
|
+
@post = PostWithoutRequiredBlog.new :blog_id => @default_blog.id
|
85
|
+
assert @post.save
|
86
|
+
end
|
87
|
+
|
88
|
+
def test_should_create_post_without_required_blog_when_blog_is_nil
|
89
|
+
@post = PostWithoutRequiredBlog.new
|
90
|
+
assert @post.save
|
91
|
+
end
|
92
|
+
|
93
|
+
def test_should_not_create_post_without_required_blog_when_blog_does_not_exist
|
94
|
+
@post = PostWithoutRequiredBlog.new :blog_id => '2'
|
95
|
+
assert !@post.save
|
96
|
+
assert @post.errors.on(:blog)
|
97
|
+
end
|
98
|
+
|
99
|
+
# Polymorphic CommentWithRequiredCommentable
|
100
|
+
|
101
|
+
def test_should_create_comment_with_required_commentable_with_valid_commentable
|
102
|
+
@comment = CommentWithRequiredCommentable.new :commentable_id => @default_post.id, :commentable_type => 'Post'
|
103
|
+
assert @comment.save
|
104
|
+
end
|
105
|
+
|
106
|
+
def test_should_not_create_comment_with_required_commentable_when_commentable_is_nil
|
107
|
+
@comment = CommentWithRequiredCommentable.new
|
108
|
+
assert !@comment.save
|
109
|
+
assert @comment.errors.on(:commentable)
|
110
|
+
end
|
111
|
+
|
112
|
+
def test_should_not_create_comment_with_required_commentable_when_commentable_does_not_exist
|
113
|
+
@comment = CommentWithRequiredCommentable.new :commentable_id => '2', :commentable_type => 'Post'
|
114
|
+
assert !@comment.save
|
115
|
+
assert @comment.errors.on(:commentable)
|
116
|
+
end
|
117
|
+
|
118
|
+
# Polymorphic CommentWithoutRequiredCommentable
|
119
|
+
|
120
|
+
def test_should_create_comment_without_required_commentable_with_valid_commentable
|
121
|
+
@comment = CommentWithoutRequiredCommentable.new :commentable_id => @default_post.id, :commentable_type => 'Post'
|
122
|
+
assert @comment.save
|
123
|
+
end
|
124
|
+
|
125
|
+
def test_should_create_comment_without_required_commentable_when_commentable_is_nil
|
126
|
+
@comment = CommentWithoutRequiredCommentable.new
|
127
|
+
assert @comment.save
|
128
|
+
end
|
129
|
+
|
130
|
+
def test_should_not_create_comment_without_required_commentable_when_commentable_does_not_exist
|
131
|
+
@comment = CommentWithoutRequiredCommentable.new :commentable_id => '2', :commentable_type => 'Post'
|
132
|
+
assert !@comment.save
|
133
|
+
assert @comment.errors.on(:commentable)
|
134
|
+
end
|
135
|
+
|
136
|
+
# PostWithRequiredBlogIf (:if => :condition)
|
137
|
+
|
138
|
+
def test_post_should_require_blog_when_if_condition_is_true
|
139
|
+
@post = PostWithRequiredBlogIf.new
|
140
|
+
@post.condition = true
|
141
|
+
assert !@post.save
|
142
|
+
end
|
143
|
+
|
144
|
+
def test_post_should_not_require_blog_when_if_condition_is_false
|
145
|
+
@post = PostWithRequiredBlogIf.new
|
146
|
+
@post.condition = false
|
147
|
+
assert @post.save
|
148
|
+
end
|
149
|
+
|
150
|
+
# PostWithRequiredBlogUnless (:unless => :condition)
|
151
|
+
|
152
|
+
def test_post_should_require_blog_when_unless_condition_is_false
|
153
|
+
@post = PostWithRequiredBlogUnless.new
|
154
|
+
@post.condition = false
|
155
|
+
assert !@post.save
|
156
|
+
end
|
157
|
+
|
158
|
+
def test_post_should_not_require_blog_when_unless_condition_is_true
|
159
|
+
@post = PostWithRequiredBlogUnless.new
|
160
|
+
@post.condition = true
|
161
|
+
assert @post.save
|
162
|
+
end
|
163
|
+
|
164
|
+
end
|
metadata
ADDED
@@ -0,0 +1,61 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: shuber-validates_existence
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.0.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Josh Susser
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
|
12
|
+
date: 2009-01-17 00:00:00 -08:00
|
13
|
+
default_executable:
|
14
|
+
dependencies: []
|
15
|
+
|
16
|
+
description: Provides a validates_existence_of method for ActiveRecord models to check existence of records referenced by belongs_to associations
|
17
|
+
email:
|
18
|
+
executables: []
|
19
|
+
|
20
|
+
extensions: []
|
21
|
+
|
22
|
+
extra_rdoc_files: []
|
23
|
+
|
24
|
+
files:
|
25
|
+
- CHANGELOG
|
26
|
+
- init.rb
|
27
|
+
- lib/validates_existence.rb
|
28
|
+
- MIT-LICENSE
|
29
|
+
- Rakefile
|
30
|
+
- README.markdown
|
31
|
+
- shoulda_macros/validates_existence.rb
|
32
|
+
- test/helpers/table_test_helper.rb
|
33
|
+
- test/init.rb
|
34
|
+
has_rdoc: false
|
35
|
+
homepage: http://github.com/shuber/validates_existence
|
36
|
+
post_install_message:
|
37
|
+
rdoc_options: []
|
38
|
+
|
39
|
+
require_paths:
|
40
|
+
- lib
|
41
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
42
|
+
requirements:
|
43
|
+
- - ">="
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
version: "0"
|
46
|
+
version:
|
47
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
48
|
+
requirements:
|
49
|
+
- - ">="
|
50
|
+
- !ruby/object:Gem::Version
|
51
|
+
version: "0"
|
52
|
+
version:
|
53
|
+
requirements: []
|
54
|
+
|
55
|
+
rubyforge_project:
|
56
|
+
rubygems_version: 1.2.0
|
57
|
+
signing_key:
|
58
|
+
specification_version: 2
|
59
|
+
summary: Provides a validates_existence_of method for ActiveRecord models to check existence of records referenced by belongs_to associations
|
60
|
+
test_files:
|
61
|
+
- test/validates_existence_test.rb
|