dbview_cti 0.0.3 → 0.1.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/CHANGELOG.md ADDED
@@ -0,0 +1,7 @@
1
+ ## 0.1.0 (22/10/2013)
2
+
3
+ * Added transparent support for associations
4
+
5
+ ## 0.0.1
6
+
7
+ * First Release
data/README.md CHANGED
@@ -4,7 +4,8 @@
4
4
  This gem implements [Class Table Inheritance](http://martinfowler.com/eaaCatalog/classTableInheritance.html) (CTI)
5
5
  for Rails, as an alternative to Single Table Inheritance (STI). The implementation is based on database views.
6
6
 
7
- Currently, only PostgreSQL (version >= 9.1) is supported. The gem works for both Rails 3.2 and Rails 4 apps.
7
+ Currently, only PostgreSQL (version >= 9.1) is supported. The gem works for both Rails 3.2 and Rails 4 apps, and on
8
+ MRI (>= 1.9.3), Rubinius and JRuby in 1.9 mode (due to some issues JRuby is not included in the travis tests, though).
8
9
 
9
10
  ## Installation
10
11
 
@@ -142,6 +143,41 @@ After running `rake db:migrate` we can now use our new models, e.g. in the rails
142
143
 
143
144
  Note that Car has all attributes of the vehicles, motor_vehicles and cars tables combined. When saving, the attributes are stored in their corresponding tables.
144
145
 
146
+ ## Initializer
147
+
148
+ When running the migrations and for some of the functionality (see e.g. the `convert_to` and `specialize` methods below),
149
+ it is important that each class knows about the full class hierarchy. This is taken care of automatically when a class
150
+ is loaded. However, in order to have full class hierarchy information all classes in the hierarchy have to be loaded,
151
+ which is not necessarily the case since rails lazy-loads classes (e.g. in development mode).
152
+ Therefore, we have to force loading of all classes by referencing the leaf-classes in the hierarchy in an initializer.
153
+
154
+ For the example given above the leaf classes are Car and MotorCycle, so we put the following in an initializer (e.g. in
155
+ `config/initializers/dbview_cti.rb`):
156
+
157
+ ```ruby
158
+ # Force loading of all classes in the CTI hierachy by referencing the leaf classes here
159
+ Car
160
+ MotorCycle
161
+ ```
162
+
163
+ In development mode, Rails reloads files as you modify them. If a file in the class hierarchy is modified, all classes
164
+ have to be reloaded, otherwise methods such as `specialize` and `convert_to` (see below) will no longer work correctly.
165
+ To make sure the whole hierarchy is reloaded at every request (in development) we can modify the above initializer to:
166
+
167
+ ```ruby
168
+ # this block makes rails reload the code after each request in development mode
169
+ Rails.configuration.to_prepare do
170
+ # Force loading of all classes in the CTI hierachy by referencing the leaf classes here
171
+ Car
172
+ MotorCycle
173
+ end
174
+ ```
175
+
176
+ ## Associations
177
+
178
+ Associations (`has_many`, `has_one`, etc.) work and are inherited as you would expect. The only caveat is that
179
+ in Rails 4 it might be necessary to explicitly specify the join table when using `has_and_belongs_to_many`.
180
+
145
181
  ## API
146
182
 
147
183
  ### Models
@@ -211,8 +247,11 @@ The `change` syntax is not (yet?) supported for recreating database views.
211
247
 
212
248
  ## Notes
213
249
 
214
- * Using dbview_cti doesn't interfere with foreign key constraints. In fact, I recommend adding foreign key constraints
250
+ * Using dbview_cti doesn't interfere with foreign key constraints. In fact, I highly recommend adding foreign key constraints
215
251
  between the tables in a CTI hierarchy (e.g. using [foreigner](https://github.com/matthuhiggins/foreigner)).
252
+ * When creating foreign key constraints involving tables that are part of the hierarchy, always refer to the tables
253
+ themselves, not the views. When modifying the models in future migrations, the views may need to be recreated, which
254
+ would cause problems with the foreign key constraints.
216
255
  * Take care when using database id's. Since the data for a Car object is spread over several tables,
217
256
  the id of a Car instance will generally be different than the id of the MotorVehicle instance you get when you
218
257
  convert the Car instance to a MotorVehicle.
@@ -112,7 +112,62 @@ module DBViewCTI
112
112
  @cti_descendants ||= {}
113
113
  @cti_descendants.each(&block)
114
114
  result
115
- end
115
+ end
116
+
117
+ # redefine association class methods (except for belongs_to)
118
+ [:has_many, :has_and_belongs_to_many, :has_one].each do |name|
119
+ self.class_eval <<-eos, __FILE__, __LINE__+1
120
+ def #{name}(*args)
121
+ cti_initialize_cti_associations
122
+ @cti_associations[:#{name}] << args.first
123
+ super
124
+ end
125
+ eos
126
+ end
127
+
128
+ # redefine associations defined in ascendant classes so they keep working
129
+ def cti_redefine_associations
130
+ @cti_ascendants.each do |ascendant|
131
+ [:has_many, :has_and_belongs_to_many].each do |association_type|
132
+ ascendant.constantize.cti_associations[association_type].each do |association|
133
+ cti_redefine_to_many(ascendant, association)
134
+ end
135
+ end
136
+ ascendant.constantize.cti_associations[:has_one].each do |association|
137
+ cti_redefine_has_one(ascendant, association)
138
+ end
139
+ end
140
+ end
141
+
142
+ # redefine has_many and has_and_belongs_to_many association
143
+ def cti_redefine_to_many(class_name, association)
144
+ plural = association.to_s
145
+ singular = association.to_s.singularize
146
+ [ plural, "#{plural}=", "#{singular}_ids", "#{singular}_ids=" ].each do |name|
147
+ cti_redefine_single_association(name, class_name)
148
+ end
149
+ end
150
+
151
+ # redefine has_many and has_and_belongs_to_many association
152
+ def cti_redefine_has_one(class_name, association)
153
+ singular = association
154
+ [ association, "#{association}=", "build_#{association}", "create_#{association}", "create_#{association}!" ].each do |name|
155
+ cti_redefine_single_association(name, class_name)
156
+ end
157
+ end
158
+
159
+ def cti_redefine_single_association(name, class_name)
160
+ self.class_eval <<-eos, __FILE__, __LINE__+1
161
+ def #{name}(*args)
162
+ self.convert_to('#{class_name}').send('#{name}', *args)
163
+ end
164
+ eos
165
+ end
166
+
167
+ def cti_associations
168
+ cti_initialize_cti_associations
169
+ @cti_associations
170
+ end
116
171
 
117
172
  include DBViewCTI::SQLGeneration::Model
118
173
 
@@ -123,6 +178,13 @@ module DBViewCTI
123
178
  result[0]['count'].to_i
124
179
  end
125
180
 
181
+ def cti_initialize_cti_associations
182
+ @cti_associations ||= {}
183
+ [:has_many, :has_and_belongs_to_many, :has_one].each do |name|
184
+ @cti_associations[name] ||= []
185
+ end
186
+ end
187
+
126
188
  end
127
189
  end
128
190
  end
@@ -17,6 +17,7 @@ module DBViewCTI
17
17
  @cti_derived_class = true
18
18
  self.table_name = DBViewCTI::Names.view_name(self)
19
19
  self.superclass.cti_register_descendants(self.name)
20
+ cti_redefine_associations
20
21
  end
21
22
 
22
23
  end
@@ -13,8 +13,12 @@ module DBViewCTI
13
13
  base_classes = []
14
14
  @connection.tables.sort.each do |table|
15
15
  next if ignore_table?(table)
16
- klass = DBViewCTI::Names.table_to_class_name(table).constantize
17
- base_classes << klass if klass.respond_to?('cti_base_class?') && klass.cti_base_class?
16
+ begin
17
+ klass = DBViewCTI::Names.table_to_class_name(table).constantize
18
+ base_classes << klass if klass.respond_to?('cti_base_class?') && klass.cti_base_class?
19
+ rescue NameError
20
+ # do nothing
21
+ end
18
22
  end
19
23
  base_classes.each do |klass|
20
24
  dump_cti_hierarchy(klass, stream)
@@ -1,3 +1,3 @@
1
1
  module DBViewCTI
2
- VERSION = "0.0.3"
2
+ VERSION = "0.1.0"
3
3
  end
@@ -0,0 +1,5 @@
1
+ class Astronaut < ActiveRecord::Base
2
+ attr_accessible :name unless Rails::VERSION::MAJOR > 3
3
+
4
+ has_and_belongs_to_many :space_ships, :join_table => 'astronauts_space_ships'
5
+ end
@@ -0,0 +1,5 @@
1
+ class Captain < ActiveRecord::Base
2
+ attr_accessible :spache_ship_id, :name unless Rails::VERSION::MAJOR > 3
3
+
4
+ belongs_to :space_ship
5
+ end
@@ -0,0 +1,6 @@
1
+ class Experiment < ActiveRecord::Base
2
+ attr_accessible :name unless Rails::VERSION::MAJOR > 3
3
+
4
+ has_many :experiment_space_ship_performances
5
+ has_many :space_ships, :through => :experiment_space_ship_performances
6
+ end
@@ -0,0 +1,6 @@
1
+ class ExperimentSpaceShipPerformance < ActiveRecord::Base
2
+ attr_accessible :performed_at unless Rails::VERSION::MAJOR > 3
3
+
4
+ belongs_to :experiment
5
+ belongs_to :space_ship
6
+ end
@@ -0,0 +1,5 @@
1
+ class Launch < ActiveRecord::Base
2
+ attr_accessible :spache_ship_id, :date unless Rails::VERSION::MAJOR > 3
3
+
4
+ belongs_to :launch
5
+ end
@@ -1,4 +1,10 @@
1
1
  class SpaceShip < Vehicle
2
2
  attr_accessible :single_use, :reliability unless Rails::VERSION::MAJOR > 3
3
3
  cti_derived_class
4
+
5
+ has_many :launches
6
+ has_one :captain
7
+ has_and_belongs_to_many :astronauts, :join_table => 'astronauts_space_ships'
8
+ has_many :experiment_space_ship_performances
9
+ has_many :experiments, :through => :experiment_space_ship_performances
4
10
  end
@@ -0,0 +1,12 @@
1
+ class CreateLaunches < ActiveRecord::Migration
2
+ def change
3
+ create_table :launches do |t|
4
+ t.references :space_ship
5
+ t.date :date
6
+
7
+ t.timestamps
8
+ end
9
+
10
+ add_foreign_key(:launches, :space_ships)
11
+ end
12
+ end
@@ -0,0 +1,12 @@
1
+ class CreateCaptains < ActiveRecord::Migration
2
+ def change
3
+ create_table :captains do |t|
4
+ t.references :space_ship
5
+ t.string :name
6
+
7
+ t.timestamps
8
+ end
9
+
10
+ add_foreign_key(:captains, :space_ships)
11
+ end
12
+ end
@@ -0,0 +1,9 @@
1
+ class CreateAstronauts < ActiveRecord::Migration
2
+ def change
3
+ create_table :astronauts do |t|
4
+ t.string :name
5
+
6
+ t.timestamps
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,11 @@
1
+ class CreateHabtmJoinTable < ActiveRecord::Migration
2
+ def change
3
+ create_table :astronauts_space_ships, id: false do |t|
4
+ t.integer :astronaut_id
5
+ t.integer :space_ship_id
6
+ end
7
+
8
+ add_foreign_key(:astronauts_space_ships, :astronauts)
9
+ add_foreign_key(:astronauts_space_ships, :space_ships)
10
+ end
11
+ end
@@ -0,0 +1,9 @@
1
+ class CreateExperiments < ActiveRecord::Migration
2
+ def change
3
+ create_table :experiments do |t|
4
+ t.string :name
5
+
6
+ t.timestamps
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,14 @@
1
+ class CreateExperimentSpaceShipPerformances < ActiveRecord::Migration
2
+ def change
3
+ create_table :experiment_space_ship_performances do |t|
4
+ t.references :experiment
5
+ t.references :space_ship
6
+ t.date :performed_at
7
+
8
+ t.timestamps
9
+ end
10
+
11
+ add_foreign_key(:experiment_space_ship_performances, :experiments)
12
+ add_foreign_key(:experiment_space_ship_performances, :space_ships)
13
+ end
14
+ end
@@ -0,0 +1,129 @@
1
+ # encoding: UTF-8
2
+ # This file is auto-generated from the current state of the database. Instead
3
+ # of editing this file, please use the migrations feature of Active Record to
4
+ # incrementally modify your database, and then regenerate this schema definition.
5
+ #
6
+ # Note that this schema.rb definition is the authoritative source for your
7
+ # database schema. If you need to create the application database on another
8
+ # system, you should be using db:schema:load, not running all the migrations
9
+ # from scratch. The latter is a flawed and unsustainable approach (the more migrations
10
+ # you'll amass, the slower it'll run and the greater likelihood for issues).
11
+ #
12
+ # It's strongly recommended to check this file into your version control system.
13
+
14
+ ActiveRecord::Schema.define(:version => 20131022030720) do
15
+
16
+ create_table "astronauts", :force => true do |t|
17
+ t.string "name"
18
+ t.datetime "created_at", :null => false
19
+ t.datetime "updated_at", :null => false
20
+ end
21
+
22
+ create_table "astronauts_space_ships", :id => false, :force => true do |t|
23
+ t.integer "astronaut_id"
24
+ t.integer "space_ship_id"
25
+ end
26
+
27
+ create_table "captains", :force => true do |t|
28
+ t.integer "space_ship_id"
29
+ t.string "name"
30
+ t.datetime "created_at", :null => false
31
+ t.datetime "updated_at", :null => false
32
+ end
33
+
34
+ create_table "cars", :force => true do |t|
35
+ t.integer "motor_vehicle_id"
36
+ t.boolean "stick_shift"
37
+ t.boolean "convertible"
38
+ t.datetime "created_at", :null => false
39
+ t.datetime "updated_at", :null => false
40
+ end
41
+
42
+ create_table "experiment_space_ship_performances", :force => true do |t|
43
+ t.integer "experiment_id"
44
+ t.integer "space_ship_id"
45
+ t.date "performed_at"
46
+ t.datetime "created_at", :null => false
47
+ t.datetime "updated_at", :null => false
48
+ end
49
+
50
+ create_table "experiments", :force => true do |t|
51
+ t.string "name"
52
+ t.datetime "created_at", :null => false
53
+ t.datetime "updated_at", :null => false
54
+ end
55
+
56
+ create_table "launches", :force => true do |t|
57
+ t.integer "space_ship_id"
58
+ t.date "date"
59
+ t.datetime "created_at", :null => false
60
+ t.datetime "updated_at", :null => false
61
+ end
62
+
63
+ create_table "motor_cycles", :force => true do |t|
64
+ t.integer "motor_vehicle_id"
65
+ t.boolean "offroad"
66
+ t.datetime "created_at", :null => false
67
+ t.datetime "updated_at", :null => false
68
+ end
69
+
70
+ create_table "motor_vehicles", :force => true do |t|
71
+ t.integer "vehicle_id"
72
+ t.string "fuel"
73
+ t.integer "number_of_wheels"
74
+ t.datetime "created_at", :null => false
75
+ t.datetime "updated_at", :null => false
76
+ end
77
+
78
+ create_table "rocket_engines", :force => true do |t|
79
+ t.integer "space_ship_id"
80
+ t.string "name"
81
+ t.datetime "created_at", :null => false
82
+ t.datetime "updated_at", :null => false
83
+ end
84
+
85
+ create_table "space_ships", :force => true do |t|
86
+ t.integer "vehicle_id"
87
+ t.boolean "single_use"
88
+ t.datetime "created_at", :null => false
89
+ t.datetime "updated_at", :null => false
90
+ t.integer "reliability"
91
+ end
92
+
93
+ create_table "space_shuttles", :force => true do |t|
94
+ t.integer "space_ship_id"
95
+ t.integer "power"
96
+ t.datetime "created_at", :null => false
97
+ t.datetime "updated_at", :null => false
98
+ end
99
+
100
+ create_table "vehicles", :force => true do |t|
101
+ t.string "name"
102
+ t.integer "mass"
103
+ t.datetime "created_at", :null => false
104
+ t.datetime "updated_at", :null => false
105
+ end
106
+
107
+ cti_create_view('MotorVehicle')
108
+ cti_create_view('Car')
109
+ cti_create_view('MotorCycle')
110
+ cti_create_view('SpaceShip')
111
+ cti_create_view('SpaceShuttle')
112
+
113
+ add_foreign_key "astronauts_space_ships", "astronauts", :name => "astronauts_space_ships_astronaut_id_fk"
114
+ add_foreign_key "astronauts_space_ships", "space_ships", :name => "astronauts_space_ships_space_ship_id_fk"
115
+
116
+ add_foreign_key "captains", "space_ships", :name => "captains_space_ship_id_fk"
117
+
118
+ add_foreign_key "experiment_space_ship_performances", "experiments", :name => "experiment_space_ship_performances_experiment_id_fk"
119
+ add_foreign_key "experiment_space_ship_performances", "space_ships", :name => "experiment_space_ship_performances_space_ship_id_fk"
120
+
121
+ add_foreign_key "launches", "space_ships", :name => "launches_space_ship_id_fk"
122
+
123
+ add_foreign_key "rocket_engines", "space_ships", :name => "rocket_engines_space_ship_id_fk"
124
+
125
+ add_foreign_key "space_ships", "vehicles", :name => "space_ships_vehicle_id_fk"
126
+
127
+ add_foreign_key "space_shuttles", "space_ships", :name => "space_shuttles_space_ship_id_fk"
128
+
129
+ end
@@ -0,0 +1,112 @@
1
+ # encoding: UTF-8
2
+ # This file is auto-generated from the current state of the database. Instead
3
+ # of editing this file, please use the migrations feature of Active Record to
4
+ # incrementally modify your database, and then regenerate this schema definition.
5
+ #
6
+ # Note that this schema.rb definition is the authoritative source for your
7
+ # database schema. If you need to create the application database on another
8
+ # system, you should be using db:schema:load, not running all the migrations
9
+ # from scratch. The latter is a flawed and unsustainable approach (the more migrations
10
+ # you'll amass, the slower it'll run and the greater likelihood for issues).
11
+ #
12
+ # It's strongly recommended that you check this file into your version control system.
13
+
14
+ ActiveRecord::Schema.define(version: 20131022020655) do
15
+
16
+ create_table "astronauts", force: true do |t|
17
+ t.string "name"
18
+ t.datetime "created_at"
19
+ t.datetime "updated_at"
20
+ end
21
+
22
+ create_table "astronauts_space_ships", id: false, force: true do |t|
23
+ t.integer "astronaut_id"
24
+ t.integer "space_ship_id"
25
+ end
26
+
27
+ create_table "captains", force: true do |t|
28
+ t.integer "space_ship_id"
29
+ t.string "name"
30
+ t.datetime "created_at"
31
+ t.datetime "updated_at"
32
+ end
33
+
34
+ create_table "cars", force: true do |t|
35
+ t.integer "motor_vehicle_id"
36
+ t.boolean "stick_shift"
37
+ t.boolean "convertible"
38
+ t.datetime "created_at"
39
+ t.datetime "updated_at"
40
+ end
41
+
42
+ create_table "launches", force: true do |t|
43
+ t.integer "space_ship_id"
44
+ t.date "date"
45
+ t.datetime "created_at"
46
+ t.datetime "updated_at"
47
+ end
48
+
49
+ create_table "motor_cycles", force: true do |t|
50
+ t.integer "motor_vehicle_id"
51
+ t.boolean "offroad"
52
+ t.datetime "created_at"
53
+ t.datetime "updated_at"
54
+ end
55
+
56
+ create_table "motor_vehicles", force: true do |t|
57
+ t.integer "vehicle_id"
58
+ t.string "fuel"
59
+ t.integer "number_of_wheels"
60
+ t.datetime "created_at"
61
+ t.datetime "updated_at"
62
+ end
63
+
64
+ create_table "rocket_engines", force: true do |t|
65
+ t.integer "space_ship_id"
66
+ t.string "name"
67
+ t.datetime "created_at"
68
+ t.datetime "updated_at"
69
+ end
70
+
71
+ create_table "space_ships", force: true do |t|
72
+ t.integer "vehicle_id"
73
+ t.boolean "single_use"
74
+ t.datetime "created_at"
75
+ t.datetime "updated_at"
76
+ t.integer "reliability"
77
+ end
78
+
79
+ create_table "space_shuttles", force: true do |t|
80
+ t.integer "space_ship_id"
81
+ t.integer "power"
82
+ t.datetime "created_at"
83
+ t.datetime "updated_at"
84
+ end
85
+
86
+ create_table "vehicles", force: true do |t|
87
+ t.string "name"
88
+ t.integer "mass"
89
+ t.datetime "created_at"
90
+ t.datetime "updated_at"
91
+ end
92
+
93
+ cti_create_view('MotorVehicle')
94
+ cti_create_view('Car')
95
+ cti_create_view('MotorCycle')
96
+ cti_create_view('SpaceShip')
97
+ cti_create_view('SpaceShuttle')
98
+
99
+ add_foreign_key "astronauts_space_ships", "astronauts", :name => "astronauts_space_ships_astronaut_id_fk"
100
+ add_foreign_key "astronauts_space_ships", "space_ships", :name => "astronauts_space_ships_space_ship_id_fk"
101
+
102
+ add_foreign_key "captains", "space_ships", :name => "captains_space_ship_id_fk"
103
+
104
+ add_foreign_key "launches", "space_ships", :name => "launches_space_ship_id_fk"
105
+
106
+ add_foreign_key "rocket_engines", "space_ships", :name => "rocket_engines_space_ship_id_fk"
107
+
108
+ add_foreign_key "space_ships", "vehicles", :name => "space_ships_vehicle_id_fk"
109
+
110
+ add_foreign_key "space_shuttles", "space_ships", :name => "space_shuttles_space_ship_id_fk"
111
+
112
+ end
@@ -19,4 +19,104 @@ describe SpaceShuttle do
19
19
  shuttle.convert_to(:space_ship).reliability.should eq 100
20
20
  end
21
21
 
22
+ it "can use has_many associations defined in ascendant classes" do
23
+ # create dummy space ships to make sure the shuttle we'll cereate has a different database id than
24
+ # its associated spaceship
25
+ (1..2).map { SpaceShip.create }
26
+ shuttle = SpaceShuttle.create(:name => 'Discovery', :reliability => 100)
27
+ shuttle.id.should_not eq shuttle.convert_to(:space_ship).id
28
+ # test has_many functionality
29
+ launch1 = Launch.new(:date => Date.today)
30
+ launch2 = Launch.new(:date => Date.tomorrow)
31
+ launch3 = Launch.new(:date => Date.tomorrow)
32
+ expect {
33
+ shuttle.launches << launch1
34
+ shuttle.save!
35
+ }.to change(Launch, :count).by(1)
36
+ expect {
37
+ shuttle.launches = [ launch1, launch2 ]
38
+ shuttle.save!
39
+ }.to change(Launch, :count).by(1)
40
+ shuttle.launch_ids.sort.should eq [ launch1.id, launch2.id ]
41
+ launch3.save!
42
+ shuttle.launch_ids = [ launch1.id, launch3.id ]
43
+ shuttle.launch_ids.sort.should eq [ launch1.id, launch3.id ]
44
+ end
45
+
46
+ it "can use has_many :through associations defined in ascendant classes" do
47
+ # create dummy space ships to make sure the shuttle we'll cereate has a different database id than
48
+ # its associated spaceship
49
+ (1..2).map { SpaceShip.create }
50
+ shuttle = SpaceShuttle.create(:name => 'Discovery', :reliability => 100)
51
+ shuttle.id.should_not eq shuttle.convert_to(:space_ship).id
52
+ # test has_many functionality
53
+ experiment1 = Experiment.new(:name => 'Zero-gravity')
54
+ experiment2 = Experiment.new(:name => 'Physics 101')
55
+ experiment3 = Experiment.new(:name => 'Cell growth')
56
+ expect {
57
+ shuttle.experiments << experiment1
58
+ shuttle.save!
59
+ }.to change(Experiment, :count).by(1)
60
+ expect {
61
+ shuttle.experiments = [ experiment1, experiment2 ]
62
+ shuttle.save!
63
+ }.to change(Experiment, :count).by(1)
64
+ shuttle.experiment_ids.sort.should eq [ experiment1.id, experiment2.id ]
65
+ experiment3.save!
66
+ shuttle.experiment_ids = [ experiment1.id, experiment3.id ]
67
+ shuttle.experiment_ids.sort.should eq [ experiment1.id, experiment3.id ]
68
+ Experiment.last.space_ships.first.specialize.id.should eq shuttle.id
69
+ end
70
+
71
+ it "can use has_one associations defined in ascendant classes" do
72
+ # create dummy space ships to make sure the shuttle we'll cereate has a different database id than
73
+ # its associated captain
74
+ (1..2).map { SpaceShip.create }
75
+ shuttle = SpaceShuttle.create(:name => 'Discovery', :reliability => 100)
76
+ shuttle.id.should_not eq shuttle.convert_to(:space_ship).id
77
+ # test has_one functionality
78
+ captain = Captain.new(:name => 'Armstrong')
79
+ expect {
80
+ shuttle.captain = captain
81
+ shuttle.save!
82
+ }.to change(Captain, :count).by(1)
83
+ shuttle.reload
84
+ shuttle.captain.id.should eq captain.id
85
+ shuttle.captain.destroy
86
+ expect {
87
+ shuttle.create_captain(:name => 'Glenn')
88
+ }.to change(Captain, :count).by(1)
89
+ shuttle.captain.space_ship_id.should eq shuttle.convert_to(:space_ship).id
90
+ expect {
91
+ cap = shuttle.build_captain(:name => 'Aldrinn')
92
+ cap.save!
93
+ }.to change(Captain, :count).by(1)
94
+ shuttle.captain.space_ship_id.should eq shuttle.convert_to(:space_ship).id
95
+ end
96
+
97
+ it "can use has_and_belongs_to_many associations defined in ascendant classes" do
98
+ # create dummy space ships to make sure the shuttle we'll cereate has a different database id than
99
+ # its associated spaceship
100
+ (1..2).map { SpaceShip.create }
101
+ shuttle = SpaceShuttle.create(:name => 'Discovery', :reliability => 100)
102
+ shuttle.id.should_not eq shuttle.convert_to(:space_ship).id
103
+ # test has_and_belongs_to_many functionality
104
+ astronaut1 = Astronaut.new(:name => 'Armstrong')
105
+ astronaut2 = Astronaut.new(:name => 'Glenn')
106
+ astronaut3 = Astronaut.new(:name => 'Gagarin')
107
+ expect {
108
+ shuttle.astronauts << astronaut1
109
+ shuttle.save!
110
+ }.to change(Astronaut, :count).by(1)
111
+ shuttle.astronauts.first.name.should eq astronaut1.name
112
+ expect {
113
+ shuttle.astronauts = [ astronaut1, astronaut2 ]
114
+ shuttle.save!
115
+ }.to change(Astronaut, :count).by(1)
116
+ shuttle.astronaut_ids.sort.should eq [ astronaut1.id, astronaut2.id ]
117
+ astronaut3.save!
118
+ shuttle.astronaut_ids = [ astronaut1.id, astronaut3.id ]
119
+ shuttle.astronaut_ids.sort.should eq [ astronaut1.id, astronaut3.id ]
120
+ end
121
+
22
122
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: dbview_cti
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.3
4
+ version: 0.1.0
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2013-08-28 00:00:00.000000000 Z
12
+ date: 2013-10-22 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: rails
@@ -69,6 +69,7 @@ extra_rdoc_files: []
69
69
  files:
70
70
  - .gitignore
71
71
  - .travis.yml
72
+ - CHANGELOG.md
72
73
  - Gemfile
73
74
  - MIT-LICENSE
74
75
  - README.md
@@ -99,7 +100,12 @@ files:
99
100
  - spec/dummy-rails-3/app/helpers/application_helper.rb
100
101
  - spec/dummy-rails-3/app/mailers/.gitkeep
101
102
  - spec/dummy-rails-3/app/models/.gitkeep
103
+ - spec/dummy-rails-3/app/models/astronaut.rb
104
+ - spec/dummy-rails-3/app/models/captain.rb
102
105
  - spec/dummy-rails-3/app/models/car.rb
106
+ - spec/dummy-rails-3/app/models/experiment.rb
107
+ - spec/dummy-rails-3/app/models/experiment_space_ship_performance.rb
108
+ - spec/dummy-rails-3/app/models/launch.rb
103
109
  - spec/dummy-rails-3/app/models/motor_cycle.rb
104
110
  - spec/dummy-rails-3/app/models/motor_vehicle.rb
105
111
  - spec/dummy-rails-3/app/models/rocket_engine.rb
@@ -132,6 +138,13 @@ files:
132
138
  - spec/dummy-rails-3/db/migrate/20130817014120_create_space_shuttles.rb
133
139
  - spec/dummy-rails-3/db/migrate/20130817024220_create_rocket_engines.rb
134
140
  - spec/dummy-rails-3/db/migrate/20130819040414_add_reliability_to_space_ships.rb
141
+ - spec/dummy-rails-3/db/migrate/20131021211442_create_launches.rb
142
+ - spec/dummy-rails-3/db/migrate/20131022010731_create_captains.rb
143
+ - spec/dummy-rails-3/db/migrate/20131022020536_create_astronauts.rb
144
+ - spec/dummy-rails-3/db/migrate/20131022020655_create_habtm_join_table.rb
145
+ - spec/dummy-rails-3/db/migrate/20131022030659_create_experiments.rb
146
+ - spec/dummy-rails-3/db/migrate/20131022030720_create_experiment_space_ship_performances.rb
147
+ - spec/dummy-rails-3/db/schema.rb
135
148
  - spec/dummy-rails-3/lib/assets/.gitkeep
136
149
  - spec/dummy-rails-3/log/.gitkeep
137
150
  - spec/dummy-rails-3/public/404.html
@@ -170,6 +183,7 @@ files:
170
183
  - spec/dummy-rails-4/config/initializers/wrap_parameters.rb
171
184
  - spec/dummy-rails-4/config/locales/en.yml
172
185
  - spec/dummy-rails-4/config/routes.rb
186
+ - spec/dummy-rails-4/db/schema.rb
173
187
  - spec/dummy-rails-4/lib/assets/.keep
174
188
  - spec/dummy-rails-4/log/.keep
175
189
  - spec/dummy-rails-4/public/404.html
@@ -196,7 +210,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
196
210
  version: '0'
197
211
  segments:
198
212
  - 0
199
- hash: 3838779478172072654
213
+ hash: -2732780512702174148
200
214
  required_rubygems_version: !ruby/object:Gem::Requirement
201
215
  none: false
202
216
  requirements:
@@ -205,7 +219,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
205
219
  version: '0'
206
220
  segments:
207
221
  - 0
208
- hash: 3838779478172072654
222
+ hash: -2732780512702174148
209
223
  requirements: []
210
224
  rubyforge_project:
211
225
  rubygems_version: 1.8.25