whorm 0.4.0
Sign up to get free protection for your applications and to get access to all the features.
- data/LICENSE +20 -0
- data/README.rdoc +113 -0
- data/Rakefile +64 -0
- data/VERSION +1 -0
- data/lib/test/macros.rb +20 -0
- data/lib/whorm.rb +15 -0
- data/lib/whorm/adapters/active_record.rb +88 -0
- data/lib/whorm/adapters/data_mapper.rb +66 -0
- data/lib/whorm/adapters/mongo_mapper.rb +64 -0
- data/lib/whorm/model.rb +370 -0
- data/test/active_record_test.rb +0 -0
- data/test/app/config/application.rb +70 -0
- data/test/app/config/database.yml +3 -0
- data/test/app/db/schema.rb +75 -0
- data/test/app/models/active_record/address.rb +4 -0
- data/test/app/models/active_record/data_type.rb +3 -0
- data/test/app/models/active_record/group.rb +4 -0
- data/test/app/models/active_record/house.rb +4 -0
- data/test/app/models/active_record/location.rb +5 -0
- data/test/app/models/active_record/person.rb +4 -0
- data/test/app/models/active_record/user.rb +6 -0
- data/test/app/models/active_record/user_group.rb +4 -0
- data/test/data_mapper_test.rb +0 -0
- data/test/model_test.rb +526 -0
- data/test/mongo_mapper_test.rb +0 -0
- data/test/test_helper.rb +32 -0
- metadata +123 -0
data/lib/whorm/model.rb
ADDED
@@ -0,0 +1,370 @@
|
|
1
|
+
module Whorm
|
2
|
+
module Model
|
3
|
+
|
4
|
+
def self.included(model)
|
5
|
+
model.send(:extend, ClassMethods)
|
6
|
+
model.send(:include, InstanceMethods)
|
7
|
+
##
|
8
|
+
# @config {String} whorm_parent_trail_template This a template used to render mapped field-names.
|
9
|
+
# Default is Proc.new{ |field_name| "_#{field_name}" }
|
10
|
+
# You could also use the Rails standard
|
11
|
+
# Proc.new{ |field_name| "[#{field_name}]" }
|
12
|
+
#
|
13
|
+
model.cattr_accessor :whorm_parent_trail_template
|
14
|
+
model.whorm_parent_trail_template = Proc.new{ |field_name| "_#{field_name}" } if model.whorm_parent_trail_template.nil?
|
15
|
+
end
|
16
|
+
|
17
|
+
##
|
18
|
+
# InstanceMethods
|
19
|
+
#
|
20
|
+
module InstanceMethods
|
21
|
+
|
22
|
+
##
|
23
|
+
# Converts a model instance to a record compatible with javascript applications
|
24
|
+
#
|
25
|
+
# The first parameter should be the fieldset for which the record will be returned.
|
26
|
+
# If no parameter is provided, then the default fieldset will be choosen
|
27
|
+
# Alternativly the first parameter can be a Hash with a :fields member to directly specify
|
28
|
+
# the fields to use for the record.
|
29
|
+
#
|
30
|
+
# All these are valid calls:
|
31
|
+
#
|
32
|
+
# user.to_record # returns record for :default fieldset
|
33
|
+
# # (fieldset is autmatically defined, if not set)
|
34
|
+
#
|
35
|
+
# user.to_record :fieldset # returns record for :fieldset fieldset
|
36
|
+
# # (fieldset is autmatically defined, if not set)
|
37
|
+
#
|
38
|
+
# user.to_record :fields => [:id, :password]
|
39
|
+
# # returns record for the fields 'id' and 'password'
|
40
|
+
#
|
41
|
+
# For even more valid options for this method (which all should not be neccessary to use)
|
42
|
+
# have a look at Whorm::Model::Util.extract_fieldset_and_options
|
43
|
+
def to_record(*params)
|
44
|
+
fieldset, options = Util.extract_fieldset_and_options params
|
45
|
+
|
46
|
+
fields = []
|
47
|
+
if options[:fields].empty?
|
48
|
+
fields = self.class.whorm_get_fields_for_fieldset(fieldset)
|
49
|
+
else
|
50
|
+
fields = self.class.process_fields(*options[:fields])
|
51
|
+
end
|
52
|
+
|
53
|
+
assns = self.class.whorm_associations
|
54
|
+
pk = self.class.whorm_primary_key
|
55
|
+
|
56
|
+
# build the initial field data-hash
|
57
|
+
data = {pk => self.send(pk)}
|
58
|
+
|
59
|
+
fields.each do |field|
|
60
|
+
next if data.has_key? field[:name] # already processed (e.g. explicit mentioning of :id)
|
61
|
+
|
62
|
+
value = nil
|
63
|
+
if association_reflection = assns[field[:name]] # if field is an association
|
64
|
+
association = self.send(field[:name])
|
65
|
+
|
66
|
+
# skip this association if we already visited it
|
67
|
+
# otherwise we could end up in a cyclic reference
|
68
|
+
next if options[:visited_classes].include? association.class
|
69
|
+
|
70
|
+
case association_reflection[:type]
|
71
|
+
when :belongs_to, :has_one
|
72
|
+
if association.respond_to? :to_record
|
73
|
+
assn_fields = field[:fields]
|
74
|
+
if assn_fields.nil?
|
75
|
+
assn_fields = association.class.whorm_get_fields_for_fieldset(field.fetch(:fieldset, fieldset))
|
76
|
+
end
|
77
|
+
|
78
|
+
value = association.to_record :fields => assn_fields,
|
79
|
+
:visited_classes => options[:visited_classes] + [self.class]
|
80
|
+
else
|
81
|
+
value = {}
|
82
|
+
(field[:fields]||[]).each do |sub_field|
|
83
|
+
value[sub_field[:name]] = association.send(sub_field[:name]) if association.respond_to? sub_field[:name]
|
84
|
+
end
|
85
|
+
end
|
86
|
+
if association_reflection[:type] == :belongs_to
|
87
|
+
# Append associations foreign_key to data
|
88
|
+
data[association_reflection[:foreign_key]] = self.send(association_reflection[:foreign_key])
|
89
|
+
if association_reflection[:is_polymorphic]
|
90
|
+
foreign_type = self.class.whorm_polymorphic_type(association_reflection[:foreign_key])
|
91
|
+
data[foreign_type] = self.send(foreign_type)
|
92
|
+
end
|
93
|
+
end
|
94
|
+
when :many
|
95
|
+
value = association.collect { |r| r.to_record } # use carefully, can get HUGE
|
96
|
+
end
|
97
|
+
else # not an association -> get the method's value
|
98
|
+
value = self.send(field[:name])
|
99
|
+
value = value.to_record if value.respond_to? :to_record
|
100
|
+
end
|
101
|
+
data[field[:name]] = value
|
102
|
+
end
|
103
|
+
data
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
##
|
108
|
+
# ClassMethods
|
109
|
+
#
|
110
|
+
module ClassMethods
|
111
|
+
##
|
112
|
+
# render AR columns to Ext.data.Record.create format
|
113
|
+
# eg: {name:'foo', type: 'string'}
|
114
|
+
#
|
115
|
+
# The first parameter should be the fieldset for which the record definition will be returned.
|
116
|
+
# If no parameter is provided, then the default fieldset will be choosen
|
117
|
+
# Alternativly the first parameter can be a Hash with a :fields member to directly specify
|
118
|
+
# the fields to use for the record config.
|
119
|
+
#
|
120
|
+
# All these are valid calls:
|
121
|
+
#
|
122
|
+
# User.whorm_schema # returns record config for :default fieldset
|
123
|
+
# # (fieldset is autmatically defined, if not set)
|
124
|
+
#
|
125
|
+
# User.whorm_schema :fieldset # returns record config for :fieldset fieldset
|
126
|
+
# # (fieldset is autmatically defined, if not set)
|
127
|
+
#
|
128
|
+
# User.whorm_schema :fields => [:id, :password]
|
129
|
+
# # returns record config for the fields 'id' and 'password'
|
130
|
+
#
|
131
|
+
# For even more valid options for this method (which all should not be neccessary to use)
|
132
|
+
# have a look at Whorm::Model::Util.extract_fieldset_and_options
|
133
|
+
def whorm_schema(*params)
|
134
|
+
fieldset, options = Util.extract_fieldset_and_options params
|
135
|
+
|
136
|
+
if options[:fields].empty?
|
137
|
+
fields = self.whorm_get_fields_for_fieldset(fieldset)
|
138
|
+
else
|
139
|
+
fields = self.process_fields(*options[:fields])
|
140
|
+
end
|
141
|
+
|
142
|
+
associations = self.whorm_associations
|
143
|
+
columns = self.whorm_columns_hash
|
144
|
+
pk = self.whorm_primary_key
|
145
|
+
rs = []
|
146
|
+
|
147
|
+
fields.each do |field|
|
148
|
+
|
149
|
+
field = Marshal.load(Marshal.dump(field)) # making a deep copy
|
150
|
+
|
151
|
+
if col = columns[field[:name]] # <-- column on this model
|
152
|
+
rs << self.whorm_field(field, col)
|
153
|
+
elsif assn = associations[field[:name]]
|
154
|
+
# skip this association if we already visited it
|
155
|
+
# otherwise we could end up in a cyclic reference
|
156
|
+
next if options[:visited_classes].include? assn[:class]
|
157
|
+
|
158
|
+
assn_fields = field[:fields]
|
159
|
+
if assn[:class].respond_to?(:whorm_schema) # <-- exec whorm_schema on assn Model.
|
160
|
+
if assn_fields.nil?
|
161
|
+
assn_fields = assn[:class].whorm_get_fields_for_fieldset(field.fetch(:fieldset, fieldset))
|
162
|
+
end
|
163
|
+
|
164
|
+
record = assn[:class].whorm_schema(field.fetch(:fieldset, fieldset), { :visited_classes => options[:visited_classes] + [self], :fields => assn_fields})
|
165
|
+
rs.concat(record[:fields].collect { |assn_field|
|
166
|
+
self.whorm_field(assn_field, :parent_trail => field[:name], :mapping => field[:name], :allowBlank => true) # <-- allowBlank on associated data?
|
167
|
+
})
|
168
|
+
elsif assn_fields # <-- :parent => [:id, :name, :sub => [:id, :name]]
|
169
|
+
field_collector = Proc.new do |parent_trail, mapping, assn_field|
|
170
|
+
if assn_field.is_a?(Hash) && assn_field.keys.size == 1 && assn_field.keys[0].is_a?(Symbol) && assn_field.values[0].is_a?(Array)
|
171
|
+
field_collector.call(parent_trail.to_s + self.whorm_parent_trail_template.call(assn_field.keys.first), "#{mapping}.#{assn_field.keys.first}", assn_field.values.first)
|
172
|
+
else
|
173
|
+
self.whorm_field(assn_field, :parent_trail => parent_trail, :mapping => mapping, :allowBlank => true)
|
174
|
+
end
|
175
|
+
end
|
176
|
+
rs.concat(assn_fields.collect { |assn_field| field_collector.call(field[:name], field[:name], assn_field) })
|
177
|
+
else
|
178
|
+
rs << whorm_field(field)
|
179
|
+
end
|
180
|
+
|
181
|
+
# attach association's foreign_key if not already included.
|
182
|
+
if columns.has_key?(assn[:foreign_key]) && !rs.any? { |r| r[:name] == assn[:foreign_key] }
|
183
|
+
rs << whorm_field({:name => assn[:foreign_key]}, columns[assn[:foreign_key]])
|
184
|
+
end
|
185
|
+
# attach association's type if polymorphic association and not alredy included
|
186
|
+
if assn[:is_polymorphic]
|
187
|
+
foreign_type = self.whorm_polymorphic_type(assn[:foreign_key])
|
188
|
+
if columns.has_key?(foreign_type) && !rs.any? { |r| r[:name] == foreign_type }
|
189
|
+
rs << whorm_field({:name => foreign_type}, columns[foreign_type])
|
190
|
+
end
|
191
|
+
end
|
192
|
+
else # property is a method?
|
193
|
+
rs << whorm_field(field)
|
194
|
+
end
|
195
|
+
end
|
196
|
+
|
197
|
+
return {
|
198
|
+
:fields => rs,
|
199
|
+
:idProperty => pk
|
200
|
+
}
|
201
|
+
end
|
202
|
+
|
203
|
+
##
|
204
|
+
# meant to be used within a Model to define the whorm record fields.
|
205
|
+
# eg:
|
206
|
+
# class User
|
207
|
+
# whorm_fieldset :grid, [:first, :last, :email => {"sortDir" => "ASC"}, :company => [:id, :name]]
|
208
|
+
# end
|
209
|
+
# or
|
210
|
+
# class User
|
211
|
+
# whorm_fieldset :last, :email => {"sortDir" => "ASC"}, :company => [:id, :name] # => implies fieldset name :default
|
212
|
+
# end
|
213
|
+
#
|
214
|
+
def whorm_fieldset(*params)
|
215
|
+
fieldset, options = Util.extract_fieldset_and_options params
|
216
|
+
var_name = :"@whorm_fieldsets__#{fieldset}"
|
217
|
+
self.instance_variable_set( var_name, self.process_fields(*options[:fields]) )
|
218
|
+
end
|
219
|
+
|
220
|
+
def whorm_get_fields_for_fieldset(fieldset)
|
221
|
+
var_name = :"@whorm_fieldsets__#{fieldset}"
|
222
|
+
super_value = nil
|
223
|
+
unless self.instance_variable_get( var_name )
|
224
|
+
if self.superclass.respond_to? :whorm_get_fields_for_fieldset
|
225
|
+
super_value = self.superclass.whorm_get_fields_for_fieldset(fieldset)
|
226
|
+
end
|
227
|
+
self.whorm_fieldset(fieldset, self.whorm_column_names) unless super_value
|
228
|
+
end
|
229
|
+
super_value || self.instance_variable_get( var_name )
|
230
|
+
end
|
231
|
+
|
232
|
+
##
|
233
|
+
# shortcut to define the default fieldset. For backwards-compatibility.
|
234
|
+
#
|
235
|
+
def whorm_fields(*params)
|
236
|
+
self.whorm_fieldset(:default, {
|
237
|
+
:fields => params
|
238
|
+
})
|
239
|
+
end
|
240
|
+
|
241
|
+
##
|
242
|
+
# Prepare a field configuration list into a normalized array of Hashes, {:name => "field_name"}
|
243
|
+
# @param {Mixed} params
|
244
|
+
# @return {Array} of Hashes
|
245
|
+
#
|
246
|
+
def process_fields(*params)
|
247
|
+
fields = []
|
248
|
+
if params.size == 1 && params.last.is_a?(Hash) # peek into argument to see if its an option hash
|
249
|
+
options = params.last
|
250
|
+
if options.has_key?(:additional) && options[:additional].is_a?(Array)
|
251
|
+
return self.process_fields(*(self.whorm_column_names + options[:additional].map(&:to_sym)))
|
252
|
+
elsif options.has_key?(:exclude) && options[:exclude].is_a?(Array)
|
253
|
+
return self.process_fields(*(self.whorm_column_names - options[:exclude].map(&:to_sym)))
|
254
|
+
elsif options.has_key?(:only) && options[:only].is_a?(Array)
|
255
|
+
return self.process_fields(*options[:only])
|
256
|
+
end
|
257
|
+
end
|
258
|
+
|
259
|
+
params = self.whorm_column_names if params.empty?
|
260
|
+
|
261
|
+
associations = whorm_associations
|
262
|
+
|
263
|
+
params.each do |f|
|
264
|
+
if f.kind_of?(Hash)
|
265
|
+
if f.keys.size == 1 && f.keys[0].is_a?(Symbol) && f.values[0].is_a?(Array) # {:association => [:field1, :field2]}
|
266
|
+
fields << {
|
267
|
+
:name => f.keys[0],
|
268
|
+
:fields => process_fields(*f.values[0])
|
269
|
+
}
|
270
|
+
elsif f.keys.size == 1 && f.keys[0].is_a?(Symbol) && f.values[0].is_a?(Hash) # {:field => {:sortDir => 'ASC'}}
|
271
|
+
fields << f.values[0].update(:name => f.keys[0])
|
272
|
+
elsif f.has_key?(:name) # already a valid Hash, just copy it over
|
273
|
+
fields << f
|
274
|
+
else
|
275
|
+
raise ArgumentError, "encountered a Hash that I don't know anything to do with `#{f.inspect}:#{f.class}`"
|
276
|
+
end
|
277
|
+
else # should be a String or Symbol
|
278
|
+
raise ArgumentError, "encountered a fields Array that I don't understand: #{params.inspect} -- `#{f.inspect}:#{f.class}` is not a Symbol or String" unless f.is_a?(Symbol) || f.is_a?(String)
|
279
|
+
fields << {:name => f.to_sym}
|
280
|
+
end
|
281
|
+
end
|
282
|
+
|
283
|
+
fields
|
284
|
+
end
|
285
|
+
|
286
|
+
##
|
287
|
+
# Render a column-config object
|
288
|
+
# @param {Hash/Column} field Field-configuration Hash, probably has :name already set and possibly Ext.data.Field options.
|
289
|
+
# @param {ORM Column Object from AR, DM or MM}
|
290
|
+
#
|
291
|
+
def whorm_field(field, config=nil)
|
292
|
+
if config.kind_of? Hash
|
293
|
+
if config.has_key?(:mapping) && config.has_key?(:parent_trail)
|
294
|
+
field.update( # <-- We use a template for rendering mapped field-names.
|
295
|
+
:name => config[:parent_trail].to_s + self.whorm_parent_trail_template.call(field[:name]),
|
296
|
+
:mapping => "#{config[:mapping]}.#{field[:name]}"
|
297
|
+
)
|
298
|
+
end
|
299
|
+
field.update(config.except(:mapping, :parent_trail))
|
300
|
+
elsif !config.nil? # <-- Hopfully an ORM Column object.
|
301
|
+
field.update(
|
302
|
+
:allowBlank => self.whorm_allow_blank(config),
|
303
|
+
:type => self.whorm_type(config),
|
304
|
+
:defaultValue => self.whorm_default(config)
|
305
|
+
)
|
306
|
+
field[:dateFormat] = "c" if field[:type] === "date" && field[:dateFormat].nil? # <-- ugly hack for date
|
307
|
+
end
|
308
|
+
field.update(:type => "auto") if field[:type].nil?
|
309
|
+
# convert Symbol values to String values
|
310
|
+
field.keys.each do |k|
|
311
|
+
raise ArgumentError, "whorm_field expects a Hash as first parameter with all it's keys Symbols. Found key #{k.inspect}:#{k.class.to_s}" unless k.is_a?(Symbol)
|
312
|
+
field[k] = field[k].to_s if field[k].is_a?(Symbol)
|
313
|
+
end
|
314
|
+
field
|
315
|
+
end
|
316
|
+
|
317
|
+
# ##
|
318
|
+
# # Returns an array of symbolized association names that will be referenced by a call to to_record
|
319
|
+
# # i.e. [:parent1, :parent2]
|
320
|
+
# #
|
321
|
+
# def whorm_used_associations
|
322
|
+
# if @whorm_used_associations.nil?
|
323
|
+
# assoc = []
|
324
|
+
# self.whorm_record_fields.each do |f|
|
325
|
+
# #This needs to be the first condition because the others will break if f is an Array
|
326
|
+
# if whorm_associations[f[:name]]
|
327
|
+
# assoc << f[:name]
|
328
|
+
# end
|
329
|
+
# end
|
330
|
+
# @whorm_used_associations = assoc.uniq
|
331
|
+
# end
|
332
|
+
# @whorm_used_associations
|
333
|
+
# end
|
334
|
+
end
|
335
|
+
|
336
|
+
module Util
|
337
|
+
|
338
|
+
##
|
339
|
+
# returns the fieldset from the arguments and normalizes the options.
|
340
|
+
# @return [{Symbol}, {Hash}]
|
341
|
+
def self.extract_fieldset_and_options arguments
|
342
|
+
orig_args = arguments
|
343
|
+
fieldset = :default
|
344
|
+
options = { # default options
|
345
|
+
:visited_classes => [],
|
346
|
+
:fields => []
|
347
|
+
}
|
348
|
+
if arguments.size > 2 || (arguments.size == 2 && !arguments[0].is_a?(Symbol))
|
349
|
+
raise ArgumentError, "Don't know how to handle #{arguments.inspect}"
|
350
|
+
elsif arguments.size == 2 && arguments[0].is_a?(Symbol)
|
351
|
+
fieldset = arguments.shift
|
352
|
+
if arguments[0].is_a?(Array)
|
353
|
+
options.update({
|
354
|
+
:fields => arguments[0]
|
355
|
+
})
|
356
|
+
elsif arguments[0].is_a?(Hash)
|
357
|
+
options.update(arguments[0])
|
358
|
+
end
|
359
|
+
elsif arguments.size == 1 && (arguments[0].is_a?(Symbol) || arguments[0].is_a?(String))
|
360
|
+
fieldset = arguments.shift.to_sym
|
361
|
+
elsif arguments.size == 1 && arguments[0].is_a?(Hash)
|
362
|
+
fieldset = arguments[0].delete(:fieldset) || :default
|
363
|
+
options.update(arguments[0])
|
364
|
+
end
|
365
|
+
[fieldset, options]
|
366
|
+
end
|
367
|
+
end
|
368
|
+
end
|
369
|
+
end
|
370
|
+
|
File without changes
|
@@ -0,0 +1,70 @@
|
|
1
|
+
# TODO: Figure out how to iterate each ORM framework AR, DM, MM and test each.
|
2
|
+
require 'active_record'
|
3
|
+
require 'active_support'
|
4
|
+
require 'whorm'
|
5
|
+
require 'extlib/inflection'
|
6
|
+
|
7
|
+
gem 'sqlite3-ruby'
|
8
|
+
|
9
|
+
class Test::App
|
10
|
+
|
11
|
+
attr_reader :models
|
12
|
+
|
13
|
+
def initialize(orm = :active_record)
|
14
|
+
@orm = orm
|
15
|
+
@config = YAML::load(IO.read("#{ROOT}/config/database.yml"))
|
16
|
+
|
17
|
+
# Load ORM
|
18
|
+
send("boot_#{orm.to_s}")
|
19
|
+
|
20
|
+
load_models
|
21
|
+
|
22
|
+
require 'db/schema'
|
23
|
+
|
24
|
+
end
|
25
|
+
|
26
|
+
##
|
27
|
+
# Reset a model's @whorm_fieldsets
|
28
|
+
#
|
29
|
+
def clean_all
|
30
|
+
@models.map { |klass| clean klass }
|
31
|
+
end
|
32
|
+
|
33
|
+
|
34
|
+
private
|
35
|
+
|
36
|
+
def boot_active_record
|
37
|
+
ActiveRecord::Base.establish_connection(@config['test'])
|
38
|
+
end
|
39
|
+
|
40
|
+
def boot_mongo_mapper
|
41
|
+
|
42
|
+
end
|
43
|
+
|
44
|
+
def boot_data_mapper
|
45
|
+
|
46
|
+
end
|
47
|
+
|
48
|
+
##
|
49
|
+
# Do a dir on /models and constantize each filename
|
50
|
+
#
|
51
|
+
def load_models
|
52
|
+
@models = []
|
53
|
+
# Load Models and Schema for corresponding orm
|
54
|
+
re = /^.*\/(.*).rb$/
|
55
|
+
Dir["#{ROOT}/models/#{@orm.to_s}/*"].each { |c|
|
56
|
+
require c
|
57
|
+
match = c.match(re)
|
58
|
+
@models << Extlib::Inflection.constantize(Extlib::Inflection.camelize(match[1])) if match
|
59
|
+
}
|
60
|
+
end
|
61
|
+
|
62
|
+
def clean klass
|
63
|
+
klass.instance_variables.each do |var_name|
|
64
|
+
if /\A@whorm_fieldsets__/ =~ var_name.to_s
|
65
|
+
klass.instance_variable_set( var_name.to_sym, nil )
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
end
|
@@ -0,0 +1,75 @@
|
|
1
|
+
|
2
|
+
##
|
3
|
+
# build simple database
|
4
|
+
#
|
5
|
+
# people
|
6
|
+
#
|
7
|
+
ActiveRecord::Base.connection.create_table :users, :force => true do |table|
|
8
|
+
table.column :id, :serial
|
9
|
+
table.column :person_id, :integer
|
10
|
+
table.column :password, :string
|
11
|
+
table.column :created_at, :date
|
12
|
+
table.column :disabled, :boolean, :default => true
|
13
|
+
end
|
14
|
+
##
|
15
|
+
# people
|
16
|
+
#
|
17
|
+
ActiveRecord::Base.connection.create_table :people, :force => true do |table|
|
18
|
+
table.column :id, :serial
|
19
|
+
table.column :first, :string, :null => false
|
20
|
+
table.column :last, :string, :null => false
|
21
|
+
table.column :email, :string, :null => false
|
22
|
+
end
|
23
|
+
##
|
24
|
+
# user_groups, join table
|
25
|
+
#
|
26
|
+
ActiveRecord::Base.connection.create_table :user_groups, :force => true do |table|
|
27
|
+
table.column :user_id, :integer
|
28
|
+
table.column :group_id, :integer
|
29
|
+
end
|
30
|
+
|
31
|
+
##
|
32
|
+
# groups
|
33
|
+
#
|
34
|
+
ActiveRecord::Base.connection.create_table :groups, :force => true do |table|
|
35
|
+
table.column :id, :serial
|
36
|
+
table.column :title, :string
|
37
|
+
end
|
38
|
+
|
39
|
+
##
|
40
|
+
# locations
|
41
|
+
#
|
42
|
+
ActiveRecord::Base.connection.create_table :locations, :force => true do |table|
|
43
|
+
table.column :id, :serial
|
44
|
+
table.column :name, :string
|
45
|
+
table.column :street, :string
|
46
|
+
table.column :type, :string
|
47
|
+
end
|
48
|
+
|
49
|
+
##
|
50
|
+
# addresses
|
51
|
+
#
|
52
|
+
ActiveRecord::Base.connection.create_table :addresses, :force => true do |table|
|
53
|
+
table.column :id, :serial
|
54
|
+
table.column :addressable_type, :string
|
55
|
+
table.column :addressable_id, :integer
|
56
|
+
table.column :street, :string
|
57
|
+
end
|
58
|
+
|
59
|
+
##
|
60
|
+
# Mock a Model for testing data-types
|
61
|
+
#
|
62
|
+
ActiveRecord::Base.connection.create_table :data_types, :force => true do |table|
|
63
|
+
table.column :id, :serial
|
64
|
+
table.column :string_column, :string
|
65
|
+
table.column :decimal_column, :decimal
|
66
|
+
table.column :float_column, :float
|
67
|
+
table.column :date_column, :date
|
68
|
+
table.column :datetime_column, :datetime
|
69
|
+
table.column :time_column, :time
|
70
|
+
table.column :email, :string
|
71
|
+
table.column :integer_column, :integer
|
72
|
+
table.column :notnull_column, :string, :null => false
|
73
|
+
table.column :default_column, :boolean, :default => true
|
74
|
+
table.column :boolean_column, :boolean
|
75
|
+
end
|