amoeba 1.2.1 → 3.2.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/spec/spec_helper.rb CHANGED
@@ -1,8 +1,29 @@
1
+ require 'simplecov'
2
+ require 'coveralls'
3
+ SimpleCov.formatter = SimpleCov::Formatter::MultiFormatter.new([
4
+ SimpleCov::Formatter::HTMLFormatter,
5
+ Coveralls::SimpleCov::Formatter
6
+ ])
7
+ SimpleCov.start do
8
+ add_filter 'spec'
9
+ minimum_coverage(76)
10
+ end
11
+ require 'active_record'
1
12
  require 'amoeba'
2
13
 
3
- ActiveRecord::Base.establish_connection(:adapter => "sqlite3",
4
- :database => File.dirname(__FILE__) + "/test.sqlite3")
14
+ adapter = if defined?(JRuby)
15
+ require 'activerecord-jdbcsqlite3-adapter'
16
+ 'jdbcsqlite3'
17
+ else
18
+ require 'sqlite3'
19
+ 'sqlite3'
20
+ end
21
+
22
+ ActiveRecord::Base.establish_connection(adapter: adapter, database: ':memory:')
23
+
24
+ ::RSpec.configure do |config|
25
+ config.order = :default
26
+ end
5
27
 
6
28
  load File.dirname(__FILE__) + '/support/schema.rb'
7
29
  load File.dirname(__FILE__) + '/support/models.rb'
8
- load File.dirname(__FILE__) + '/support/data.rb'
data/spec/support/data.rb CHANGED
@@ -1,108 +1,77 @@
1
- u1 = User.create(:name => "Robert Johnson", :email => "bob@crossroads.com")
2
- u2 = User.create(:name => "Miles Davis", :email => "miles@kindofblue.com")
3
1
 
4
- a1 = Author.create(:full_name => "Kermit The Vonnegut", :nickname => "kvsoitgoes")
5
- a2 = Author.create(:full_name => "Arthur Sees Clarck", :nickname => "strangewater")
2
+ u1 = User.create(name: 'Robert Johnson', email: 'bob@crossroads.com')
3
+ u2 = User.create(name: 'Miles Davis', email: 'miles@kindofblue.com')
6
4
 
7
- t = Topic.create(:title => "Ponies", :description => "Lets talk about my ponies.")
5
+ a1 = Author.create(full_name: 'Kermit The Vonnegut', nickname: 'kvsoitgoes')
6
+ a2 = Author.create(full_name: 'Arthur Sees Clarck', nickname: 'strangewater')
7
+
8
+ t = Topic.create(title: 'Ponies', description: 'Lets talk about my ponies.')
8
9
 
9
10
  # First Post {{{
10
- p1 = t.posts.create(:owner => u1, :author => a1, :title => "My little pony", :contents => "Lorum ipsum dolor rainbow bright. I like dogs, dogs are awesome.")
11
- f1 = p1.create_post_config(:is_visible => true, :is_open => false, :password => 'abcdefg123')
12
- a1 = p1.create_account(:title => "Foo")
13
- h1 = p1.account.create_history(:some_stuff => "Bar")
14
- c1 = p1.comments.create(:contents => "I love it!", :nerf => "ratatat")
15
- c1.ratings.create(:num_stars => 5)
16
- c1.ratings.create(:num_stars => 5)
17
- c1.ratings.create(:num_stars => 4)
18
- c1.ratings.create(:num_stars => 3)
19
- c1.ratings.create(:num_stars => 5)
20
- c1.ratings.create(:num_stars => 5)
21
-
22
- c2 = p1.comments.create(:contents => "I hate it!", :nerf => "whapaow")
23
- c2.ratings.create(:num_stars => 3)
24
- c2.ratings.create(:num_stars => 1)
25
- c2.ratings.create(:num_stars => 4)
26
- c2.ratings.create(:num_stars => 1)
27
- c2.ratings.create(:num_stars => 1)
28
- c2.ratings.create(:num_stars => 2)
29
-
30
- c3 = p1.comments.create(:contents => "kthxbbq!!11!!!1!eleven!!", :nerf => "bonk")
31
- c3.ratings.create(:num_stars => 0)
32
- c3.ratings.create(:num_stars => 0)
33
- c3.ratings.create(:num_stars => 1)
34
- c3.ratings.create(:num_stars => 2)
35
- c3.ratings.create(:num_stars => 1)
36
- c3.ratings.create(:num_stars => 0)
37
-
38
- t1 = Tag.create(:value => "funny")
39
- t2 = Tag.create(:value => "wtf")
40
- t3 = Tag.create(:value => "cats")
41
-
42
- p1.tags << t1
43
- p1.tags << t2
44
- p1.tags << t3
45
- p1.save
11
+ p1 = t.posts.create(owner: u1, author: a1, title: 'My little pony', contents: 'Lorum ipsum dolor rainbow bright. I like dogs, dogs are awesome.')
12
+ f1 = p1.create_post_config(is_visible: true, is_open: false, password: 'abcdefg123')
13
+ a1 = p1.create_account(title: 'Foo')
14
+ h1 = p1.account.create_history(some_stuff: 'Bar')
15
+ c1 = p1.comments.create(contents: 'I love it!', nerf: 'ratatat')
16
+ [5, 5, 4, 3, 5, 5].each { |stars| c1.ratings.create(num_stars: stars) }
46
17
 
