bellmyer-validates_blacklist 0.1.1
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 +148 -0
- data/lib/active_record/validates/blacklist.rb +27 -0
- data/lib/bellmyer-validates_blacklist.rb +2 -0
- data/test/blacklist_test.rb +332 -0
- data/validates_blacklist.gemspec +28 -0
- metadata +67 -0
data/README
ADDED
@@ -0,0 +1,148 @@
|
|
1
|
+
validates_blacklist
|
2
|
+
===================
|
3
|
+
|
4
|
+
The ridiculously paranoid don't want anything getting past them. Wouldn't you
|
5
|
+
feel the same if everyone was out to get you? How do you know they're not?
|
6
|
+
|
7
|
+
When it comes to validations, paranoia is pricey. You need a tool to simplify
|
8
|
+
the process. Time is of the essence, and those aluminum foil hats aren't going to
|
9
|
+
fashion themselves.
|
10
|
+
|
11
|
+
In all seriousness, validations are great for general rules that describe what type
|
12
|
+
of data is or isn't acceptable. What they're not good for is muddying up your
|
13
|
+
model with lists, possibly large lists, of specifically blacklisted data.
|
14
|
+
|
15
|
+
You may not want chunkeymonkey47@aol.com joining your online forum because you know
|
16
|
+
they're just going to spam your users with viagra ads. Maybe there are dozens of
|
17
|
+
chunkymonkeys out there, as it were, and that sort of config data is just
|
18
|
+
hideous in your model, if you care anything about beautiful code. I say one
|
19
|
+
chunkymonkey is too much.
|
20
|
+
|
21
|
+
|
22
|
+
What can be done?
|
23
|
+
=================
|
24
|
+
|
25
|
+
What if we create a list *outside* the model, that can be validated against? What
|
26
|
+
if we gave each model its own blacklist file in the config folder so you knew
|
27
|
+
exactly where to find them? Maybe a yaml file would make it easy to blacklist at
|
28
|
+
the attribute level. And what if I wrote a nify little mixin for you, so calling
|
29
|
+
"validates_blacklist" inside a model would automatically read this list and handle
|
30
|
+
the validation for you?
|
31
|
+
|
32
|
+
Well, I'd be a swell guy. And as it turns out, I kind of am.
|
33
|
+
|
34
|
+
|
35
|
+
Installation
|
36
|
+
============
|
37
|
+
|
38
|
+
Stick this little line in your environment.rb:
|
39
|
+
|
40
|
+
config.gem 'bellmyer-validates_blacklist', :lib => 'validates_blacklist', :source => 'http://gems.github.com'
|
41
|
+
|
42
|
+
Then, for fun, run these two rake tasks:
|
43
|
+
|
44
|
+
rake gems:install
|
45
|
+
rake gems:unpack
|
46
|
+
|
47
|
+
|
48
|
+
Usage
|
49
|
+
=====
|
50
|
+
|
51
|
+
Run this command to create blacklist files for all your models in the config/blacklists/ folder:
|
52
|
+
|
53
|
+
script/generate blacklists
|
54
|
+
|
55
|
+
Don't worry, it won't overwrite your existing blacklist files, only create the ones
|
56
|
+
you're missing. This means you can run it after every new model is added, no worries.
|
57
|
+
|
58
|
+
Now, call this in your models:
|
59
|
+
|
60
|
+
validates_blacklist
|
61
|
+
|
62
|
+
And populate the yaml files using the example below to guide you. Have fun!
|
63
|
+
|
64
|
+
|
65
|
+
Example
|
66
|
+
=======
|
67
|
+
|
68
|
+
As an example, we'll imagine a high school girl named Heather. Although she has
|
69
|
+
mad Ruby skillz (perhaps BECAUSE) she's a snob. All her potential friends must
|
70
|
+
submit applications for friendship via her Rails website. She uses
|
71
|
+
validates_blacklist to weed out the "undesireables".
|
72
|
+
|
73
|
+
# config/blacklists/user_blacklist.yml
|
74
|
+
email:
|
75
|
+
- greasy_pete@yahoo.com # We kissed once when we were 5. Get over it already.
|
76
|
+
- /@aol.com$/ # Like, yeah right, AOL is for losers!
|
77
|
+
|
78
|
+
age:
|
79
|
+
- <14 # Junior high? Need not apply.
|
80
|
+
- >25 # Gross, you perv!
|
81
|
+
|
82
|
+
parents_salary:
|
83
|
+
- 50_000..150_000 # Poor kids are gullible. Rich kids have money. Middle class is so passe.
|
84
|
+
|
85
|
+
# app/models/user.rb
|
86
|
+
class User < ActiveRecord::Base
|
87
|
+
validates_blacklist
|
88
|
+
end
|
89
|
+
|
90
|
+
|
91
|
+
Explanation
|
92
|
+
===========
|
93
|
+
|
94
|
+
Basically, under each attribute (email, age, parents_salary, etc) you can list
|
95
|
+
as many blacklisted values as you like. They can be a simple strings:
|
96
|
+
|
97
|
+
greasy_pete@aol.com
|
98
|
+
|
99
|
+
or regular expressions, if you wrap them in forward slashes:
|
100
|
+
|
101
|
+
/aol.com$/
|
102
|
+
|
103
|
+
or numbers (not very exciting):
|
104
|
+
|
105
|
+
5
|
106
|
+
|
107
|
+
or ranges of numbers:
|
108
|
+
|
109
|
+
5..15
|
110
|
+
|
111
|
+
or any other conditionals you can think of:
|
112
|
+
|
113
|
+
!= 'sadness'
|
114
|
+
=~ /happiness/
|
115
|
+
!~ /sad/
|
116
|
+
> 12
|
117
|
+
< 99
|
118
|
+
|
119
|
+
The only limits are your imagination, and my forethought. You can even specify
|
120
|
+
the error message that is generated:
|
121
|
+
|
122
|
+
email:
|
123
|
+
- [greasy_pete@aol.com, cannot be greasy pete from biology]
|
124
|
+
|
125
|
+
age:
|
126
|
+
- [>25, cannot be a pervert]
|
127
|
+
|
128
|
+
parents_salary
|
129
|
+
- [50_000..150_000, cannot be middle class]
|
130
|
+
|
131
|
+
Otherwise, the user will receive a generic message like:
|
132
|
+
|
133
|
+
Email is not allowed
|
134
|
+
|
135
|
+
Of course, you can change that for an entire model with the mixin call:
|
136
|
+
|
137
|
+
validates_blacklist :message => 'is not valid'
|
138
|
+
|
139
|
+
or per attribute:
|
140
|
+
|
141
|
+
validates_blacklist :message => "is not valid',
|
142
|
+
:attributes => { :email => 'has been banned', :age => 'is not allowed' }
|
143
|
+
|
144
|
+
For the record, I think even a 21 year old hitting on high school girls is a
|
145
|
+
pervert, but I'm trying to approach this thing from Heather's point of view.
|
146
|
+
|
147
|
+
|
148
|
+
Copyright (c) 2009 Jaime Bellmyer, released under the MIT license
|
@@ -0,0 +1,27 @@
|
|
1
|
+
module ActiveRecord
|
2
|
+
module Validates #:nodoc:
|
3
|
+
module Blacklist #:nodoc:
|
4
|
+
def self.included(base)
|
5
|
+
base.extend(ClassMethods)
|
6
|
+
end
|
7
|
+
|
8
|
+
module ClassMethods
|
9
|
+
validates_blacklist(options = {})
|
10
|
+
options.reverse_merge!(:message => 'is not allowed')
|
11
|
+
|
12
|
+
include ActiveRecord::Validates::Blacklist::InstanceMethods
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
module InstanceMethods
|
17
|
+
def blacklist(attribute, value, message = nil)
|
18
|
+
puts "blacklisted!"
|
19
|
+
end
|
20
|
+
|
21
|
+
def unblacklist(attribute, value)
|
22
|
+
puts "unblacklisted!"
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,332 @@
|
|
1
|
+
require 'test/unit'
|
2
|
+
|
3
|
+
require 'rubygems'
|
4
|
+
gem 'activerecord', '>= 1.15.4.7794'
|
5
|
+
require 'active_record'
|
6
|
+
|
7
|
+
require "#{File.dirname(__FILE__)}/../init"
|
8
|
+
|
9
|
+
ActiveRecord::Base.establish_connection(:adapter => "sqlite3", :dbfile => ":memory:")
|
10
|
+
|
11
|
+
def setup_db
|
12
|
+
ActiveRecord::Schema.define(:version => 1) do
|
13
|
+
create_table :mixins do |t|
|
14
|
+
t.column :pos, :integer
|
15
|
+
t.column :parent_id, :integer
|
16
|
+
t.column :created_at, :datetime
|
17
|
+
t.column :updated_at, :datetime
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
def teardown_db
|
23
|
+
ActiveRecord::Base.connection.tables.each do |table|
|
24
|
+
ActiveRecord::Base.connection.drop_table(table)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
class Mixin < ActiveRecord::Base
|
29
|
+
end
|
30
|
+
|
31
|
+
class ListMixin < Mixin
|
32
|
+
acts_as_list :column => "pos", :scope => :parent
|
33
|
+
|
34
|
+
def self.table_name() "mixins" end
|
35
|
+
end
|
36
|
+
|
37
|
+
class ListMixinSub1 < ListMixin
|
38
|
+
end
|
39
|
+
|
40
|
+
class ListMixinSub2 < ListMixin
|
41
|
+
end
|
42
|
+
|
43
|
+
class ListWithStringScopeMixin < ActiveRecord::Base
|
44
|
+
acts_as_list :column => "pos", :scope => 'parent_id = #{parent_id}'
|
45
|
+
|
46
|
+
def self.table_name() "mixins" end
|
47
|
+
end
|
48
|
+
|
49
|
+
|
50
|
+
class ListTest < Test::Unit::TestCase
|
51
|
+
|
52
|
+
def setup
|
53
|
+
setup_db
|
54
|
+
(1..4).each { |counter| ListMixin.create! :pos => counter, :parent_id => 5 }
|
55
|
+
end
|
56
|
+
|
57
|
+
def teardown
|
58
|
+
teardown_db
|
59
|
+
end
|
60
|
+
|
61
|
+
def test_reordering
|
62
|
+
assert_equal [1, 2, 3, 4], ListMixin.find(:all, :conditions => 'parent_id = 5', :order => 'pos').map(&:id)
|
63
|
+
|
64
|
+
ListMixin.find(2).move_lower
|
65
|
+
assert_equal [1, 3, 2, 4], ListMixin.find(:all, :conditions => 'parent_id = 5', :order => 'pos').map(&:id)
|
66
|
+
|
67
|
+
ListMixin.find(2).move_higher
|
68
|
+
assert_equal [1, 2, 3, 4], ListMixin.find(:all, :conditions => 'parent_id = 5', :order => 'pos').map(&:id)
|
69
|
+
|
70
|
+
ListMixin.find(1).move_to_bottom
|
71
|
+
assert_equal [2, 3, 4, 1], ListMixin.find(:all, :conditions => 'parent_id = 5', :order => 'pos').map(&:id)
|
72
|
+
|
73
|
+
ListMixin.find(1).move_to_top
|
74
|
+
assert_equal [1, 2, 3, 4], ListMixin.find(:all, :conditions => 'parent_id = 5', :order => 'pos').map(&:id)
|
75
|
+
|
76
|
+
ListMixin.find(2).move_to_bottom
|
77
|
+
assert_equal [1, 3, 4, 2], ListMixin.find(:all, :conditions => 'parent_id = 5', :order => 'pos').map(&:id)
|
78
|
+
|
79
|
+
ListMixin.find(4).move_to_top
|
80
|
+
assert_equal [4, 1, 3, 2], ListMixin.find(:all, :conditions => 'parent_id = 5', :order => 'pos').map(&:id)
|
81
|
+
end
|
82
|
+
|
83
|
+
def test_move_to_bottom_with_next_to_last_item
|
84
|
+
assert_equal [1, 2, 3, 4], ListMixin.find(:all, :conditions => 'parent_id = 5', :order => 'pos').map(&:id)
|
85
|
+
ListMixin.find(3).move_to_bottom
|
86
|
+
assert_equal [1, 2, 4, 3], ListMixin.find(:all, :conditions => 'parent_id = 5', :order => 'pos').map(&:id)
|
87
|
+
end
|
88
|
+
|
89
|
+
def test_next_prev
|
90
|
+
assert_equal ListMixin.find(2), ListMixin.find(1).lower_item
|
91
|
+
assert_nil ListMixin.find(1).higher_item
|
92
|
+
assert_equal ListMixin.find(3), ListMixin.find(4).higher_item
|
93
|
+
assert_nil ListMixin.find(4).lower_item
|
94
|
+
end
|
95
|
+
|
96
|
+
def test_injection
|
97
|
+
item = ListMixin.new(:parent_id => 1)
|
98
|
+
assert_equal "parent_id = 1", item.scope_condition
|
99
|
+
assert_equal "pos", item.position_column
|
100
|
+
end
|
101
|
+
|
102
|
+
def test_insert
|
103
|
+
new = ListMixin.create(:parent_id => 20)
|
104
|
+
assert_equal 1, new.pos
|
105
|
+
assert new.first?
|
106
|
+
assert new.last?
|
107
|
+
|
108
|
+
new = ListMixin.create(:parent_id => 20)
|
109
|
+
assert_equal 2, new.pos
|
110
|
+
assert !new.first?
|
111
|
+
assert new.last?
|
112
|
+
|
113
|
+
new = ListMixin.create(:parent_id => 20)
|
114
|
+
assert_equal 3, new.pos
|
115
|
+
assert !new.first?
|
116
|
+
assert new.last?
|
117
|
+
|
118
|
+
new = ListMixin.create(:parent_id => 0)
|
119
|
+
assert_equal 1, new.pos
|
120
|
+
assert new.first?
|
121
|
+
assert new.last?
|
122
|
+
end
|
123
|
+
|
124
|
+
def test_insert_at
|
125
|
+
new = ListMixin.create(:parent_id => 20)
|
126
|
+
assert_equal 1, new.pos
|
127
|
+
|
128
|
+
new = ListMixin.create(:parent_id => 20)
|
129
|
+
assert_equal 2, new.pos
|
130
|
+
|
131
|
+
new = ListMixin.create(:parent_id => 20)
|
132
|
+
assert_equal 3, new.pos
|
133
|
+
|
134
|
+
new4 = ListMixin.create(:parent_id => 20)
|
135
|
+
assert_equal 4, new4.pos
|
136
|
+
|
137
|
+
new4.insert_at(3)
|
138
|
+
assert_equal 3, new4.pos
|
139
|
+
|
140
|
+
new.reload
|
141
|
+
assert_equal 4, new.pos
|
142
|
+
|
143
|
+
new.insert_at(2)
|
144
|
+
assert_equal 2, new.pos
|
145
|
+
|
146
|
+
new4.reload
|
147
|
+
assert_equal 4, new4.pos
|
148
|
+
|
149
|
+
new5 = ListMixin.create(:parent_id => 20)
|
150
|
+
assert_equal 5, new5.pos
|
151
|
+
|
152
|
+
new5.insert_at(1)
|
153
|
+
assert_equal 1, new5.pos
|
154
|
+
|
155
|
+
new4.reload
|
156
|
+
assert_equal 5, new4.pos
|
157
|
+
end
|
158
|
+
|
159
|
+
def test_delete_middle
|
160
|
+
assert_equal [1, 2, 3, 4], ListMixin.find(:all, :conditions => 'parent_id = 5', :order => 'pos').map(&:id)
|
161
|
+
|
162
|
+
ListMixin.find(2).destroy
|
163
|
+
|
164
|
+
assert_equal [1, 3, 4], ListMixin.find(:all, :conditions => 'parent_id = 5', :order => 'pos').map(&:id)
|
165
|
+
|
166
|
+
assert_equal 1, ListMixin.find(1).pos
|
167
|
+
assert_equal 2, ListMixin.find(3).pos
|
168
|
+
assert_equal 3, ListMixin.find(4).pos
|
169
|
+
|
170
|
+
ListMixin.find(1).destroy
|
171
|
+
|
172
|
+
assert_equal [3, 4], ListMixin.find(:all, :conditions => 'parent_id = 5', :order => 'pos').map(&:id)
|
173
|
+
|
174
|
+
assert_equal 1, ListMixin.find(3).pos
|
175
|
+
assert_equal 2, ListMixin.find(4).pos
|
176
|
+
end
|
177
|
+
|
178
|
+
def test_with_string_based_scope
|
179
|
+
new = ListWithStringScopeMixin.create(:parent_id => 500)
|
180
|
+
assert_equal 1, new.pos
|
181
|
+
assert new.first?
|
182
|
+
assert new.last?
|
183
|
+
end
|
184
|
+
|
185
|
+
def test_nil_scope
|
186
|
+
new1, new2, new3 = ListMixin.create, ListMixin.create, ListMixin.create
|
187
|
+
new2.move_higher
|
188
|
+
assert_equal [new2, new1, new3], ListMixin.find(:all, :conditions => 'parent_id IS NULL', :order => 'pos')
|
189
|
+
end
|
190
|
+
|
191
|
+
|
192
|
+
def test_remove_from_list_should_then_fail_in_list?
|
193
|
+
assert_equal true, ListMixin.find(1).in_list?
|
194
|
+
ListMixin.find(1).remove_from_list
|
195
|
+
assert_equal false, ListMixin.find(1).in_list?
|
196
|
+
end
|
197
|
+
|
198
|
+
def test_remove_from_list_should_set_position_to_nil
|
199
|
+
assert_equal [1, 2, 3, 4], ListMixin.find(:all, :conditions => 'parent_id = 5', :order => 'pos').map(&:id)
|
200
|
+
|
201
|
+
ListMixin.find(2).remove_from_list
|
202
|
+
|
203
|
+
assert_equal [2, 1, 3, 4], ListMixin.find(:all, :conditions => 'parent_id = 5', :order => 'pos').map(&:id)
|
204
|
+
|
205
|
+
assert_equal 1, ListMixin.find(1).pos
|
206
|
+
assert_equal nil, ListMixin.find(2).pos
|
207
|
+
assert_equal 2, ListMixin.find(3).pos
|
208
|
+
assert_equal 3, ListMixin.find(4).pos
|
209
|
+
end
|
210
|
+
|
211
|
+
def test_remove_before_destroy_does_not_shift_lower_items_twice
|
212
|
+
assert_equal [1, 2, 3, 4], ListMixin.find(:all, :conditions => 'parent_id = 5', :order => 'pos').map(&:id)
|
213
|
+
|
214
|
+
ListMixin.find(2).remove_from_list
|
215
|
+
ListMixin.find(2).destroy
|
216
|
+
|
217
|
+
assert_equal [1, 3, 4], ListMixin.find(:all, :conditions => 'parent_id = 5', :order => 'pos').map(&:id)
|
218
|
+
|
219
|
+
assert_equal 1, ListMixin.find(1).pos
|
220
|
+
assert_equal 2, ListMixin.find(3).pos
|
221
|
+
assert_equal 3, ListMixin.find(4).pos
|
222
|
+
end
|
223
|
+
|
224
|
+
end
|
225
|
+
|
226
|
+
class ListSubTest < Test::Unit::TestCase
|
227
|
+
|
228
|
+
def setup
|
229
|
+
setup_db
|
230
|
+
(1..4).each { |i| ((i % 2 == 1) ? ListMixinSub1 : ListMixinSub2).create! :pos => i, :parent_id => 5000 }
|
231
|
+
end
|
232
|
+
|
233
|
+
def teardown
|
234
|
+
teardown_db
|
235
|
+
end
|
236
|
+
|
237
|
+
def test_reordering
|
238
|
+
assert_equal [1, 2, 3, 4], ListMixin.find(:all, :conditions => 'parent_id = 5000', :order => 'pos').map(&:id)
|
239
|
+
|
240
|
+
ListMixin.find(2).move_lower
|
241
|
+
assert_equal [1, 3, 2, 4], ListMixin.find(:all, :conditions => 'parent_id = 5000', :order => 'pos').map(&:id)
|
242
|
+
|
243
|
+
ListMixin.find(2).move_higher
|
244
|
+
assert_equal [1, 2, 3, 4], ListMixin.find(:all, :conditions => 'parent_id = 5000', :order => 'pos').map(&:id)
|
245
|
+
|
246
|
+
ListMixin.find(1).move_to_bottom
|
247
|
+
assert_equal [2, 3, 4, 1], ListMixin.find(:all, :conditions => 'parent_id = 5000', :order => 'pos').map(&:id)
|
248
|
+
|
249
|
+
ListMixin.find(1).move_to_top
|
250
|
+
assert_equal [1, 2, 3, 4], ListMixin.find(:all, :conditions => 'parent_id = 5000', :order => 'pos').map(&:id)
|
251
|
+
|
252
|
+
ListMixin.find(2).move_to_bottom
|
253
|
+
assert_equal [1, 3, 4, 2], ListMixin.find(:all, :conditions => 'parent_id = 5000', :order => 'pos').map(&:id)
|
254
|
+
|
255
|
+
ListMixin.find(4).move_to_top
|
256
|
+
assert_equal [4, 1, 3, 2], ListMixin.find(:all, :conditions => 'parent_id = 5000', :order => 'pos').map(&:id)
|
257
|
+
end
|
258
|
+
|
259
|
+
def test_move_to_bottom_with_next_to_last_item
|
260
|
+
assert_equal [1, 2, 3, 4], ListMixin.find(:all, :conditions => 'parent_id = 5000', :order => 'pos').map(&:id)
|
261
|
+
ListMixin.find(3).move_to_bottom
|
262
|
+
assert_equal [1, 2, 4, 3], ListMixin.find(:all, :conditions => 'parent_id = 5000', :order => 'pos').map(&:id)
|
263
|
+
end
|
264
|
+
|
265
|
+
def test_next_prev
|
266
|
+
assert_equal ListMixin.find(2), ListMixin.find(1).lower_item
|
267
|
+
assert_nil ListMixin.find(1).higher_item
|
268
|
+
assert_equal ListMixin.find(3), ListMixin.find(4).higher_item
|
269
|
+
assert_nil ListMixin.find(4).lower_item
|
270
|
+
end
|
271
|
+
|
272
|
+
def test_injection
|
273
|
+
item = ListMixin.new("parent_id"=>1)
|
274
|
+
assert_equal "parent_id = 1", item.scope_condition
|
275
|
+
assert_equal "pos", item.position_column
|
276
|
+
end
|
277
|
+
|
278
|
+
def test_insert_at
|
279
|
+
new = ListMixin.create("parent_id" => 20)
|
280
|
+
assert_equal 1, new.pos
|
281
|
+
|
282
|
+
new = ListMixinSub1.create("parent_id" => 20)
|
283
|
+
assert_equal 2, new.pos
|
284
|
+
|
285
|
+
new = ListMixinSub2.create("parent_id" => 20)
|
286
|
+
assert_equal 3, new.pos
|
287
|
+
|
288
|
+
new4 = ListMixin.create("parent_id" => 20)
|
289
|
+
assert_equal 4, new4.pos
|
290
|
+
|
291
|
+
new4.insert_at(3)
|
292
|
+
assert_equal 3, new4.pos
|
293
|
+
|
294
|
+
new.reload
|
295
|
+
assert_equal 4, new.pos
|
296
|
+
|
297
|
+
new.insert_at(2)
|
298
|
+
assert_equal 2, new.pos
|
299
|
+
|
300
|
+
new4.reload
|
301
|
+
assert_equal 4, new4.pos
|
302
|
+
|
303
|
+
new5 = ListMixinSub1.create("parent_id" => 20)
|
304
|
+
assert_equal 5, new5.pos
|
305
|
+
|
306
|
+
new5.insert_at(1)
|
307
|
+
assert_equal 1, new5.pos
|
308
|
+
|
309
|
+
new4.reload
|
310
|
+
assert_equal 5, new4.pos
|
311
|
+
end
|
312
|
+
|
313
|
+
def test_delete_middle
|
314
|
+
assert_equal [1, 2, 3, 4], ListMixin.find(:all, :conditions => 'parent_id = 5000', :order => 'pos').map(&:id)
|
315
|
+
|
316
|
+
ListMixin.find(2).destroy
|
317
|
+
|
318
|
+
assert_equal [1, 3, 4], ListMixin.find(:all, :conditions => 'parent_id = 5000', :order => 'pos').map(&:id)
|
319
|
+
|
320
|
+
assert_equal 1, ListMixin.find(1).pos
|
321
|
+
assert_equal 2, ListMixin.find(3).pos
|
322
|
+
assert_equal 3, ListMixin.find(4).pos
|
323
|
+
|
324
|
+
ListMixin.find(1).destroy
|
325
|
+
|
326
|
+
assert_equal [3, 4], ListMixin.find(:all, :conditions => 'parent_id = 5000', :order => 'pos').map(&:id)
|
327
|
+
|
328
|
+
assert_equal 1, ListMixin.find(3).pos
|
329
|
+
assert_equal 2, ListMixin.find(4).pos
|
330
|
+
end
|
331
|
+
|
332
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
Gem::Specification.new do |s|
|
2
|
+
s.name = 'validates_blacklist'
|
3
|
+
s.version = '0.1.1'
|
4
|
+
s.date = '2009-08-26'
|
5
|
+
|
6
|
+
s.summary = "Allows models to be validated against yaml-based blacklists"
|
7
|
+
s.description = ""
|
8
|
+
|
9
|
+
s.authors = ['Jaime Bellmyer']
|
10
|
+
s.email = 'ruby@bellmyer.com'
|
11
|
+
s.homepage = 'http://github.com/bellmyer/validates_blacklist'
|
12
|
+
|
13
|
+
s.has_rdoc = true
|
14
|
+
s.rdoc_options = ["--main", "README"]
|
15
|
+
s.extra_rdoc_files = ["README"]
|
16
|
+
|
17
|
+
s.add_dependency 'rails', ['>= 2.1']
|
18
|
+
|
19
|
+
s.files = [
|
20
|
+
"README",
|
21
|
+
"validates_blacklist.gemspec",
|
22
|
+
"lib/bellmyer-validates_blacklist.rb",
|
23
|
+
"lib/active_record/validates/blacklist.rb",
|
24
|
+
]
|
25
|
+
|
26
|
+
s.test_files = ["test/blacklist_test.rb"]
|
27
|
+
|
28
|
+
end
|
metadata
ADDED
@@ -0,0 +1,67 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: bellmyer-validates_blacklist
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Jaime Bellmyer
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
|
12
|
+
date: 2009-08-26 00:00:00 -07:00
|
13
|
+
default_executable:
|
14
|
+
dependencies:
|
15
|
+
- !ruby/object:Gem::Dependency
|
16
|
+
name: rails
|
17
|
+
type: :runtime
|
18
|
+
version_requirement:
|
19
|
+
version_requirements: !ruby/object:Gem::Requirement
|
20
|
+
requirements:
|
21
|
+
- - ">="
|
22
|
+
- !ruby/object:Gem::Version
|
23
|
+
version: "2.1"
|
24
|
+
version:
|
25
|
+
description: ""
|
26
|
+
email: ruby@bellmyer.com
|
27
|
+
executables: []
|
28
|
+
|
29
|
+
extensions: []
|
30
|
+
|
31
|
+
extra_rdoc_files:
|
32
|
+
- README
|
33
|
+
files:
|
34
|
+
- README
|
35
|
+
- validates_blacklist.gemspec
|
36
|
+
- lib/bellmyer-validates_blacklist.rb
|
37
|
+
- lib/active_record/validates/blacklist.rb
|
38
|
+
has_rdoc: true
|
39
|
+
homepage: http://github.com/bellmyer/validates_blacklist
|
40
|
+
licenses:
|
41
|
+
post_install_message:
|
42
|
+
rdoc_options:
|
43
|
+
- --main
|
44
|
+
- README
|
45
|
+
require_paths:
|
46
|
+
- lib
|
47
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
48
|
+
requirements:
|
49
|
+
- - ">="
|
50
|
+
- !ruby/object:Gem::Version
|
51
|
+
version: "0"
|
52
|
+
version:
|
53
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
54
|
+
requirements:
|
55
|
+
- - ">="
|
56
|
+
- !ruby/object:Gem::Version
|
57
|
+
version: "0"
|
58
|
+
version:
|
59
|
+
requirements: []
|
60
|
+
|
61
|
+
rubyforge_project:
|
62
|
+
rubygems_version: 1.3.5
|
63
|
+
signing_key:
|
64
|
+
specification_version: 2
|
65
|
+
summary: Allows models to be validated against yaml-based blacklists
|
66
|
+
test_files:
|
67
|
+
- test/blacklist_test.rb
|