shuber-validates_existence 1.0.0

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