47
- w1 = Widget.create(:value => "My Sidebar")
48
- w2 = Widget.create(:value => "Photo Gallery")
49
- w3 = Widget.create(:value => "Share & Like")
18
+ c2 = p1.comments.create(contents: 'I hate it!', nerf: 'whapaow')
19
+ [3, 1, 4, 1, 1, 2].each { |stars| c2.ratings.create(num_stars: stars) }
50
20
 
51
- p1.widgets << w1
52
- p1.widgets << w2
53
- p1.widgets << w3
54
- p1.save
21
+ c3 = p1.comments.create(contents: 'kthxbbq!!11!!!1!eleven!!', nerf: 'bonk')
22
+ [0, 0, 1, 2, 1, 0].each { |stars| c3.ratings.create(num_stars: stars) }
23
+
24
+ %w(funny wtf cats).each { |value| p1.tags << Tag.create(value: value) }
25
+
26
+ ['My Sidebar', 'Photo Gallery', 'Share & Like'].each { |value| p1.widgets << Widget.create(value: value) }
55
27
 
56
- n1 = Note.create(:value => "This is important")
57
- n2 = Note.create(:value => "You've been warned")
58
- n3 = Note.create(:value => "Don't forget")
28
+ ['This is important', "You've been warned", "Don't forget"].each { |value| p1.notes << Note.create(value: value) }
59
29
 
60
- p1.notes << n1
61
- p1.notes << n2
62
- p1.notes << n3
63
30
  p1.save
64
31
 
65
- c1 = Category.create(:title => "Umbrellas", :description => "Clown fart")
66
- c2 = Category.create(:title => "Widgets", :description => "Humpty dumpty")
67
- c3 = Category.create(:title => "Wombats", :description => "Slushy mushy")
32
+ c1 = Category.create(title: 'Umbrellas', description: 'Clown fart')
33
+ c2 = Category.create(title: 'Widgets', description: 'Humpty dumpty')
34
+ c3 = Category.create(title: 'Wombats', description: 'Slushy mushy')
68
35
 
69
- s1 = Supercat.create(:post => p1, :category => c1, :ramblings => "zomg", :other_ramblings => "nerp")
70
- s2 = Supercat.create(:post => p1, :category => c2, :ramblings => "why", :other_ramblings => "narp")
71
- s3 = Supercat.create(:post => p1, :category => c3, :ramblings => "ohnoes", :other_ramblings => "blap")
36
+ s1 = Supercat.create(post: p1, category: c1, ramblings: 'zomg', other_ramblings: 'nerp')
37
+ s2 = Supercat.create(post: p1, category: c2, ramblings: 'why', other_ramblings: 'narp')
38
+ s3 = Supercat.create(post: p1, category: c3, ramblings: 'ohnoes', other_ramblings: 'blap')
72
39
 
73
- s1.superkittens.create(:value => "Fluffy")
74
- s1.superkittens.create(:value => "Buffy")
75
- s1.superkittens.create(:value => "Fuzzy")
40
+ s1.superkittens.create(value: 'Fluffy')
41
+ s1.superkittens.create(value: 'Buffy')
42
+ s1.superkittens.create(value: 'Fuzzy')
76
43
 
