multiple_table_inheritance 0.1.3 → 0.1.4

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/.travis.yml ADDED
@@ -0,0 +1,7 @@
1
+ language: ruby
2
+ rvm:
3
+ - 1.8.7
4
+ - 1.9.2
5
+ - 1.9.3
6
+ - ruby-head
7
+ - ree
data/CHANGELOG.md CHANGED
@@ -1,6 +1,13 @@
1
+ 0.1.4
2
+
3
+ * Fixed mass assignment when security is only defined in child model.
4
+ * Added support for namespaced models.
5
+ * Added many more unit tests.
6
+
1
7
  0.1.3
2
8
 
3
9
  * Fixed a bug that prevented migrations from being run properly.
10
+ * Added several unit tests.
4
11
 
5
12
  0.1.2
6
13
 
data/README.md CHANGED
@@ -1,6 +1,8 @@
1
1
  Multiple Table Inheritance
2
2
  ==========================
3
3
 
4
+ [![Build Status](https://secure.travis-ci.org/mhuggins/multiple_table_inheritance.png)](http://travis-ci.org/mhuggins/multiple_table_inheritance)
5
+
4
6
  Multiple Table Inheritance is a plugin designed to allow for multiple table
5
7
  inheritance between your database tables and your ActiveRecord models.
6
8
 
@@ -19,15 +21,20 @@ How to Install
19
21
 
20
22
  From the command line:
21
23
 
22
- gem install multiple-table-inheritance
24
+ gem install multiple_table_inheritance
23
25
 
24
26
  From your Gemfile:
25
27
 
26
- gem 'multiple_table_inheritance', '~> 0.1.3'
28
+ gem 'multiple_table_inheritance', '~> 0.1.4'
27
29
 
28
30
  Usage
29
31
  =====
30
32
 
33
+ The following sections attempt to explain full coverage for the Multiple Table
34
+ Inheritance plugin. For full code examples, take a look at the test database
35
+ structure and associated models found in `spec/support/tables.rb` and
36
+ `spec/support/models.rb`, respectively.
37
+
31
38
  Running Migrations
32
39
  ------------------
33
40
 
@@ -44,8 +51,10 @@ that this column be non-null for sanity.
44
51
  t.timestamps
45
52
  end
46
53
 
47
- When creating tables that are derived from your superclass table, simple
48
- provide the `:inherits` hash option to your `create_table` call.
54
+ When creating tables that are derived from your superclass table, simply
55
+ provide the `:inherits` hash option to your `create_table` call. The value of
56
+ the option represent the name by which the association is referenced in your
57
+ model.
49
58
 
50
59
  create_table :programmers, :inherits => :employee do |t|
51
60
  t.datetime :training_completed_at
@@ -96,6 +105,11 @@ to `inherits_from`. (Presently, this has only be tested to work with the
96
105
  Creating Records
97
106
  ----------------
98
107
 
108
+ Records can be created directly from their inheriting (child) model classes.
109
+ Given model names `Employee`, `Programmer`, and `Manager` based upon the table
110
+ structures outlined in the "Running Migrations" section, records can be created
111
+ in the following manner.
112
+
99
113
  Programmer.create(
100
114
  :first_name => 'Bob',
101
115
  :last_name => 'Smith',
@@ -142,18 +156,18 @@ Validation
142
156
  When creating a new record that inherits from another model, validation is
143
157
  taken into consideration across both models.
144
158
 
145
- class ::Employee < ActiveRecord::Base
159
+ class Employee < ActiveRecord::Base
146
160
  acts_as_superclass
147
161
  validates :first_name, :presence => true
148
162
  validates :last_name, :presence => true
149
163
  validates :salary, :presence => true, :numericality => { :min => 0 }
150
164
  end
151
165
 
152
- class ::Programmer < ActiveRecord::Base
166
+ class Programmer < ActiveRecord::Base
153
167
  inherits_from :employee
154
168
  end
155
169
 
156
- class ::Manager < ActiveRecord::Base
170
+ class Manager < ActiveRecord::Base
157
171
  inherits_from :employee
158
172
  validates :bonus, :presence => true, :numericality => true
159
173
  end
@@ -180,12 +194,6 @@ for a normal ActiveRecord model.
180
194
  attr_accessible :bonus
181
195
  end
182
196
 
183
- **NOTE:** When an ActiveRecord model does not make a call to `attr_accessible`,
184
- all its fields are presumed to be accessible. Currently, when using
185
- MultipleTableInheritance, if a parent class does not call `attr_accesible` and
186
- one of its children does, then the parent's attributes cannot properly be
187
- stored. This will be fixed in a future release.
188
-
189
197
  Associations
190
198
  ------------
191
199
 
@@ -220,3 +228,31 @@ Associations will also work in the same way as other attributes.
220
228
  programmer = Programmer.first # <Programmer employee_id: 1 training_completed_at: "2009-03-06 00:30:00">
221
229
  programmer.languages.collect(&:name) # ['Java', 'C++']
222
230
  programmer.team.name # 'Website Front-End'
231
+
232
+ Methods
233
+ -------
234
+
235
+ When inheriting from another parent model, methods can optionally be called on
236
+ the parent model automatically as well. To do so, specify the `:methods`
237
+ option when calling `inherits_from`.
238
+
239
+ class Employee < ActiveRecord::Base
240
+ acts_as_superclass
241
+ belongs_to :team
242
+
243
+ def give_raise!(amount)
244
+ update_attribute!(:salary, self.salary + amount)
245
+ puts "Congrats on your well-deserved raise, #{self.first_name}!"
246
+ end
247
+ end
248
+
249
+ class Programmer < ActiveRecord::Base
250
+ inherits_from :employee, :methods => true
251
+ end
252
+
253
+ @programmer = Programmer.first
254
+ @programmer.give_raise!
255
+ # yields: "Congrats on your well-deserved raise, Mike!"
256
+
257
+ NOTE: This is not fully implemented yet as of version 0.1.4. Please wait until
258
+ a future release to prior to using this feature.
@@ -3,5 +3,6 @@ module MultipleTableInheritance
3
3
  extend ActiveSupport::Autoload
4
4
 
5
5
  autoload :Base
6
+ autoload :Sanitizer
6
7
  end
7
8
  end
@@ -2,7 +2,7 @@ module MultipleTableInheritance
2
2
  module Child
3
3
  module Base
4
4
  def self.default_options
5
- { :dependent => :destroy, :inherit_methods => false }
5
+ { :dependent => :destroy, :methods => false }
6
6
  end
7
7
 
8
8
  def self.included(base)
@@ -14,7 +14,7 @@ module MultipleTableInheritance
14
14
  def inherits_from(association_name, options={})
15
15
  # Standardize options, and remove those that should not affect the belongs_to relationship
16
16
  options = Base::default_options.merge(options.to_options)
17
- inherit_methods = options.delete(:inherit_methods)
17
+ inherit_methods = options.delete(:methods)
18
18
 
19
19
  extend FinderMethods, SharedMethods
20
20
  include InstanceMethods, SharedMethods
@@ -39,6 +39,9 @@ module MultipleTableInheritance
39
39
  attr_accessible attr.to_sym
40
40
  end
41
41
 
42
+ # Sanitize attributes across parent and child
43
+ self.mass_assignment_sanitizer = Child::Sanitizer.new(self)
44
+
42
45
  # Bind relationship, handle validation, and save properly.
43
46
  belongs_to parent_association_name, options
44
47
  alias_method_chain parent_association_name, :autobuild
@@ -47,13 +50,13 @@ module MultipleTableInheritance
47
50
  before_save :parent_association_must_be_saved
48
51
  end
49
52
 
50
- private
51
-
52
53
  def parent_association_class
53
54
  reflection = create_reflection(:belongs_to, parent_association_name, {}, self)
54
55
  reflection.klass
55
56
  end
56
57
 
58
+ private
59
+
57
60
  def inherited_columns_and_associations
58
61
  # Get the associated columns and relationship names
59
62
  inherited_columns = parent_association_class.column_names
@@ -78,7 +81,8 @@ module MultipleTableInheritance
78
81
  child_records = super(*args)
79
82
 
80
83
  child_records.each do |child|
81
- child.send(:parent_association=, parent_association_class.as_supertype.find_by_id(child.id))
84
+ parent = parent_association_class.as_supertype.find_by_id(child.id)
85
+ child.send(:parent_association=, parent)
82
86
  end
83
87
  end
84
88
  end
@@ -127,18 +131,17 @@ module MultipleTableInheritance
127
131
  end
128
132
 
129
133
  module DelegateMethods
130
- private
131
-
132
- def method_missing(name, *args)
134
+ def method_missing(name, *args, &block)
133
135
  if parent_association.respond_to?(name)
134
- parent_association.public_send(name, *args)
136
+ parent_association.send(name, *args, &block)
135
137
  else
136
- super(name, *args)
138
+ super(name, *args, &block)
137
139
  end
138
140
  end
139
141
 
140
- def respond_to?(name)
141
- parent_association.respond_to?(name) || super
142
+ def respond_to?(name, *args)
143
+ return true if name.to_sym == :parent_association
144
+ super(name, *args) || parent_association.respond_to?(name)
142
145
  end
143
146
  end
144
147
  end
@@ -0,0 +1,57 @@
1
+ module MultipleTableInheritance
2
+ module Child
3
+ class Sanitizer < ActiveModel::MassAssignmentSecurity::LoggerSanitizer
4
+ def initialize(target)
5
+ @target = target
6
+ super
7
+ end
8
+
9
+ def sanitize(attributes, authorizer)
10
+ sanitized_attributes = attributes.reject { |key, value| deny?(key) }
11
+ debug_protected_attribute_removal(attributes, sanitized_attributes)
12
+ sanitized_attributes
13
+ end
14
+
15
+ protected
16
+
17
+ def deny?(key)
18
+ return true if protected_attribute?(key)
19
+ return !accessible_attribute?(key)
20
+ end
21
+
22
+ def protected_attribute?(key)
23
+ protected_attributes.include?(key)
24
+ end
25
+
26
+ def accessible_attribute?(key)
27
+ return true if accessible_parent_attributes.empty? && parent_attribute_names.include?(key)
28
+ return true if accessible_child_attributes.empty? && child_attribute_names.include?(key)
29
+ accessible_attributes.include?(key)
30
+ end
31
+
32
+ def protected_attributes
33
+ @protected_attributes ||= (@target.protected_attributes + @target.parent_association_class.protected_attributes)
34
+ end
35
+
36
+ def accessible_attributes
37
+ @accessible_attributes ||= (@target.accessible_attributes + @target.parent_association_class.accessible_attributes)
38
+ end
39
+
40
+ def accessible_child_attributes
41
+ @accessible_child_attributes ||= @target.accessible_attributes
42
+ end
43
+
44
+ def accessible_parent_attributes
45
+ @accessible_parent_attributes ||= @target.parent_association_class.accessible_attributes
46
+ end
47
+
48
+ def child_attribute_names
49
+ @child_attribute_names ||= @target.attribute_names
50
+ end
51
+
52
+ def parent_attribute_names
53
+ @parent_attribute_names ||= @target.parent_association_class.attribute_names
54
+ end
55
+ end
56
+ end
57
+ end
@@ -31,7 +31,7 @@ module MultipleTableInheritance
31
31
  child.delete
32
32
  end
33
33
  rescue NameError => e
34
- # TODO log error
34
+ logger.warn "Can't find matching child association for deletion: #{self.class} ##{id}" if logger
35
35
  end
36
36
 
37
37
  def find_by_subtype(*args)
@@ -19,7 +19,7 @@ module MultipleTableInheritance
19
19
  klass = type.constantize
20
20
  child_records += klass.find(ids)
21
21
  rescue NameError => e
22
- # TODO log error
22
+ logger.warn "Can't find matching child association for deletion: #{type} #{ids.inspect}" if logger
23
23
  end
24
24
  end
25
25
 
@@ -1,3 +1,3 @@
1
1
  module MultipleTableInheritance
2
- VERSION = "0.1.3"
2
+ VERSION = "0.1.4"
3
3
  end
@@ -1,92 +1,415 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  describe MultipleTableInheritance::Child do
4
- context 'retrieving records' do
5
- before do
6
- programmer = Programmer.create!(:first_name => 'Bob', :last_name => 'Smith', :salary => 50000)
7
- @programmer_id = programmer.id
8
- @programmer = Programmer.find(@programmer_id)
4
+ context 'non-namespaced classes with default subtype' do
5
+ context 'retrieving records' do
6
+ before do
7
+ programmer = Programmer.create!(:first_name => 'Bob', :last_name => 'Smith', :salary => 50000)
8
+ @programmer_id = programmer.id
9
+ @programmer = Programmer.find(@programmer_id)
10
+ end
11
+
12
+ it 'should retrieve child records' do
13
+ @programmer.should be_instance_of(Programmer)
14
+ @programmer.id.should be(@programmer_id)
15
+ end
16
+
17
+ it 'should allow access to parent record' do
18
+ @programmer.employee.should be_instance_of(Employee)
19
+ @programmer.employee.id.should be(@programmer_id)
20
+ end
9
21
  end
10
22
 
11
- it 'should retrieve child records' do
12
- @programmer.should be_instance_of(Programmer)
13
- @programmer.id.should be(@programmer_id)
23
+ context 'creating records' do
24
+ context 'with mass assignment security' do
25
+ context 'on just child' do
26
+ context 'without assigning all attributes' do
27
+ before(:each) do
28
+ @shirt = Shirt.create(:color => 'Red')
29
+ end
30
+
31
+ it 'should have errors' do
32
+ @shirt.errors.messages.should_not be_empty
33
+ @shirt.errors.messages.keys.should include(:size)
34
+ end
35
+
36
+ it 'should not have been saved' do
37
+ @shirt.should be_new_record
38
+ end
39
+ end
40
+
41
+ context 'with all attributes assigned' do
42
+ before(:each) do
43
+ @shirt = Shirt.create(:color => 'Red', :size => 'XL')
44
+ end
45
+
46
+ it 'should not have errors' do
47
+ @shirt.errors.messages.should be_empty
48
+ end
49
+
50
+ it 'should have been saved' do
51
+ @shirt.should_not be_new_record
52
+ end
53
+ end
54
+ end
55
+
56
+ context 'on just parent' do
57
+ context 'without assigning all attributes' do
58
+ before(:each) do
59
+ @janitor = Janitor.create(:first_name => 'Billy', :last_name => 'McGee')
60
+ end
61
+
62
+ it 'should have errors' do
63
+ @janitor.errors.messages.should_not be_empty
64
+ @janitor.errors.messages.keys.should include(:salary)
65
+ end
66
+
67
+ it 'should not have been saved' do
68
+ @janitor.should be_new_record
69
+ end
70
+ end
71
+
72
+ context 'with all attributes assigned' do
73
+ before(:each) do
74
+ @janitor = Janitor.create(:first_name => 'Billy', :last_name => 'McGee', :salary => 40000, :favorite_cleaner => 'Swiffer')
75
+ end
76
+
77
+ it 'should not have errors' do
78
+ @janitor.errors.messages.should be_empty
79
+ end
80
+
81
+ it 'should have been saved' do
82
+ @janitor.should_not be_new_record
83
+ end
84
+ end
85
+ end
86
+
87
+ context 'on child and parent' do
88
+ context 'with attributes set on instance' do
89
+ before(:each) do
90
+ @programmer = Programmer.create(:first_name => 'Joe', :last_name => 'Schmoe') do |programmer|
91
+ programmer.team = Team.first
92
+ programmer.salary = 45000
93
+ end
94
+ end
95
+
96
+ it 'should not have errors' do
97
+ @programmer.errors.messages.should be_empty
98
+ end
99
+
100
+ it 'should have been saved' do
101
+ @programmer.should_not be_new_record
102
+ end
103
+ end
104
+
105
+ context 'with attributes specified in hash' do
106
+ before(:each) do
107
+ @programmer = Programmer.create(:first_name => 'Joe', :last_name => 'Schmoe', :salary => 45000)
108
+ end
109
+
110
+ it 'should not have errors' do
111
+ @programmer.errors.messages.should be_empty
112
+ end
113
+
114
+ it 'should have been saved' do
115
+ @programmer.should_not be_new_record
116
+ end
117
+ end
118
+ end
119
+ end
120
+
121
+ context 'without mass assignment security' do
122
+ context 'without assigning all attributes' do
123
+ before(:each) do
124
+ @pants = Pants.create(:color => 'Blue', :waist_size => 32)
125
+ end
126
+
127
+ it 'should have errors' do
128
+ @pants.errors.messages.should_not be_empty
129
+ @pants.errors.messages.keys.should include(:length)
130
+ end
131
+
132
+ it 'should not have been saved' do
133
+ @pants.should be_new_record
134
+ end
135
+ end
136
+
137
+ context 'with all attributes assigned' do
138
+ before(:each) do
139
+ @pants = Pants.create(:color => 'Blue', :waist_size => 32, :length => 34)
140
+ end
141
+
142
+ it 'should not have errors' do
143
+ @pants.errors.messages.should be_empty
144
+ end
145
+
146
+ it 'should have been saved' do
147
+ @pants.should_not be_new_record
148
+ end
149
+ end
150
+ end
14
151
  end
15
152
 
16
- it 'should allow access to parent record' do
17
- @programmer.employee.should be_instance_of(Employee)
18
- @programmer.employee.id.should be(@programmer_id)
153
+ context 'updating records' do
154
+ pending "todo"
155
+ end
156
+
157
+ context 'deleting records' do
158
+ before do
159
+ mock_employees!
160
+ @programmer = Programmer.first
161
+ @programmer_id = @programmer.id
162
+ end
163
+
164
+ it 'should delete the parent record' do
165
+ @programmer.destroy
166
+ Employee.find_by_id(@programmer_id).should be_nil
167
+ end
168
+
169
+ it 'should delete the child record' do
170
+ @programmer.destroy.should be_true
171
+ Programmer.find_by_id(@programmer_id).should be_nil
172
+ end
19
173
  end
20
174
  end
21
175
 
22
- context 'creating records' do
23
- context 'with mass assignment security' do
24
- context 'specifying fields that are accessible' do
25
- it 'should assign accessible fields' do
26
- pending "create a model that allows for proper testing"
176
+ context 'namespaced classes with custom subtype' do
177
+ context 'retrieving records' do
178
+ before do
179
+ mock_pets!
180
+ @dog = Pet::Dog.first
181
+ @dog_id = @dog.id
182
+ end
183
+
184
+ it 'should retrieve child records' do
185
+ @dog.should be_instance_of(Pet::Dog)
186
+ @dog.id.should be(@dog_id)
187
+ end
188
+
189
+ it 'should allow access to parent record' do
190
+ @dog.pet.should be_instance_of(Pet::Pet)
191
+ @dog.pet.id.should be(@dog_id)
192
+ end
193
+ end
194
+
195
+ context 'creating records' do
196
+ before(:each) do
197
+ @owner = Pet::Owner.create!(:first_name => 'Bob', :last_name => 'Smith') { |owner| owner.ssn = '123456789' }
198
+ end
199
+
200
+ context 'with mass assignment security' do
201
+ context 'on just child' do
202
+ context 'without assigning all attributes' do
203
+ before(:each) do
204
+ @table = Store::Table.create(:brand => 'Rio', :name => 'Corner Office')
205
+ end
206
+
207
+ it 'should have errors' do
208
+ @table.errors.messages.should_not be_empty
209
+ @table.errors.messages.keys.should include(:color)
210
+ @table.errors.messages.keys.should include(:chairs)
211
+ end
212
+
213
+ it 'should not have been saved' do
214
+ @table.should be_new_record
215
+ end
216
+ end
217
+
218
+ context 'with all attributes assigned' do
219
+ before(:each) do
220
+ @table = Store::Table.create(:brand => 'Rio', :name => 'Corner Office', :color => 'Brown', :chairs => 1)
221
+ end
222
+
223
+ it 'should not have errors' do
224
+ @table.errors.messages.should be_empty
225
+ end
226
+
227
+ it 'should have been saved' do
228
+ @table.should_not be_new_record
229
+ end
230
+ end
27
231
  end
28
232
 
29
- it 'should save child associations' do
30
- pending "create a model that allows for proper testing"
233
+ context 'on just parent' do
234
+ context 'with attributes set on instance' do
235
+ before(:each) do
236
+ @dog = Pet::Dog.create(:name => 'Fido') do |dog|
237
+ dog.owner = @owner
238
+ dog.color = 'black'
239
+ dog.favorite_toy = 'Squeeky Ball'
240
+ end
241
+ end
242
+
243
+ it 'should not have errors' do
244
+ @dog.errors.messages.should be_empty
245
+ end
246
+
247
+ it 'should have been saved' do
248
+ @dog.should_not be_new_record
249
+ end
250
+ end
251
+
252
+ context 'with attributes specified in hash' do
253
+ before(:each) do
254
+ owner = Pet::Owner.create!(:first_name => 'Bob', :last_name => 'Smith') { |owner| owner.ssn = '123456789' }
255
+ @dog = Pet::Dog.create(:name => 'Fido', :color => 'black', :owner => @owner, :favorite_toy => 'Squeeky Ball')
256
+ end
257
+
258
+ it 'should assign accessible fields' do
259
+ @dog.name.should be_present
260
+ end
261
+
262
+ it 'should not assign secure fields' do
263
+ @dog.color.should_not be_present
264
+ @dog.owner.should_not be_present
265
+ @dog.owner_id.should_not be_present
266
+ @dog.favorite_toy.should_not be_present
267
+ end
268
+
269
+ it 'should have errors' do
270
+ @dog.errors.messages.should_not be_empty
271
+ end
272
+
273
+ it 'should not have been saved' do
274
+ @dog.should be_new_record
275
+ end
276
+ end
31
277
  end
32
278
 
33
- it 'should save parent associations' do
34
- pending "create a model that allows for proper testing"
279
+ context 'on child and parent' do
280
+ context 'with attributes set on instance' do
281
+ before(:each) do
282
+ @cat = Pet::Cat.create(:name => 'Mittens', :longest_nap => 100) do |cat|
283
+ cat.owner = @owner
284
+ cat.color = 'orange'
285
+ end
286
+ end
287
+
288
+ it 'should not have errors' do
289
+ @cat.errors.messages.should be_empty
290
+ end
291
+
292
+ it 'should have been saved' do
293
+ @cat.should_not be_new_record
294
+ end
295
+ end
296
+
297
+ context 'with attributes specified in hash' do
298
+ before(:each) do
299
+ @cat = Pet::Cat.create(:name => 'Fido', :color => 'black', :owner => @owner, :longest_nap => 50)
300
+ end
301
+
302
+ it 'should assign accessible fields' do
303
+ @cat.name.should be_present
304
+ @cat.longest_nap.should be_present
305
+ end
306
+
307
+ it 'should not assign secure fields' do
308
+ @cat.color.should_not be_present
309
+ @cat.owner.should_not be_present
310
+ @cat.owner_id.should_not be_present
311
+ end
312
+
313
+ it 'should have errors' do
314
+ @cat.errors.messages.should_not be_empty
315
+ end
316
+
317
+ it 'should not have been saved' do
318
+ @cat.should be_new_record
319
+ end
320
+ end
35
321
  end
36
322
  end
37
323
 
38
- context 'specifying fields that are not accessible' do
39
- it 'should not assign secure fields' do
40
- pending "create a model that allows for proper testing"
41
- end
42
-
43
- it 'should not save child associations' do
44
- pending "create a model that allows for proper testing"
324
+ context 'without mass assignment security' do
325
+ context 'without assigning all attributes' do
326
+ before(:each) do
327
+ @bed = Store::Bed.create(:brand => 'Sealy', :size => 'Queen')
328
+ end
329
+
330
+ it 'should have errors' do
331
+ @bed.errors.messages.should_not be_empty
332
+ @bed.errors.messages.keys.should include(:name)
333
+ end
334
+
335
+ it 'should not have been saved' do
336
+ @bed.should be_new_record
337
+ end
45
338
  end
46
339
 
47
- it 'should not save parent associations' do
48
- pending "create a model that allows for proper testing"
340
+ context 'with all attributes assigned' do
341
+ before(:each) do
342
+ @bed = Store::Bed.create(:brand => 'Sealy', :name => 'Feathertop', :size => 'Queen')
343
+ end
344
+
345
+ it 'should not have errors' do
346
+ @bed.errors.messages.should be_empty
347
+ end
348
+
349
+ it 'should have been saved' do
350
+ @bed.should_not be_new_record
351
+ end
49
352
  end
50
353
  end
51
354
  end
52
- end
53
-
54
- context 'updating records' do
55
- pending "todo"
56
- end
57
-
58
- context 'deleting records' do
59
- before do
60
- mock_employees!
61
- @programmer = Programmer.first
62
- @programmer_id = @programmer.id
63
- end
64
355
 
65
- it 'should delete the parent record' do
66
- @programmer.destroy
67
- Employee.find_by_id(@programmer_id).should be_nil
356
+ context 'updating records' do
357
+ pending "todo"
68
358
  end
69
359
 
70
- it 'should delete the child record' do
71
- @programmer.destroy.should be_true
72
- Programmer.find_by_id(@programmer_id).should be_nil
73
- end
74
- end
75
-
76
- context 'when instructed to inherit parent methods' do
77
- it 'should inherit parent methods' do
78
- pending "todo"
360
+ context 'deleting records' do
361
+ before do
362
+ mock_employees!
363
+ @programmer = Programmer.first
364
+ @programmer_id = @programmer.id
365
+ end
366
+
367
+ it 'should delete the parent record' do
368
+ @programmer.destroy
369
+ Employee.find_by_id(@programmer_id).should be_nil
370
+ end
371
+
372
+ it 'should delete the child record' do
373
+ @programmer.destroy.should be_true
374
+ Programmer.find_by_id(@programmer_id).should be_nil
375
+ end
79
376
  end
80
377
  end
81
378
 
82
379
  context 'methods' do
83
- before do
84
- mock_employees!
380
+ context 'accessing parent methods' do
381
+ context 'on models that allow methods to be inherited' do
382
+ before do
383
+ mock_employees!
384
+ @programmer = Programmer.first
385
+ end
386
+
387
+ it 'should allow parent methods to be called through child' do
388
+ pending "infinite recursion must be addressed"
389
+ # @programmer.should respond_to(:give_raise!)
390
+ end
391
+ end
392
+
393
+ context 'on models that do not allow methods to be inherited' do
394
+ before do
395
+ mock_pets!
396
+ @cat = Pet::Cat.first
397
+ end
398
+
399
+ it 'should not allow parent methods to be called through child' do
400
+ @cat.should_not respond_to(:rename!)
401
+ end
402
+ end
85
403
  end
86
404
 
87
405
  context 'accessing parent records' do
88
406
  before do
89
- @programmer = Programmer.create!(:first_name => 'Bob', :last_name => 'Smith', :salary => 50000)
407
+ @salary = 50000
408
+ @programmer = Programmer.create!(:first_name => 'Bob', :last_name => 'Smith', :salary => @salary)
409
+ end
410
+
411
+ it 'should allow access to parent attribute methods' do
412
+ @programmer.salary.should == @salary
90
413
  end
91
414
 
92
415
  it 'should allow access to parent records' do
@@ -97,6 +420,10 @@ describe MultipleTableInheritance::Child do
97
420
  end
98
421
 
99
422
  context 'searching by id' do
423
+ before do
424
+ mock_employees!
425
+ end
426
+
100
427
  context 'at the class level' do
101
428
  before do
102
429
  @employee_id = Employee.first.id