rd_searchlogic 3.0.0.rc

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.
Files changed (34) hide show
  1. data/.gitignore +7 -0
  2. data/LICENSE +20 -0
  3. data/README.rdoc +308 -0
  4. data/Rakefile +42 -0
  5. data/VERSION.yml +5 -0
  6. data/init.rb +1 -0
  7. data/lib/searchlogic/active_record/association_proxy.rb +19 -0
  8. data/lib/searchlogic/active_record/consistency.rb +49 -0
  9. data/lib/searchlogic/active_record/named_scope_tools.rb +102 -0
  10. data/lib/searchlogic/core_ext/object.rb +43 -0
  11. data/lib/searchlogic/core_ext/proc.rb +17 -0
  12. data/lib/searchlogic/named_scopes/alias_scope.rb +67 -0
  13. data/lib/searchlogic/named_scopes/association_conditions.rb +163 -0
  14. data/lib/searchlogic/named_scopes/association_ordering.rb +44 -0
  15. data/lib/searchlogic/named_scopes/conditions.rb +232 -0
  16. data/lib/searchlogic/named_scopes/or_conditions.rb +141 -0
  17. data/lib/searchlogic/named_scopes/ordering.rb +74 -0
  18. data/lib/searchlogic/rails_helpers.rb +79 -0
  19. data/lib/searchlogic/search.rb +259 -0
  20. data/lib/searchlogic.rb +89 -0
  21. data/rails/init.rb +1 -0
  22. data/spec/searchlogic/active_record/association_proxy_spec.rb +23 -0
  23. data/spec/searchlogic/active_record/consistency_spec.rb +28 -0
  24. data/spec/searchlogic/core_ext/object_spec.rb +9 -0
  25. data/spec/searchlogic/core_ext/proc_spec.rb +8 -0
  26. data/spec/searchlogic/named_scopes/alias_scope_spec.rb +23 -0
  27. data/spec/searchlogic/named_scopes/association_conditions_spec.rb +221 -0
  28. data/spec/searchlogic/named_scopes/association_ordering_spec.rb +29 -0
  29. data/spec/searchlogic/named_scopes/conditions_spec.rb +321 -0
  30. data/spec/searchlogic/named_scopes/or_conditions_spec.rb +66 -0
  31. data/spec/searchlogic/named_scopes/ordering_spec.rb +34 -0
  32. data/spec/searchlogic/search_spec.rb +459 -0
  33. data/spec/spec_helper.rb +146 -0
  34. metadata +123 -0