77
- s2.superkittens.create(:value => "Hairball")
78
- s2.superkittens.create(:value => "Crosseye")
79
- s2.superkittens.create(:value => "Spot")
44
+ s2.superkittens.create(value: 'Hairball')
45
+ s2.superkittens.create(value: 'Crosseye')
46
+ s2.superkittens.create(value: 'Spot')
80
47
 
81
- s3.superkittens.create(:value => "Dopey")
82
- s3.superkittens.create(:value => "Sneezy")
83
- s3.superkittens.create(:value => "Sleepy")
48
+ s3.superkittens.create(value: 'Dopey')
49
+ s3.superkittens.create(value: 'Sneezy')
50
+ s3.superkittens.create(value: 'Sleepy')
51
+
52
+ p1.custom_things.create([{ value: [1, 2] }, { value: [] }, { value: [78] }])
84
53
  # }}}
85
54
 
86
55
  # Product {{{
87
- product1 = Product.create(:title => "Sticky Notes 5-Pak", :price => 5.99, :weight => 0.56)
88
- shirt1 = Shirt.create(:title => "Fancy Shirt", :price => 48.95, :sleeve => 32, :collar => 15.5)
89
- necklace1 = Necklace.create(:title => "Pearl Necklace", :price => 2995.99, :length => 18, :metal => "14k")
56
+ product1 = Product.create(title: 'Sticky Notes 5-Pak', price: 5.99, weight: 0.56)
57
+ shirt1 = Shirt.create(title: 'Fancy Shirt', price: 48.95, sleeve: 32, collar: 15.5)
58
+ necklace1 = Necklace.create(title: 'Pearl Necklace', price: 2995.99, length: 18, metal: '14k')
90
59
 
91
- img1 = product1.images.create(:filename => "sticky.jpg")
92
- img2 = product1.images.create(:filename => "notes.jpg")
60
+ img1 = product1.images.create(filename: 'sticky.jpg')
61
+ img2 = product1.images.create(filename: 'notes.jpg')
93
62
 
94
- img1 = shirt1.images.create(:filename => "02948u31.jpg")
95
- img2 = shirt1.images.create(:filename => "zsif8327.jpg")
63
+ img1 = shirt1.images.create(filename: '02948u31.jpg')
64
+ img2 = shirt1.images.create(filename: 'zsif8327.jpg')
96
65
 
97
- img1 = necklace1.images.create(:filename => "ae02x9f1.jpg")
98
- img2 = necklace1.images.create(:filename => "cba9f912.jpg")
66
+ img1 = necklace1.images.create(filename: 'ae02x9f1.jpg')
67
+ img2 = necklace1.images.create(filename: 'cba9f912.jpg')
99
68
 
100
- office = Section.create(:name => "Office", :num_employees => 2, :total_sales => "1234.56")
101
- supplies = Section.create(:name => "Supplies", :num_employees => 1, :total_sales => "543.21")
102
- mens = Section.create(:name => "Mens", :num_employees => 3, :total_sales => "11982.63")
103
- apparel = Section.create(:name => "Apparel", :num_employees => 5, :total_sales => "1315.20")
104
- accessories = Section.create(:name => "Accessories", :num_employees => 1, :total_sales => "8992.34")
105
- jewelry = Section.create(:name => "Jewelry", :num_employees => 3, :total_sales => "25481.77")
69
+ office = Section.create(name: 'Office', num_employees: 2, total_sales: '1234.56')
70
+ supplies = Section.create(name: 'Supplies', num_employees: 1, total_sales: '543.21')
71
+ mens = Section.create(name: 'Mens', num_employees: 3, total_sales: '11982.63')
72
+ apparel = Section.create(name: 'Apparel', num_employees: 5, total_sales: '1315.20')
73
+ accessories = Section.create(name: 'Accessories', num_employees: 1, total_sales: '8992.34')
74
+ jewelry = Section.create(name: 'Jewelry', num_employees: 3, total_sales: '25481.77')
106
75
 
107
76
  product1.sections << office
108
77
  product1.sections << supplies
@@ -115,4 +84,16 @@ shirt1.save
115
84
  necklace1.sections << jewelry
116
85
  necklace1.sections << accessories
117
86
  necklace1.save
