extjs-mvc 0.2.8 → 0.3.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/README.rdoc +51 -5
- data/Rakefile +5 -2
- data/VERSION +1 -1
- data/lib/extjs-mvc.rb +0 -6
- data/lib/model/active_record.rb +38 -20
- data/lib/model/base.rb +181 -118
- data/lib/model/data_mapper.rb +2 -1
- data/lib/model/mongo_mapper.rb +2 -1
- data/test/debug.log +390 -0
- data/test/model_test.rb +342 -26
- data/test/{mongo_mapper.rb → mongo_mapper_test.rb} +0 -0
- data/test/test_helper.rb +45 -2
- metadata +15 -5
data/README.rdoc
CHANGED
@@ -45,15 +45,42 @@ fields with will be used to render the <tt>Ext.data.Record.create</tt> field-def
|
|
45
45
|
|
46
46
|
After including the model mixin <tt>ExtJS::Model</tt>, try typing the following in <tt>irb</tt> console:
|
47
47
|
>> User.extjs_record
|
48
|
-
=> {
|
49
|
-
{:type
|
50
|
-
{:type
|
51
|
-
{:type
|
52
|
-
{:type
|
48
|
+
=> { :idProperty=>"id", :fields=>[
|
49
|
+
{:type=>'int', :allowBlank=>true, :name=>"id"},
|
50
|
+
{:type=>'string', :allowBlank=>false, :name=>"first", :defaultValue => nil},
|
51
|
+
{:type=>'string', :allowBlank=>false, :name=>"last", :defaultValue => nil},
|
52
|
+
{:type=>'string', :allowBlank=>false, :name=>"email", :defaultValue => nil}
|
53
53
|
]}
|
54
54
|
|
55
55
|
An auto-generated <tt>Ext.data.JsonReader</tt> configuration!
|
56
56
|
|
57
|
+
|
58
|
+
You can also define different sets of fields for different representation of your model.
|
59
|
+
|
60
|
+
E.g. with the following definition:
|
61
|
+
|
62
|
+
class User < ActiveRecord::Base
|
63
|
+
include ExtJS::Model
|
64
|
+
|
65
|
+
extjs_fieldset :grid, [:name, :description, :company => [:name, :description]]
|
66
|
+
extjs_fieldset :combo, [:full_name]
|
67
|
+
|
68
|
+
def full_name
|
69
|
+
"#{first_name} #{name}"
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
You can get store configs for both representations with
|
74
|
+
User.extjs_record(:grid)
|
75
|
+
or
|
76
|
+
User.extjs_record(:combo)
|
77
|
+
|
78
|
+
And the corresponding data for the representations with
|
79
|
+
User.first.to_record(:grid)
|
80
|
+
or
|
81
|
+
User.first.to_record(:combo)
|
82
|
+
|
83
|
+
|
57
84
|
=== An ActionController mixin: ExtJS::Controller
|
58
85
|
The <tt>extjs-mvc</tt> Gem includes a framework agnostic Controller mixin which works with both Rails and Merb. Include this mixin into any controller which will need to generate an <tt>Ext.data.Store</tt>.
|
59
86
|
<b>usage:</b>
|
@@ -112,6 +139,25 @@ Now render a store in an erb template:
|
|
112
139
|
|
113
140
|
%= @store.render %
|
114
141
|
|
142
|
+
=== A Testing Mixin: ExtJS::TestMacros
|
143
|
+
The <tt>extjs-mvc</tt> Gem includes a small set of testing macros to help unit-test models.
|
144
|
+
This requires the 'Shoulda' gem from thoughtbot. Include this mixin inside the
|
145
|
+
<tt>ActiveSupport::TestCase</tt> class in <tt>test/test_helper.rb</tt>
|
146
|
+
|
147
|
+
==== Usage
|
148
|
+
<tt>test/test_helper.rb</tt>
|
149
|
+
class ActiveSupport::TestCase
|
150
|
+
extend ExtJS::TestMacros
|
151
|
+
#...
|
152
|
+
end
|
153
|
+
|
154
|
+
In individual model unit tests:
|
155
|
+
class ModelTest < ActiveSupport::TestCase
|
156
|
+
should_require_extjs_fields :name, :email, :city
|
157
|
+
#...
|
158
|
+
#other tests
|
159
|
+
end
|
160
|
+
|
115
161
|
|
116
162
|
== Note on Patches/Pull Requests
|
117
163
|
|
data/Rakefile
CHANGED
@@ -5,17 +5,20 @@ begin
|
|
5
5
|
require 'jeweler'
|
6
6
|
Jeweler::Tasks.new do |gem|
|
7
7
|
gem.name = "extjs-mvc"
|
8
|
-
gem.summary = %Q{Ruby tools
|
8
|
+
gem.summary = %Q{Ruby ORM tools to assist with rendering Ext.data.Store}
|
9
9
|
gem.description = %Q{MVC tools to assist with ExtJS development in Rails and Merb}
|
10
10
|
gem.email = "christocracy@gmail.com"
|
11
11
|
gem.homepage = "http://github.com/extjs/mvc"
|
12
12
|
gem.authors = ["Chris Scott"]
|
13
|
-
gem.add_development_dependency "
|
13
|
+
gem.add_development_dependency "shoulda"
|
14
|
+
gem.add_development_dependency "mocha"
|
15
|
+
|
14
16
|
gem.test_files = []
|
15
17
|
gem.files = FileList["[A-Z]*", "{bin,generators,lib,test}/**/*", 'lib/jeweler/templates/.gitignore']
|
16
18
|
|
17
19
|
# gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
|
18
20
|
end
|
21
|
+
Jeweler::GemcutterTasks.new
|
19
22
|
rescue LoadError
|
20
23
|
puts "Jeweler (or a dependency) not available. Install it with: sudo gem install jeweler"
|
21
24
|
end
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.
|
1
|
+
0.3.0
|
data/lib/extjs-mvc.rb
CHANGED
data/lib/model/active_record.rb
CHANGED
@@ -10,11 +10,11 @@ module ExtJS
|
|
10
10
|
end
|
11
11
|
|
12
12
|
def extjs_column_names
|
13
|
-
self.column_names
|
13
|
+
self.column_names.map(&:to_sym)
|
14
14
|
end
|
15
15
|
|
16
16
|
def extjs_columns_hash
|
17
|
-
self.columns_hash
|
17
|
+
self.columns_hash.symbolize_keys
|
18
18
|
end
|
19
19
|
|
20
20
|
##
|
@@ -27,21 +27,38 @@ module ExtJS
|
|
27
27
|
end
|
28
28
|
|
29
29
|
##
|
30
|
-
#
|
30
|
+
# returns the default value
|
31
31
|
# @param {ActiveRecord::ConnectionAdapters::Column}
|
32
|
+
# @return {Mixed}
|
33
|
+
#
|
34
|
+
def extjs_default(col)
|
35
|
+
col.default
|
36
|
+
end
|
37
|
+
|
38
|
+
##
|
39
|
+
# returns the corresponding column name of the type column for a polymorphic association
|
40
|
+
# @param {String/Symbol} the id column name for this association
|
32
41
|
# @return {Symbol}
|
42
|
+
def extjs_polymorphic_type(id_column_name)
|
43
|
+
id_column_name.to_s.gsub(/_id\Z/, '_type').to_sym
|
44
|
+
end
|
45
|
+
|
46
|
+
##
|
47
|
+
# determine datatype of supplied Column object
|
48
|
+
# @param {ActiveRecord::ConnectionAdapters::Column}
|
49
|
+
# @return {String}
|
33
50
|
#
|
34
51
|
def extjs_type(col)
|
35
|
-
type = col.type
|
52
|
+
type = col.type.to_s
|
36
53
|
case type
|
37
|
-
when
|
38
|
-
type =
|
39
|
-
when
|
40
|
-
type =
|
41
|
-
when
|
42
|
-
type =
|
43
|
-
when
|
44
|
-
type =
|
54
|
+
when "datetime", "date", "time", "timestamp"
|
55
|
+
type = "date"
|
56
|
+
when "text"
|
57
|
+
type = "string"
|
58
|
+
when "integer"
|
59
|
+
type = "int"
|
60
|
+
when "decimal"
|
61
|
+
type = "float"
|
45
62
|
end
|
46
63
|
type
|
47
64
|
end
|
@@ -51,20 +68,21 @@ module ExtJS
|
|
51
68
|
# @return {Array}
|
52
69
|
#
|
53
70
|
def extjs_associations
|
54
|
-
if @extjs_associations.nil?
|
55
|
-
|
71
|
+
#if @extjs_associations.nil?
|
72
|
+
extjs_associations = {}
|
56
73
|
self.reflections.keys.each do |key|
|
57
74
|
assn = self.reflections[key]
|
58
75
|
type = (assn.macro === :has_many || assn.macro === :has_and_belongs_to_many) ? :many : assn.macro
|
59
|
-
|
60
|
-
:name => key,
|
76
|
+
extjs_associations[key.to_sym] = {
|
77
|
+
:name => key.to_sym,
|
61
78
|
:type => type,
|
62
|
-
:class => assn.class_name.constantize,
|
63
|
-
:foreign_key => assn.association_foreign_key
|
79
|
+
:class => assn.options[:polymorphic] ? nil : assn.class_name.constantize,
|
80
|
+
:foreign_key => assn.association_foreign_key.to_sym,
|
81
|
+
:is_polymorphic => !!assn.options[:polymorphic]
|
64
82
|
}
|
65
83
|
end
|
66
|
-
end
|
67
|
-
|
84
|
+
#end
|
85
|
+
extjs_associations
|
68
86
|
end
|
69
87
|
end
|
70
88
|
end
|
data/lib/model/base.rb
CHANGED
@@ -4,20 +4,14 @@ module ExtJS
|
|
4
4
|
def self.included(model)
|
5
5
|
model.send(:extend, ClassMethods)
|
6
6
|
model.send(:include, InstanceMethods)
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
# One could use the Rails standard "{association}[{property}]" as well.
|
16
|
-
#
|
17
|
-
cattr_accessor :extjs_mapping_template
|
18
|
-
end
|
19
|
-
model.extjs_record_fields = []
|
20
|
-
model.extjs_mapping_template = "_{property}"
|
7
|
+
##
|
8
|
+
# @config {String} extjs_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 :extjs_parent_trail_template
|
14
|
+
model.extjs_parent_trail_template = Proc.new{ |field_name| "_#{field_name}" } if model.extjs_parent_trail_template.nil?
|
21
15
|
end
|
22
16
|
|
23
17
|
##
|
@@ -30,41 +24,55 @@ module ExtJS
|
|
30
24
|
# @params {Mixed} params A list of fields to use instead of this Class's extjs_record_fields
|
31
25
|
#
|
32
26
|
def to_record(*params)
|
33
|
-
|
34
|
-
|
27
|
+
fieldset, params = self.class.extjs_extract_fieldset! params
|
28
|
+
|
29
|
+
fields = []
|
30
|
+
if params.empty?
|
31
|
+
fields = self.class.extjs_get_fields_for_fieldset(fieldset)
|
32
|
+
else
|
33
|
+
fields = self.class.process_fields(*params)
|
35
34
|
end
|
36
35
|
|
37
|
-
fields = (params.empty?) ? self.class.extjs_record_fields : self.class.process_fields(*params)
|
38
36
|
assns = self.class.extjs_associations
|
39
37
|
pk = self.class.extjs_primary_key
|
40
38
|
|
41
39
|
# build the initial field data-hash
|
42
|
-
data = {pk
|
40
|
+
data = {pk => self.send(pk)}
|
43
41
|
|
44
42
|
fields.each do |field|
|
45
|
-
if
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
field[:fields]
|
54
|
-
|
43
|
+
next if data.has_key? field[:name] # already processed (e.g. explicit mentioning of :id)
|
44
|
+
|
45
|
+
value = nil
|
46
|
+
if association_reflection = assns[field[:name]] # if field is an association
|
47
|
+
association = self.send(field[:name])
|
48
|
+
case association_reflection[:type]
|
49
|
+
when :belongs_to
|
50
|
+
if association.respond_to? :to_record
|
51
|
+
assn_fields = field[:fields]
|
52
|
+
if assn_fields.nil?
|
53
|
+
assn_fields = association.class.extjs_get_fields_for_fieldset(field.fetch(:fieldset, fieldset))
|
55
54
|
end
|
55
|
+
value = association.to_record *assn_fields
|
56
56
|
else
|
57
|
-
|
57
|
+
value = {}
|
58
|
+
(field[:fields]||[]).each do |sub_field|
|
59
|
+
value[sub_field[:name]] = association.send(sub_field[:name]) if association.respond_to? sub_field[:name]
|
60
|
+
end
|
58
61
|
end
|
59
62
|
# Append associations foreign_key to data
|
60
|
-
data[
|
61
|
-
|
62
|
-
|
63
|
+
data[association_reflection[:foreign_key]] = self.send(association_reflection[:foreign_key])
|
64
|
+
if association_reflection[:is_polymorphic]
|
65
|
+
foreign_type = self.class.extjs_polymorphic_type(association_reflection[:foreign_key])
|
66
|
+
data[foreign_type] = self.send(foreign_type)
|
67
|
+
end
|
68
|
+
when :many
|
69
|
+
value = association.collect { |r| r.to_record } # use carefully, can get HUGE
|
63
70
|
end
|
64
|
-
else
|
71
|
+
else # not an association -> get the method's value
|
65
72
|
value = self.send(field[:name])
|
66
|
-
|
73
|
+
value = value.to_record if value.respond_to? :to_record
|
67
74
|
end
|
75
|
+
data[field[:name]] = value
|
68
76
|
end
|
69
77
|
data
|
70
78
|
end
|
@@ -79,49 +87,66 @@ module ExtJS
|
|
79
87
|
# eg: {name:'foo', type: 'string'}
|
80
88
|
#
|
81
89
|
def extjs_record(*fields)
|
82
|
-
|
83
|
-
|
90
|
+
fieldset, fields = self.extjs_extract_fieldset! fields
|
91
|
+
|
92
|
+
if fields.empty?
|
93
|
+
fields = self.extjs_get_fields_for_fieldset(fieldset)
|
94
|
+
else
|
95
|
+
fields = self.process_fields(*fields)
|
84
96
|
end
|
85
97
|
|
86
98
|
associations = self.extjs_associations
|
87
99
|
columns = self.extjs_columns_hash
|
88
|
-
fields = fields.empty? ? self.extjs_record_fields : self.process_fields(*fields)
|
89
100
|
pk = self.extjs_primary_key
|
90
101
|
rs = []
|
91
102
|
|
92
103
|
fields.each do |field|
|
93
|
-
field = field
|
104
|
+
field = Marshal.load(Marshal.dump(field)) # making a deep copy
|
94
105
|
|
95
|
-
if col = columns[field[:name]]
|
106
|
+
if col = columns[field[:name]] # <-- column on this model
|
96
107
|
rs << self.extjs_field(field, col)
|
97
|
-
elsif assn = associations[field[:name]]
|
98
|
-
assn_fields = field
|
108
|
+
elsif assn = associations[field[:name]]
|
109
|
+
assn_fields = field[:fields]
|
99
110
|
if assn[:class].respond_to?(:extjs_record) # <-- exec extjs_record on assn Model.
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
extjs_field(assn_field, :mapping => field[:name], "allowBlank" => true)
|
111
|
+
if assn_fields.nil?
|
112
|
+
assn_fields = assn[:class].extjs_get_fields_for_fieldset(field.fetch(:fieldset, fieldset))
|
113
|
+
end
|
114
|
+
record = assn[:class].extjs_record(field.fetch(:fieldset, fieldset), assn_fields)
|
115
|
+
rs.concat(record[:fields].collect { |assn_field|
|
116
|
+
self.extjs_field(assn_field, :parent_trail => field[:name], :mapping => field[:name], :allowBlank => true) # <-- allowBlank on associated data?
|
107
117
|
})
|
118
|
+
elsif assn_fields # <-- :parent => [:id, :name, :sub => [:id, :name]]
|
119
|
+
field_collector = Proc.new do |parent_trail, mapping, assn_field|
|
120
|
+
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)
|
121
|
+
field_collector.call(parent_trail.to_s + self.extjs_parent_trail_template.call(assn_field.keys.first), "#{mapping}.#{assn_field.keys.first}", assn_field.values.first)
|
122
|
+
else
|
123
|
+
self.extjs_field(assn_field, :parent_trail => parent_trail, :mapping => mapping, :allowBlank => true)
|
124
|
+
end
|
125
|
+
end
|
126
|
+
rs.concat(assn_fields.collect { |assn_field| field_collector.call(field[:name], field[:name], assn_field) })
|
108
127
|
else
|
109
128
|
rs << extjs_field(field)
|
110
129
|
end
|
111
130
|
|
112
131
|
# attach association's foreign_key if not already included.
|
113
|
-
if (
|
114
|
-
rs << extjs_field({:name => assn[:foreign_key]},
|
132
|
+
if columns.has_key?(assn[:foreign_key]) && !rs.any? { |r| r[:name] == assn[:foreign_key] }
|
133
|
+
rs << extjs_field({:name => assn[:foreign_key]}, columns[assn[:foreign_key]])
|
134
|
+
end
|
135
|
+
# attach association's type if polymorphic association and not alredy included
|
136
|
+
if assn[:is_polymorphic]
|
137
|
+
foreign_type = self.extjs_polymorphic_type(assn[:foreign_key])
|
138
|
+
if columns.has_key?(foreign_type) && !rs.any? { |r| r[:name] == foreign_type }
|
139
|
+
rs << extjs_field({:name => foreign_type}, columns[foreign_type])
|
140
|
+
end
|
115
141
|
end
|
116
|
-
|
117
142
|
else # property is a method?
|
118
143
|
rs << extjs_field(field)
|
119
144
|
end
|
120
145
|
end
|
121
146
|
|
122
147
|
return {
|
123
|
-
|
124
|
-
|
148
|
+
:fields => rs,
|
149
|
+
:idProperty => pk
|
125
150
|
}
|
126
151
|
end
|
127
152
|
|
@@ -129,67 +154,98 @@ module ExtJS
|
|
129
154
|
# meant to be used within a Model to define the extjs record fields.
|
130
155
|
# eg:
|
131
156
|
# class User
|
132
|
-
#
|
157
|
+
# extjs_fieldset :grid, [:first, :last, :email => {"sortDir" => "ASC"}, :company => [:id, :name]]
|
158
|
+
# end
|
159
|
+
# or
|
160
|
+
# class User
|
161
|
+
# extjs_fieldset :last, :email => {"sortDir" => "ASC"}, :company => [:id, :name] # => implies fieldset name :default
|
133
162
|
# end
|
134
163
|
#
|
164
|
+
def extjs_fieldset(*params)
|
165
|
+
fieldset, params = self.extjs_extract_fieldset! params
|
166
|
+
# creates a method storing the fieldset-to-field association
|
167
|
+
# using a method and not an class-level variable because the latter
|
168
|
+
# is bogus when we deal with inheritance
|
169
|
+
var_name = :"@extjs_fieldsets__#{fieldset}"
|
170
|
+
self.instance_variable_set( var_name, self.process_fields(*params) )
|
171
|
+
end
|
172
|
+
|
173
|
+
def extjs_get_fields_for_fieldset(fieldset)
|
174
|
+
var_name = :"@extjs_fieldsets__#{fieldset}"
|
175
|
+
super_value = nil
|
176
|
+
unless self.instance_variable_get( var_name )
|
177
|
+
if self.superclass.respond_to? :extjs_get_fields_for_fieldset
|
178
|
+
super_value = self.superclass.extjs_get_fields_for_fieldset(fieldset)
|
179
|
+
end
|
180
|
+
self.extjs_fieldset(fieldset, self.extjs_column_names) unless super_value
|
181
|
+
end
|
182
|
+
super_value || self.instance_variable_get( var_name )
|
183
|
+
end
|
184
|
+
|
185
|
+
##
|
186
|
+
# shortcut to define the default fieldset. For backwards-compatibility.
|
187
|
+
#
|
135
188
|
def extjs_fields(*params)
|
136
|
-
self.
|
189
|
+
self.extjs_fieldset(:default, params)
|
137
190
|
end
|
138
191
|
|
139
192
|
##
|
140
193
|
# Prepare a field configuration list into a normalized array of Hashes, {:name => "field_name"}
|
141
194
|
# @param {Mixed} params
|
142
|
-
# @return Array
|
195
|
+
# @return {Array} of Hashes
|
143
196
|
#
|
144
|
-
def process_fields(*params)
|
145
|
-
params = [] if params.first.nil?
|
146
|
-
options = params.extract_options!
|
147
|
-
|
148
|
-
# Return immediately if pre-processed fields are detected.
|
149
|
-
# ie: [ [{:name => 'foo'}, {:name => 'bar'}] ]
|
150
|
-
# This is to handle the case where extjs_record and to_record are called recursively, in which case
|
151
|
-
# these fields have already been processed.
|
152
|
-
#
|
153
|
-
#if params.length === 1 && params.first.kind_of?(Array) && !params.first.empty?
|
154
|
-
# return params.first
|
155
|
-
#end
|
156
|
-
|
197
|
+
def process_fields(*params)
|
157
198
|
fields = []
|
158
|
-
if
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
options.keys.each do |k| # <-- :email => {"sortDir" => "ASC"}
|
165
|
-
if options[k].is_a? Hash
|
166
|
-
options[k][:name] = k.to_s
|
167
|
-
fields << options[k]
|
168
|
-
elsif options[k].is_a? Array # <-- :parent => [:id, :name]
|
169
|
-
fields << {
|
170
|
-
:name => k.to_s,
|
171
|
-
:fields => process_fields(*options[k])
|
172
|
-
}
|
173
|
-
end
|
174
|
-
end
|
199
|
+
if params.size == 1 && params.last.is_a?(Hash) # peek into argument to see if its an option hash
|
200
|
+
options = params.last
|
201
|
+
if options.has_key?(:exclude) && options[:exclude].is_a?(Array)
|
202
|
+
return self.process_fields(*(self.extjs_column_names - options[:exclude].map(&:to_sym)))
|
203
|
+
elsif options.has_key?(:only) && options[:only].is_a?(Array)
|
204
|
+
return self.process_fields(*options[:only])
|
175
205
|
end
|
176
|
-
elsif params.empty?
|
177
|
-
return self.extjs_record_fields
|
178
206
|
end
|
179
207
|
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
208
|
+
params = self.extjs_column_names if params.empty?
|
209
|
+
|
210
|
+
associations = extjs_associations
|
211
|
+
|
212
|
+
params.each do |f|
|
213
|
+
if f.kind_of?(Hash)
|
214
|
+
if f.keys.size == 1 && f.keys[0].is_a?(Symbol) && f.values[0].is_a?(Array) # {:association => [:field1, :field2]}
|
215
|
+
fields << {
|
216
|
+
:name => f.keys[0],
|
217
|
+
:fields => process_fields(*f.values[0])
|
218
|
+
}
|
219
|
+
elsif f.keys.size == 1 && f.keys[0].is_a?(Symbol) && f.values[0].is_a?(Hash) # {:field => {:sortDir => 'ASC'}}
|
220
|
+
fields << f.values[0].update(:name => f.keys[0])
|
221
|
+
elsif f.has_key?(:name) # already a valid Hash, just copy it over
|
184
222
|
fields << f
|
185
223
|
else
|
186
|
-
|
224
|
+
raise ArgumentError, "encountered a Hash that I don't know anyting to do with `#{f.inspect}:#{f.class}`"
|
187
225
|
end
|
226
|
+
else # should be a String or Symbol
|
227
|
+
puts params.inspect if f.nil?
|
228
|
+
fields << {:name => f.to_sym}
|
188
229
|
end
|
189
230
|
end
|
231
|
+
|
190
232
|
fields
|
191
233
|
end
|
192
234
|
|
235
|
+
##
|
236
|
+
# returns the fieldset from the arguments.
|
237
|
+
# @return [{Symbol}, Array]
|
238
|
+
def extjs_extract_fieldset! arguments
|
239
|
+
fieldset = :default
|
240
|
+
if arguments.size > 1 && arguments[0].is_a?(Symbol) && arguments[1].is_a?(Array)
|
241
|
+
fieldset = arguments.shift
|
242
|
+
arguments = arguments[0]
|
243
|
+
elsif arguments.size == 1 && arguments[0].is_a?(Symbol)
|
244
|
+
fieldset = arguments.shift
|
245
|
+
end
|
246
|
+
[fieldset, arguments]
|
247
|
+
end
|
248
|
+
|
193
249
|
##
|
194
250
|
# Render a column-config object
|
195
251
|
# @param {Hash/Column} field Field-configuration Hash, probably has :name already set and possibly Ext.data.Field options.
|
@@ -197,41 +253,48 @@ module ExtJS
|
|
197
253
|
#
|
198
254
|
def extjs_field(field, config=nil)
|
199
255
|
if config.kind_of? Hash
|
200
|
-
if mapping
|
256
|
+
if config.has_key?(:mapping) && config.has_key?(:parent_trail)
|
201
257
|
field.update( # <-- We use a template for rendering mapped field-names.
|
202
|
-
:name =>
|
203
|
-
|
258
|
+
:name => config[:parent_trail].to_s + self.extjs_parent_trail_template.call(field[:name]),
|
259
|
+
:mapping => "#{config[:mapping]}.#{field[:name]}"
|
204
260
|
)
|
205
261
|
end
|
206
|
-
field.update(config)
|
262
|
+
field.update(config.except(:mapping, :parent_trail))
|
207
263
|
elsif !config.nil? # <-- Hopfully an ORM Column object.
|
208
264
|
field.update(
|
209
|
-
|
210
|
-
|
265
|
+
:allowBlank => self.extjs_allow_blank(config),
|
266
|
+
:type => self.extjs_type(config),
|
267
|
+
:defaultValue => self.extjs_default(config)
|
211
268
|
)
|
212
|
-
field[
|
269
|
+
field[:dateFormat] = "c" if field[:type] === "date" && field[:dateFormat].nil? # <-- ugly hack for date
|
213
270
|
end
|
214
|
-
field.update(
|
271
|
+
field.update(:type => "auto") if field[:type].nil?
|
272
|
+
# convert Symbol values to String values
|
273
|
+
field.keys.each do |k|
|
274
|
+
raise ArgumentError, "extjs_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)
|
275
|
+
field[k] = field[k].to_s if field[k].is_a?(Symbol)
|
276
|
+
end
|
215
277
|
field
|
216
278
|
end
|
279
|
+
|
217
280
|
|
218
|
-
##
|
219
|
-
# Returns an array of symbolized association names that will be referenced by a call to to_record
|
220
|
-
# i.e. [:parent1, :parent2]
|
221
|
-
#
|
222
|
-
def extjs_used_associations
|
223
|
-
|
224
|
-
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
-
end
|
281
|
+
# ##
|
282
|
+
# # Returns an array of symbolized association names that will be referenced by a call to to_record
|
283
|
+
# # i.e. [:parent1, :parent2]
|
284
|
+
# #
|
285
|
+
# def extjs_used_associations
|
286
|
+
# if @extjs_used_associations.nil?
|
287
|
+
# assoc = []
|
288
|
+
# self.extjs_record_fields.each do |f|
|
289
|
+
# #This needs to be the first condition because the others will break if f is an Array
|
290
|
+
# if extjs_associations[f[:name]]
|
291
|
+
# assoc << f[:name]
|
292
|
+
# end
|
293
|
+
# end
|
294
|
+
# @extjs_used_associations = assoc.uniq
|
295
|
+
# end
|
296
|
+
# @extjs_used_associations
|
297
|
+
# end
|
235
298
|
end
|
236
299
|
end
|
237
300
|
end
|
data/lib/model/data_mapper.rb
CHANGED
@@ -52,7 +52,8 @@ module ExtJS
|
|
52
52
|
:name => key,
|
53
53
|
:type => type = (assn.options[:max].nil? && assn.options[:min].nil?) ? :belongs_to : (assn.options[:max] > 1) ? :many : nil ,
|
54
54
|
:class => assn.parent_model,
|
55
|
-
:foreign_key => assn.child_key.first.name
|
55
|
+
:foreign_key => assn.child_key.first.name,
|
56
|
+
:is_polymorphic => false # <-- No impl. for DM is_polymorphic. Anyone care to implement this?
|
56
57
|
}
|
57
58
|
end
|
58
59
|
end
|
data/lib/model/mongo_mapper.rb
CHANGED
@@ -28,7 +28,8 @@ module ExtJS
|
|
28
28
|
:name => key,
|
29
29
|
:type => self.associations[key].type,
|
30
30
|
:class => self.associations[key].class_name.constantize,
|
31
|
-
:foreign_key => self.associations[key].foreign_key
|
31
|
+
:foreign_key => self.associations[key].foreign_key,
|
32
|
+
:is_polymorphic => false # <-- no impl. for MM is_polymorhpic yet. Anyone care to implement this?
|
32
33
|
}
|
33
34
|
end
|
34
35
|
end
|