@@ -0,0 +1,459 @@
1
+ require File.expand_path(File.dirname(__FILE__) + "/../spec_helper")
2
+
3
+ describe Searchlogic::Search do
4
+ # describe "Implementation" do
5
+ # context "#searchlogic" do
6
+ # it "should create a search proxy" do
7
+ # User.search(:username => "joe").should be_kind_of(Searchlogic::Search)
8
+ # end
9
+ #
10
+ # it "should create a search proxy using the same class" do
11
+ # User.search.klass.should == User
12
+ # end
13
+ #
14
+ # it "should pass on the current scope to the proxy" do
15
+ # company = Company.create
16
+ # user = company.users.create
17
+ # search = company.users.search
18
+ # search.current_scope.should == company.users.scope(:find)
19
+ # end
20
+ # end
21
+ # end
22
+
23
+ context "#initialize" do
24
+ it "should require a class" do
25
+ lambda { Searchlogic::Search.new }.should raise_error(ArgumentError)
26
+ end
27
+
28
+ it "should set the conditions" do
29
+ search = User.search(:username => "bjohnson")
30
+ search.conditions.should == {:username => "bjohnson"}
31
+ end
32
+ end
33
+
34
+ # context "#clone" do
35
+ # it "should clone properly" do
36
+ # company = Company.create
37
+ # user1 = company.users.create(:age => 5)
38
+ # user2 = company.users.create(:age => 25)
39
+ # search1 = company.users.search(:age_gt => 10)
40
+ # search2 = search1.clone
41
+ # search2.age_gt = 1
42
+ # search2.all.should == User.all
43
+ # search1.all.should == [user2]
44
+ # end
45
+ #
46
+ # it "should clone properly without scope" do
47
+ # user1 = User.create(:age => 5)
48
+ # user2 = User.create(:age => 25)
49
+ # search1 = User.search(:age_gt => 10)
50
+ # search2 = search1.clone
51
+ # search2.age_gt = 1
52
+ # search2.all.should == User.all
53
+ # search1.all.should == [user2]
54
+ # end
55
+ # end
56
+ #
57
+ # context "#conditions" do
58
+ # it "should set the conditions and be accessible individually" do
59
+ # search = User.search
60
+ # search.conditions = {:username => "bjohnson"}
61
+ # search.username.should == "bjohnson"
62
+ # end
63
+ #
64
+ # it "should set the conditions and allow string keys" do
65
+ # search = User.search
66
+ # search.conditions = {"username" => "bjohnson"}
67
+ # search.username.should == "bjohnson"
68
+ # end
69
+ #
70
+ # it "should use custom scopes before normalizing" do
71
+ # User.create(:username => "bjohnson")
72
+ # User.named_scope :username, lambda { |value| {:conditions => {:username => value.reverse}} }
73
+ # search1 = User.search(:username => "bjohnson")
74
+ # search2 = User.search(:username => "nosnhojb")
75
+ # search1.count.should == 0
76
+ # search2.count.should == 1
77
+ # end
78
+ #
79
+ # # We ignore them upon execution. But we still want to accept the condition so that returning the conditions
80
+ # # preserves the values.
81
+ # it "should ignore blank values but still return on conditions" do
82
+ # search = User.search
83
+ # search.conditions = {"username" => ""}
84
+ # search.username.should be_nil
85
+ # search.conditions.should == {:username => ""}
86
+ # end
87
+ #
88
+ # it "should not ignore blank values and should not cast them" do
89
+ # search = User.search
90
+ # search.conditions = {"id_equals" => ""}
91
+ # search.id_equals.should be_nil
92
+ # search.conditions.should == {:id_equals => ""}
93
+ # end
94
+ #
95
+ # it "should ignore blank values in arrays" do
96
+ # search = User.search
97
+ # search.conditions = {"username_equals_any" => [""]}
98
+ # search.username_equals_any.should be_nil
99
+ #
100
+ # search.conditions = {"id_equals_any" => ["", "1"]}
101
+ # search.id_equals_any.should == [1]
102
+ # end
103
+ # end
104
+ #
105
+ # context "condition accessors" do
106
+ # it "should allow setting exact columns individually" do
107
+ # search = User.search
108
+ # search.username = "bjohnson"
109
+ # search.username.should == "bjohnson"
110
+ # end
111
+ #
112
+ # it "should allow setting local column conditions individually" do
113
+ # search = User.search
114
+ # search.username_gt = "bjohnson"
115
+ # search.username_gt.should == "bjohnson"
116
+ # end
117
+ #
118
+ # it "should allow chaining conditions" do
119
+ # user = User.create(:username => "bjohnson", :age => 20)
120
+ # User.create(:username => "bjohnson", :age => 5)
121
+ # search = User.search
122
+ # search.username_equals("bjohnson").age_gt(10)
123
+ # search.all.should == [user]
124
+ # end
125
+ #
126
+ # it "should allow setting association conditions" do
127
+ # search = User.search
128
+ # search.orders_total_gt = 10
129
+ # search.orders_total_gt.should == 10
130
+ # end
131
+ #
132
+ # it "should allow setting pre-existing association conditions" do
133
+ # User.named_scope :uname, lambda { |value| {:conditions => ["users.username = ?", value]} }
134
+ # search = Company.search
135
+ # search.users_uname = "bjohnson"
136
+ # search.users_uname.should == "bjohnson"
137
+ # end
138
+ #
139
+ # it "should allow setting pre-existing association alias conditions" do
140
+ # User.alias_scope :username_has, lambda { |value| User.username_like(value) }
141
+ # search = Company.search
142
+ # search.users_username_has = "bjohnson"
143
+ # search.users_username_has.should == "bjohnson"
144
+ # end
145
+ #
146
+ # it "should allow using custom conditions" do
147
+ # User.named_scope(:four_year_olds, { :conditions => { :age => 4 } })
148
+ # search = User.search
149
+ # search.four_year_olds = true
150
+ # search.four_year_olds.should == true
151
+ # search.proxy_options.should == User.four_year_olds.proxy_options
152
+ # end
153
+ #
154
+ # it "should not merge conflicting conditions into one value" do
155
+ # # This class should JUST be a proxy. It should not do anything more than that.
156
+ # # A user would be allowed to call both named scopes if they wanted.
157
+ # search = User.search
158
+ # search.username_greater_than = "bjohnson1"
159
+ # search.username_gt = "bjohnson2"
160
+ # search.username_greater_than.should == "bjohnson1"
161
+ # search.username_gt.should == "bjohnson2"
162
+ # end
163
+ #
164
+ # it "should allow setting custom conditions individually with an arity of 0" do
165
+ # User.named_scope(:four_year_olds, :conditions => {:age => 4})
166
+ # search = User.search
167
+ # search.four_year_olds = true
168
+ # search.four_year_olds.should == true
169
+ # end
170
+ #
171
+ # it "should allow setting custom conditions individually with an arity of 1" do
172
+ # User.named_scope(:username_should_be, lambda { |u| {:conditions => {:username => u}} })
173
+ # search = User.search
174
+ # search.username_should_be = "bjohnson"
175
+ # search.username_should_be.should == "bjohnson"
176
+ # end
177
+ #
178
+ # it "should not allow setting conditions that are not scopes" do
179
+ # search = User.search
180
+ # lambda { search.unknown = true }.should raise_error(Searchlogic::Search::UnknownConditionError)
181
+ # end
182
+ #
183
+ # it "should not allow setting conditions on sensitive methods" do
184
+ # search = User.search
185
+ # lambda { search.destroy = true }.should raise_error(Searchlogic::Search::UnknownConditionError)
186
+ # end
187
+ #
188
+ # it "should not use the ruby implementation of the id method" do
189
+ # search = User.search
190
+ # search.id.should be_nil
191
+ # end
192
+ #
193
+ # context "type casting" do
194
+ # it "should be a Boolean given true" do
195
+ # search = User.search
196
+ # search.id_nil = true
197
+ # search.id_nil.should == true
198
+ # end
199
+ #
200
+ # it "should be a Boolean given 'true'" do
201
+ # search = User.search
202
+ # search.id_nil = "true"
203
+ # search.id_nil.should == true
204
+ # end
205
+ #
206
+ # it "should be a Boolean given '1'" do
207
+ # search = User.search
208
+ # search.id_nil = "1"
209
+ # search.id_nil.should == true
210
+ # end
211
+ #
212
+ # it "should be a Boolean given false" do
213
+ # search = User.search
214
+ # search.id_nil = false
215
+ # search.id_nil.should == false
216
+ # end
217
+ #
218
+ # it "should be a Boolean given 'false'" do
219
+ # search = User.search
220
+ # search.id_nil = "false"
221
+ # search.id_nil.should == false
222
+ # end
223
+ #
224
+ # it "should be a Boolean given '0'" do
225
+ # search = User.search
226
+ # search.id_nil = "0"
227
+ # search.id_nil.should == false
228
+ # end
229
+ #
230
+ # it "should be an Integer given ''" do
231
+ # search = User.search
232
+ # search.id_gt = ''
233
+ # search.id_gt.should == 0
234
+ # end
235
+ #
236
+ # it "should be an Integer given 1" do
237
+ # search = User.search
238
+ # search.id_gt = 1
239
+ # search.id_gt.should == 1
240
+ # end
241
+ #
242
+ # it "should be an Integer given '1'" do
243
+ # search = User.search
244
+ # search.id_gt = "1"
245
+ # search.id_gt.should == 1
246
+ # end
247
+ #
248
+ # it "should be a Float given 1.0" do
249
+ # search = Order.search
250
+ # search.total_gt = 1.0
251
+ # search.total_gt.should == 1.0
252
+ # end
253
+ #
254
+ # it "should be a Float given '1'" do
255
+ # search = Order.search
256
+ # search.total_gt = "1"
257
+ # search.total_gt.should == 1.0
258
+ # end
259
+ #
260
+ # it "should be a Float given '1.5'" do
261
+ # search = Order.search
262
+ # search.total_gt = "1.5"
263
+ # search.total_gt.should == 1.5
264
+ # end
265
+ #
266
+ # it "should be a Range given 1..3" do
267
+ # search = Order.search
268
+ # search.total_eq = (1..3)
269
+ # search.total_eq.should == (1..3)
270
+ # end
271
+ #
272
+ # it "should be a Date given 'Jan 1, 2009'" do
273
+ # search = Order.search
274
+ # search.shipped_on_after = "Jan 1, 2009"
275
+ # search.shipped_on_after.should == Date.parse("Jan 1, 2009")
276
+ # end
277
+ #
278
+ # it "should be a Time given 'Jan 1, 2009'" do
279
+ # search = Order.search
280
+ # search.created_at_after = "Jan 1, 2009"
281
+ # search.created_at_after.should == Time.zone.parse("Jan 1, 2009")
282
+ # end
283
+ #
284
+ # it "should be a Time given 'Jan 1, 2009 9:33AM'" do
285
+ # search = Order.search
286
+ # search.created_at_after = "Jan 1, 2009 9:33AM"
287
+ # search.created_at_after.should == Time.zone.parse("Jan 1, 2009 9:33AM")
288
+ # end
289
+ #
290
+ # it "should skip time zone conversion for attributes skipped" do
291
+ # search = User.search
292
+ # search.whatever_at_after = "Jan 1, 2009 9:33AM"
293
+ # search.whatever_at_after.should == Time.parse("Jan 1, 2009 9:33AM").utc
294
+ # end
295
+ #
296
+ # it "should convert the time to the current zone" do
297
+ # search = Order.search
298
+ # now = Time.now
299
+ # search.created_at_after = now
300
+ # search.created_at_after.should == now.in_time_zone
301
+ # end
302
+ #
303
+ # it "should be an Array and cast it's values given ['1', '2', '3']" do
304
+ # search = Order.search
305
+ # search.id_equals_any = ["1", "2", "3"]
306
+ # search.id_equals_any.should == [1, 2, 3]
307
+ # end
308
+ #
309
+ # it "should type cast association conditions" do
310
+ # search = User.search
311
+ # search.orders_total_gt = "10"
312
+ # search.orders_total_gt.should == 10
313
+ # end
314
+ #
315
+ # it "should type cast deep association conditions" do
316
+ # search = Company.search
317
+ # search.users_orders_total_gt = "10"
318
+ # search.users_orders_total_gt.should == 10
319
+ # end
320
+ #
321
+ # it "should support Rails' date_select and datetime_select out of the box" do
322
+ # search = Company.search('created_at_after(1i)' => 2000, 'created_at_after(2i)' => 1, 'created_at_after(3i)' => 1)
323
+ # search.created_at_after.should_not be_nil
324
+ # search.created_at_after.should == Time.zone.local(2000, 1, 1)
325
+ # end
326
+ # end
327
+ # end
328
+ #
329
+ # context "#delete" do
330
+ # it "should delete the condition" do
331
+ # search = User.search(:username_like => "bjohnson")
332
+ # search.delete("username_like")
333
+ # search.username_like.should be_nil
334
+ # search.conditions["username_like"].should be_nil
335
+ # end
336
+ # end
337
+ #
338
+ # context "#ordering_by" do
339
+ # it "should return nil if we aren't ordering" do
340
+ # search = User.search
341
+ # search.ordering_by.should be_nil
342
+ # end
343
+ #
344
+ # it "should return the column name for ascending" do
345
+ # search = User.search(:order => "ascend_by_first_name")
346
+ # search.ordering_by.should == "first_name"
347
+ # end
348
+ #
349
+ # it "should return the column name for descending" do
350
+ # search = User.search(:order => "descend_by_first_name")
351
+ # search.ordering_by.should == "first_name"
352
+ # end
353
+ #
354
+ # it "should handle symbols" do
355
+ # search = User.search(:order => :descend_by_first_name)
356
+ # search.ordering_by.should == "first_name"
357
+ # end
358
+ # end
359
+ #
360
+ # context "#method_missing" do
361
+ # context "setting" do
362
+ # it "should call named scopes for conditions" do
363
+ # User.search(:age_less_than => 5).proxy_options.should == User.age_less_than(5).proxy_options
364
+ # end
365
+ #
366
+ # it "should alias exact column names to use equals" do
367
+ # User.search(:username => "joe").proxy_options.should == User.username_equals("joe").proxy_options
368
+ # end
369
+ #
370
+ # it "should recognize conditions with a value of true where the named scope has an arity of 0" do
371
+ # User.search(:username_nil => true).proxy_options.should == User.username_nil.proxy_options
372
+ # end
373
+ #
374
+ # it "should ignore conditions with a value of false where the named scope has an arity of 0" do
375
+ # User.search(:username_nil => false).proxy_options.should == {}
376
+ # end
377
+ #
378
+ # it "should not ignore conditions with a value of false where the named scope does not have an arity of 0" do
379
+ # User.search(:username_is => false).proxy_options.should == User.username_is(false).proxy_options
380
+ # end
381
+ #
382
+ # it "should recognize the order condition" do
383
+ # User.search(:order => "ascend_by_username").proxy_options.should == User.ascend_by_username.proxy_options
384
+ # end
385
+ #
386
+ # it "should pass array values as multiple arguments with arity -1" do
387
+ # User.named_scope(:multiple_args, lambda { |*args|
388
+ # raise "This should not be an array, it should be 1" if args.first.is_a?(Array)
389
+ # {:conditions => ["id IN (?)", args]}
390
+ # })
391
+ # User.search(:multiple_args => [1,2]).proxy_options.should == User.multiple_args(1,2).proxy_options
392
+ # end
393
+ #
394
+ # it "should pass array as a single value with arity >= 0" do
395
+ # User.named_scope(:multiple_args, lambda { |args|
396
+ # raise "This should be an array" if !args.is_a?(Array)
397
+ # {:conditions => ["id IN (?)", args]}
398
+ # })
399
+ # User.search(:multiple_args => [1,2]).proxy_options.should == User.multiple_args([1,2]).proxy_options
400
+ # end
401
+ #
402
+ # it "should not split out dates or times (big fix)" do
403
+ # s = User.search
404
+ # s.created_at_after = Time.now
405
+ # lambda { s.count }.should_not raise_error
406
+ # end
407
+ #
408
+ # it "should not include blank values" do
409
+ # s = User.search
410
+ # s.conditions = {"id_equals" => ""}
411
+ # s.proxy_options.should == {}
412
+ # end
413
+ # end
414
+ # end
415
+ #
416
+ # context "delegation" do
417
+ # it "should return all when not given any conditions" do
418
+ # 3.times { User.create }
419
+ # User.search.all.length.should == 3
420
+ # end
421
+ #
422
+ # it "should implement the current scope based on an association" do
423
+ # User.create
424
+ # company = Company.create
425
+ # user = company.users.create
426
+ # company.users.search.all.should == [user]
427
+ # end
428
+ #
429
+ # it "should implement the current scope based on a named scope" do
430
+ # User.named_scope(:four_year_olds, :conditions => {:age => 4})
431
+ # (3..5).each { |age| User.create(:age => age) }
432
+ # User.four_year_olds.search.all.should == User.find_all_by_age(4)
433
+ # end
434
+ #
435
+ # it "should respond to count" do
436
+ # User.create(:username => "bjohnson")
437
+ # search1 = User.search(:username => "bjohnson")
438
+ # search2 = User.search(:username => "nosnhojb")
439
+ # search1.count.should == 1
440
+ # search2.count.should == 0
441
+ # end
442
+ #
443
+ # it "should respond to empty?" do
444
+ # User.create(:username => "bjohnson")
445
+ # search1 = User.search(:username => "bjohnson")
446
+ # search2 = User.search(:username => "nosnhojb")
447
+ # search1.empty?.should == false
448
+ # search2.empty?.should == true
449
+ # end
450
+ #
451
+ # it "should delegate to named scopes with arity > 1" do
452
+ # User.named_scope :paged, lambda {|start, limit| { :limit => limit, :offset => start }}
453
+ # User.create(:username => "bjohnson")
454
+ # search = User.search(:username => "bjohnson")
455
+ # search.paged(0, 1).count.should == 1
456
+ # search.paged(0, 0).count.should == 0
457
+ # end
458
+ # end
459
+ end
@@ -0,0 +1,146 @@
1
+ require 'spec'
2
+ require 'rubygems'
3
+ require 'ruby-debug'
4
+ require 'active_record'
5
+ require 'active_support/core_ext' if ActiveRecord::VERSION::MAJOR > 2
6
+
7
+ Spec::Matchers.define :eq_scope do |relation2|
8
+ match do |relation1|
9
+ relation1.to_sql.squeeze(' ').downcase == relation2.to_sql.squeeze(' ').downcase
10
+ end
11
+ failure_message_for_should do |relation1|
12
+ "expected\n#{relation2.to_sql.squeeze(' ')}\nto equal\n#{relation1.to_sql.squeeze(' ')}"
13
+ end
14
+ failure_message_for_should_not do |relation1|
15
+ "expected\n#{relation2.to_sql.squeeze(' ')}\nto not equal\n#{relation1.to_sql.squeeze(' ')}"
16
+ end
17
+ end
18
+
19
+ ENV['TZ'] = 'UTC'
20
+ Time.zone = 'Eastern Time (US & Canada)'
21
+
22
+ ActiveRecord::Base.establish_connection(:adapter => "sqlite3", :database => ":memory:")
23
+ ActiveRecord::Base.configurations = true
24
+ ActiveRecord::Base.logger = Logger.new(STDOUT)
25
+
26
+ ActiveRecord::Schema.verbose = false
27
+ ActiveRecord::Schema.define(:version => 1) do
28
+ create_table :audits do |t|
29
+ t.string :auditable_type
30
+ t.integer :auditable_id
31
+ end
32
+
33
+ create_table :companies do |t|
34
+ t.datetime :created_at
35
+ t.datetime :updated_at
36
+ t.string :name
37
+ t.string :description
38
+ t.integer :users_count, :default => 0
39
+ end
40
+
41
+ create_table :user_groups do |t|
42
+ t.string :name
43
+ end
44
+
45
+ create_table :user_groups_users, :id => false do |t|
46
+ t.integer :user_group_id, :null => false
47
+ t.integer :user_id, :null => false
48
+ end
49
+
50
+ create_table :users do |t|
51
+ t.datetime :created_at
52
+ t.datetime :updated_at
53
+ t.integer :company_id
54
+ t.string :username
55
+ t.string :name
56
+ t.integer :age
57
+ t.boolean :male
58
+ t.string :some_type_id
59
+ t.datetime :whatever_at
60
+ end
61
+
62
+ create_table :carts do |t|
63
+ t.datetime :created_at
64
+ t.datetime :updated_at
65
+ t.integer :user_id
66
+ end
67
+
68
+ create_table :orders do |t|
69
+ t.datetime :created_at
70
+ t.datetime :updated_at
71
+ t.integer :user_id
72
+ t.date :shipped_on
73
+ t.float :taxes
74
+ t.float :total
75
+ end
76
+
77
+ create_table :fees do |t|
78
+ t.datetime :created_at
79
+ t.datetime :updated_at
80
+ t.string :owner_type
81
+ t.integer :owner_id
82
+ t.float :cost
83
+ end
84
+
85
+ create_table :line_items do |t|
86
+ t.datetime :created_at
87
+ t.datetime :updated_at
88
+ t.integer :order_id
89
+ t.float :price
90
+ end
91
+ end
92
+
93
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
94
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
95
+ require 'searchlogic'
96
+
97
+ Spec::Runner.configure do |config|
98
+ config.before(:each) do
99
+ class Audit < ActiveRecord::Base
100
+ belongs_to :auditable, :polymorphic => true
101
+ end
102
+
103
+ class Company < ActiveRecord::Base
104
+ has_many :orders, :through => :users
105
+ has_many :users, :dependent => :destroy
106
+ end
107
+
108
+ class UserGroup < ActiveRecord::Base
109
+ has_and_belongs_to_many :users
110
+ end
111
+
112
+ class User < ActiveRecord::Base
113
+ belongs_to :company, :counter_cache => true
114
+ has_many :orders, :dependent => :destroy
115
+ has_many :orders_big, :class_name => 'Order', :conditions => 'total > 100'
116
+ has_and_belongs_to_many :user_groups
117
+
118
+ self.skip_time_zone_conversion_for_attributes = [:whatever_at]
119
+ end
120
+
121
+ class Order < ActiveRecord::Base
122
+ belongs_to :user
123
+ has_many :line_items, :dependent => :destroy
124
+ end
125
+
126
+ class Fee < ActiveRecord::Base
127
+ belongs_to :owner, :polymorphic => true
128
+ end
129
+
130
+ class LineItem < ActiveRecord::Base
131
+ belongs_to :order
132
+ end
133
+
134
+ Company.destroy_all
135
+ User.destroy_all
136
+ Order.destroy_all
137
+ LineItem.destroy_all
138
+ end
139
+
140
+ config.after(:each) do
141
+ Object.send(:remove_const, :Company)
142
+ Object.send(:remove_const, :User)
143
+ Object.send(:remove_const, :Order)
144
+ Object.send(:remove_const, :LineItem)
145
+ end
146
+ end