87
+
88
+
89
+ company = Company.create(name:'ABC Industries')
90
+ employee = company.employees.create(name:'Joe',ssn:'1111111111',salary:10000.0)
91
+ employee_address = employee.addresses.create(street: '123 My Street',unit:'103',city:'Hollywood',state:'CA',zip:'90210')
92
+ employee_address_2 = employee.addresses.create(street: '124 My Street',unit:'103',city:'Follywood',state:'CA',zip:'90210')
93
+ employee_photo = employee.photos.create(name: 'Portrait', size: 12345)
94
+ customer = company.customers.create(email:'my@email.address',password:'password')
95
+ customer_address = customer.addresses.create(street: '321 My Street',unit:'301',city:'Bollywood',state:'IN',zip:'11111')
96
+ customer_address_2 = customer.addresses.create(street: '321 My Drive',unit:'311',city:'Mollywood',state:'IN',zip:'21111')
97
+ customer_photo = customer.photos.create(name: 'Mug Shot', size: 54321)
98
+
118
99
  # }}}
@@ -7,7 +7,7 @@ class User < ActiveRecord::Base
7
7
  end
8
8
 
9
9
  class Author < ActiveRecord::Base
10
- has_many :posts, :inverse_of => :author
10
+ has_many :posts, inverse_of: :author
11
11
  amoeba do
12
12
  enable
13
13
  end
@@ -15,16 +15,17 @@ end
15
15
 
16
16
  class Post < ActiveRecord::Base
17
17
  belongs_to :topic
18
- belongs_to :owner, :class_name => 'User'
19
- belongs_to :author, :inverse_of => :posts
18
+ belongs_to :owner, class_name: 'User'
19
+ belongs_to :author, inverse_of: :posts
20
20
  has_one :post_config
21
21
  has_one :account
22
- has_one :history, :through => :account
22
+ has_one :history, through: :account
23
23
  has_many :comments
24
24
  has_many :supercats
25
- has_many :categories, :through => :supercats
25
+ has_many :categories, through: :supercats
26
26
  has_many :post_widgets
27
- has_many :widgets, :through => :post_widgets
27
+ has_many :widgets, through: :post_widgets
28
+ has_many :custom_things
28
29
  has_and_belongs_to_many :tags
29
30
  has_and_belongs_to_many :notes
30
31
 
@@ -34,13 +35,13 @@ class Post < ActiveRecord::Base
34
35
  amoeba do
35
36
  enable
36
37
  clone [:widgets, :notes]
37
- prepend :title => "Copy of "
38
- append :contents => " (copied version)"
39
- regex :contents => {:replace => /dog/, :with => 'cat'}
38
+ prepend title: 'Copy of '
39
+ append contents: ' (copied version)'
40
+ regex contents: { replace: /dog/, with: 'cat' }
40
41
  customize([
41
- lambda do |orig_obj,copy_of_obj|
42
+ lambda do |orig_obj, copy_of_obj|
42
43
  orig_obj.comments.each do |oc|
43
- if oc.nerf == "ratatat"
44
+ if oc.nerf == 'ratatat'
44
45
  hash = oc.attributes
45
46
  hash[:id] = nil
46
47
  hash[:post_id] = nil
@@ -52,14 +53,14 @@ class Post < ActiveRecord::Base
52
53
  end
53
54
  end
54
55
  end,
55
- lambda do |orig_obj,copy_of_obj|
56
+ lambda do |orig_obj, copy_of_obj|
56
57
  orig_obj.comments.each do |oc|
57
- if oc.nerf == "bonk"
58
+ if oc.nerf == 'bonk'
58
59
  hash = oc.attributes
59
60
  hash[:id] = nil
60
61
  hash[:post_id] = nil
61
62
  hash[:contents] = nil
62
- hash[:nerf] = "bonkers"
63
+ hash[:nerf] = 'bonkers'
63
64
 
64
65
  cc = Comment.new(hash)
65
66
 
@@ -69,10 +70,49 @@ class Post < ActiveRecord::Base
69
70
  end
70
71
  ])
71
72
  end
73
+
74
+ def truthy?
75
+ true
76
+ end
77
+
78
+ def falsey?
79
+ false
80
+ end
81
+
82
+ class << self
83
+ def tag_count
84
+ ActiveRecord::Base.connection.select_one('SELECT COUNT(*) AS tag_count FROM posts_tags')['tag_count']
85
+ end
86
+
87
+ def note_count
88
+ ActiveRecord::Base.connection.select_one('SELECT COUNT(*) AS note_count FROM notes_posts')['note_count']
89
+ end
90
+ end
72
91
  end
