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.
@@ -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)
@@ -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.
@@ -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.*
@@ -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
@@ -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