extjs-mvc 0.2.8 → 0.3.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|