73
92
 
74
93
  class CustomThing < ActiveRecord::Base
75
94
  belongs_to :post
95
+
96
+ class ArrayPack
97
+ def self.load(str)
98
+ return [] unless str.present?
99
+ return str if str.is_a?(Array)
100
+ str.split(',').map(&:to_i)
101
+ end
102
+
103
+ def self.dump(int_array)
104
+ return '' unless int_array.present?
105
+ int_array.join(',')
106
+ end
107
+ end
108
+
109
+ serialize :value, ArrayPack
110
+
111
+ before_create :hydrate_me
112
+
113
+ def hydrate_me
114
+ self.value = value
115
+ end
76
116
  end
77
117
 
78
118
  class Account < ActiveRecord::Base
@@ -90,12 +130,12 @@ end
90
130
 
91
131
  class Category < ActiveRecord::Base
92
132
  has_many :supercats
93
- has_many :posts, :through => :supercats
133
+ has_many :posts, through: :supercats
94
134
 
95
135
  amoeba do
96
136
  enable
97
- prepend :ramblings => "Copy of "
98
- set :other_ramblings => "La la la"
137
+ prepend ramblings: 'Copy of '
138
+ set other_ramblings: 'La la la'
99
139
  end
100
140
  end
101
141
 
@@ -105,9 +145,9 @@ class Supercat < ActiveRecord::Base
105
145
  has_many :superkittens
106
146
 
107
147
  amoeba do
108
- include_field :superkittens
109
- prepend :ramblings => "Copy of "
110
- set :other_ramblings => "La la la"
148
+ include_association :superkittens
149
+ prepend ramblings: 'Copy of '
150
+ set other_ramblings: 'La la la'
111
151
  end
112
152
  end
113
153
 
@@ -125,7 +165,7 @@ class Comment < ActiveRecord::Base
125
165
  has_many :reviews
126
166
 
127
167
  amoeba do
128
- exclude_field :reviews
168
+ exclude_association :reviews
129
169
  end
130
170
  end
131
171
 
@@ -139,7 +179,7 @@ end
139
179
 
140
180
  class Widget < ActiveRecord::Base
141
181
  has_many :post_widgets
142
- has_many :posts, :through => :post_widgets
182
+ has_many :posts, through: :post_widgets
143
183
  end
144
184
 
145
185
  class PostWidget < ActiveRecord::Base
@@ -160,10 +200,16 @@ class Product < ActiveRecord::Base
160
200
  has_many :images
161
201
  has_and_belongs_to_many :sections
162
202
 
203
+ SECTION_COUNT_QUERY = 'SELECT COUNT(*) AS section_count FROM products_sections WHERE product_id = ?'.freeze
204
+
163
205
  amoeba do
164
206
  enable
165
207
  propagate
166
208
  end
209
+
210
+ def section_count
211
+ ActiveRecord::Base.connection.select_one(SECTION_COUNT_QUERY, id)['section_count']
212
+ end
167
213
  end
168
214
 
169
215
  class Section < ActiveRecord::Base
@@ -179,21 +225,191 @@ class Shirt < Product
179
225
  end
180
226
 
181
227
  class Necklace < Product
228
+ # Strange bug on rbx
229
+ if defined?(::Rubinius)
230
+ after_initialize :set_type
231
+
232
+ def set_type
233
+ self.type = 'Necklace'
234
+ end
235
+ end
236
+
182
237
  amoeba do
183
238
  raised :relaxed
184
239
  end
185
240
  end
186
241
 
242
+ class BlackBox < Product
243
+ amoeba do
244
+ propagate :strict
245
+ end
246
+ end
247
+
248
+ class SuperBlackBox < BlackBox
249
+ end
250
+
187
251
  # Polymorphism
188
252
  class Address < ActiveRecord::Base
189
- belongs_to :addressable, :polymorphic => true
253
+ belongs_to :addressable, polymorphic: true
254
+
255
+ amoeba do
256
+ enable
257
+ end
258
+ end
259
+
260
+ class Photo < ActiveRecord::Base
261
+ belongs_to :imageable, polymorphic: true
262
+
263
+ amoeba do
264
+ customize(lambda { |original_photo,new_photo|
265
+ new_photo.name = original_photo.name.to_s + ' Copy'
266
+ })
267
+ end
268
+ end
269
+
270
+ class Company < ActiveRecord::Base
271
+ has_many :employees
272
+ has_many :customers
273
+
274
+ amoeba do
275
+ include_associations :employees,
276
+ :customers
277
+ end
190
278
  end
191
279
 
192
280
  class Employee < ActiveRecord::Base
193
- has_many :addresses, :as => :addressable
281
+ has_many :addresses, as: :addressable
282
+ has_many :photos, as: :imageable
283
+ belongs_to :company
284
+
285
+ amoeba do
286
+ include_associations [:addresses, :photos]
287
+ end
288
+
194
289
  end
195
290
 
196
291
  class Customer < ActiveRecord::Base
197
- has_many :addresses, :as => :addressable
292
+ has_many :addresses, as: :addressable
293
+ has_many :photos, as: :imageable
294
+ belongs_to :company
295
+
296
+ amoeba do
297
+ enable
298
+ end
299
+ end
300
+
301
+ # Remapping and Method
302
+
303
+ class MetalObject < ActiveRecord::Base
304
+ end
305
+
306
+ class ObjectPrototype < MetalObject
307
+ has_many :subobject_prototypes, foreign_key: :parent_id
308
+
309
+ amoeba do
310
+ enable
311
+ through :become_real
312
+ remapper :remap_subobjects
313
+ end
314
+
315
+ def become_real
316
+ self.dup.becomes RealObject
317
+ end
318
+
319
+ def remap_subobjects(relation_name)
320
+ :subobjects if relation_name == :subobject_prototypes
321
+ end
322
+ end
323
+
324
+ class RealObject < MetalObject
325
+ has_many :subobjects, foreign_key: :parent_id
198
326
  end
199
327
 
328
+ class SubobjectPrototype < MetalObject
329
+ amoeba do
330
+ enable
331
+ through :become_subobject
332
+ end
333
+
334
+ def become_subobject
335
+ self.dup.becomes Subobject
336
+ end
337
+ end
338
+
339
+ class Subobject < MetalObject
340
+ end
341
+
342
+ # Check of changing boolean attributes
343
+
344
+ class SuperAdmin < ::ActiveRecord::Base
345
+ amoeba do
346
+ set active: false
347
+ prepend password: false
348
+ end
349
+ end
350
+
351
+ # Proper inheritance
352
+
353
+ class Box < ActiveRecord::Base
354
+ has_many :products, class_name: 'BoxProduct'
355
+ has_many :sub_products, class_name: 'BoxSubProduct'
356
+
357
+ amoeba do
358
+ enable
359
+ end
360
+ end
361
+
362
+ class BoxProduct < ActiveRecord::Base
363
+ belongs_to :box, class_name: 'Box'
364
+
365
+ amoeba do
366
+ enable
367
+ propagate
368
+ end
369
+ end
370
+
371
+ class BoxSubProduct < BoxProduct
372
+ has_one :another_product, class_name: 'BoxAnotherProduct'
373
+ end
374
+
375
+ class BoxSubSubProduct < BoxSubProduct
376
+ end
377
+
378
+ class BoxAnotherProduct < BoxProduct
379
+ belongs_to :sub_product, class_name: 'BoxSubProduct'
380
+ end
381
+
382
+ # Inclusion inheritance
383
+ class Stage < ActiveRecord::Base
384
+ has_many :listeners
385
+ has_many :specialists
386
+
387
+ amoeba do
388
+ include_association :listeners
389
+ include_association :specialists
390
+ nullify :external_id
391
+ propagate
392
+ end
393
+ end
394
+
395
+ class Participant < ActiveRecord::Base
396
+ belongs_to :stage
397
+ end
398
+
399
+ class Listener < Participant
400
+ end
401
+
402
+ class Specialist < Participant
403
+ end
404
+
405
+ class CustomStage < Stage
406
+ has_many :custom_rules, foreign_key: :stage_id
407
+
408
+ amoeba do
409
+ include_association :custom_rules
410
+ end
411
+ end
412
+
413
+ class CustomRule < ActiveRecord::Base
414
+ belongs_to :custom_stage
415
+ end