extjs-mvc 0.2.7 → 0.2.8

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 CHANGED
@@ -1,22 +1,22 @@
1
1
  = mvc
2
2
 
3
-
4
3
  A collection of helpers, MVC mixins and PORs (plain-old-ruby-object) to assist with auto-generating ExtJS Stores (Ext.data.Store) including its associated DataReader (Ext.data.JsonReader, Ext.data.XmlReader) and DataWriter (Ext.data.JsonWriter, Ext.data.XmlWriter). Also contains a helper for rendering javascript component definitions via partials.
5
4
 
5
+ See tutorial http://www.extjs.com/blog/2009/09/30/ext-js-on-rails-a-comprehensivetutorial/
6
6
 
7
7
  ===Installation
8
8
  % sudo gem install gemcutter
9
9
  % gem tumble (only have to do this once, adds gemcutter as primary gem-source)
10
- % sudo gem install extjs-mvc
10
+ % sudo gem install extjs-mvc
11
11
 
12
- <p><b>Rails Installation:</b></p>
12
+ <b>Rails Installation:</b>
13
13
  In <tt>environment.rb</tt>,
14
14
 
15
15
  Rails::Initializer.run do |config|
16
16
  config.gem "extjs-mvc"
17
17
  end
18
18
 
19
- <p><b>Merb installation:</b></p>
19
+ <b>Merb installation:</b>
20
20
  In <tt>config/dependencies.rb</tt>, Add extjs-mvc as a new dependency
21
21
 
22
22
  dependency "extjs-mvc"
@@ -27,22 +27,23 @@ extjs-mvc contains Model mixin named <tt>ExtJS::Model</tt> which works for <b>th
27
27
  Simply include the mixin into your model. Use the class-method <tt>extjs_fields</tt> to specify those
28
28
  fields with will be used to render the <tt>Ext.data.Record.create</tt> field-def'n.
29
29
 
30
- class User < ActiveRecord::Base
31
- include ExtJS::Model
32
-
33
- extjs_fields :exclude => [:password, :password_confirmation]
34
- # OR
35
- extjs_fields :name, :description
36
- # OR define a column as a Hash
37
- extjs_fields :description, :name => {"sortDir" => "ASC"}, :created_at => {"dateFormat" => "c"}
38
- #
39
- extjs_fields :name, :description, :parent => [:name, :date]
40
- # this would configure associated columns with names like:
41
- [...{name: "parent_name", mapping: "parent.name"}, {name: "parent_date", mapping: "parent.date"}...]
42
- end
30
+ class User < ActiveRecord::Base
31
+ include ExtJS::Model
43
32
 
44
- In <tt>irb</tt> console:
45
- >> User.extjs_fields
33
+ extjs_fields :exclude => [:password, :password_confirmation]
34
+
35
+ # OR
36
+ extjs_fields :name, :description
37
+
38
+ # OR define a column as a Hash
39
+ extjs_fields :description, :name => {"sortDir" => "ASC"}, :created_at => {"dateFormat" => "c"}
40
+
41
+ # OR render associations, association-fields will have their "mapping" property set automatically
42
+ extjs_fields :name, :description, :company => [:name, :description]
43
+
44
+ end
45
+
46
+ After including the model mixin <tt>ExtJS::Model</tt>, try typing the following in <tt>irb</tt> console:
46
47
  >> User.extjs_record
47
48
  => { "idProperty"=>"id", "fields"=>[
48
49
  {:type=>:int, :allowBlank=>true, :name=>"id"},
@@ -51,8 +52,10 @@ In <tt>irb</tt> console:
51
52
  {:type=>:string, :allowBlank=>false, :name=>"email"}
52
53
  ]}
53
54
 
55
+ An auto-generated <tt>Ext.data.JsonReader</tt> configuration!
56
+
54
57
  === An ActionController mixin: ExtJS::Controller
55
- The <tt>extjs-mvc</tt> Gem includes a framework agnostic Controller mixin which works with both Rails and Merb.
58
+ 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>.
56
59
  <b>usage:</b>
57
60
 
58
61
  class UsersController < ActionController::Base
@@ -71,13 +74,13 @@ The <tt>extjs-mvc</tt> Gem includes a framework agnostic Controller mixin which
71
74
  Now render Ext components using helper method <tt>extjs_component</tt>
72
75
 
73
76
  @viewport = extjs_component(
74
- "xtype" =&gt; "viewport",
75
- "frame" =&gt; true,
76
- "layout" =&gt; "border")
77
- @viewport.add("xtype" =&gt; "panel", "contentEl" =&gt; "hd", "region" =&gt; "north", "height" =&gt; 30)
78
- @viewport.add(:partial =&gt; "/users/grid", "itemId" =&gt; "users-grid", "region" =&gt; "west")
79
- @viewport.add(:partial =&gt; "/tasks/grid", "itemId" =&gt; "tasks-grid", "region" =&gt; "center")
80
- @viewport.add("xtype" =&gt; "panel", "contentEl" =&gt; "ft", "region" =&gt; "south", "height" =&gt; 20)
77
+ "xtype" => "viewport",
78
+ "frame" => true,
79
+ "layout" => "border")
80
+ @viewport.add("xtype" => "panel", "contentEl" => "hd", "region" => "north", "height" => 30)
81
+ @viewport.add(:partial => "/users/grid", "itemId" => "users-grid", "region" => "west")
82
+ @viewport.add(:partial => "/tasks/grid", "itemId" => "tasks-grid", "region" => "center")
83
+ @viewport.add("xtype" => "panel", "contentEl" => "ft", "region" => "south", "height" => 20)
81
84
 
82
85
  Note how it can also render partials. Partials will be invoked with a local-variable named "container", a reference to the
83
86
  parent Ext::Component instance which added the partial. If no "container" is specified, it would be expected that your partial
@@ -93,12 +96,13 @@ Renders an Ext.data.Store with helper method <tt>extjs_store</tt>
93
96
  helper ExtJS::Helpers::Store
94
97
  end
95
98
 
99
+ Now render a store in an erb template:
96
100
 
97
101
  @store = extjs_store(
98
102
  :controller => "users",
99
103
  :proxy => "http" # <-- default
100
104
  :format => "json" # <-- default
101
- :model => "user", # <-- default: controller_name.singularize.camelize.constantize
105
+ :model => "user", # <-- default: controller_name.singularize
102
106
  :writer => {:encode => false},
103
107
  :config => { # <-- standard Ext.data.Store config-params
104
108
  "autoLoad" => true
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.2.7
1
+ 0.2.8
data/lib/extjs-mvc.rb CHANGED
@@ -36,3 +36,9 @@ module ExtJS
36
36
 
37
37
  end
38
38
  end
39
+
40
+ #require 'test/macros'
41
+
42
+ #class ActiveSupport::TestCase < Test::Unit::TestCase
43
+ # extend ExtJS::TestMacros
44
+ #end
@@ -34,7 +34,7 @@ module ExtJS
34
34
  def extjs_type(col)
35
35
  type = col.type
36
36
  case type
37
- when :datetime || :date || :time || :timestamp
37
+ when :datetime, :date, :time, :timestamp
38
38
  type = :date
39
39
  when :text
40
40
  type = :string
@@ -55,7 +55,7 @@ module ExtJS
55
55
  @extjs_associations = {}
56
56
  self.reflections.keys.each do |key|
57
57
  assn = self.reflections[key]
58
- type = (assn.macro === :has_many) ? :many : assn.macro
58
+ type = (assn.macro === :has_many || assn.macro === :has_and_belongs_to_many) ? :many : assn.macro
59
59
  @extjs_associations[key.to_sym] = {
60
60
  :name => key,
61
61
  :type => type,
data/lib/model/base.rb CHANGED
@@ -30,20 +30,24 @@ module ExtJS
30
30
  # @params {Mixed} params A list of fields to use instead of this Class's extjs_record_fields
31
31
  #
32
32
  def to_record(*params)
33
+ if self.class.extjs_record_fields.empty?
34
+ self.class.extjs_fields(*self.class.extjs_column_names)
35
+ end
33
36
 
34
37
  fields = (params.empty?) ? self.class.extjs_record_fields : self.class.process_fields(*params)
35
38
  assns = self.class.extjs_associations
36
39
  pk = self.class.extjs_primary_key
37
40
 
38
41
  # build the initial field data-hash
39
- data = {pk => self.send(pk)}
42
+ data = {pk.to_s => self.send(pk)}
40
43
 
41
44
  fields.each do |field|
42
45
  if refl = assns[field[:name]] || assns[field[:name].to_sym]
43
46
  if refl[:type] === :belongs_to
44
47
  assn = self.send(field[:name])
48
+
45
49
  if assn.respond_to?(:to_record)
46
- data[field[:name]] = assn.send(:to_record, *[field[:fields]])
50
+ data[field[:name]] = assn.to_record field[:fields]
47
51
  elsif (field[:fields])
48
52
  data[field[:name]] = {}
49
53
  field[:fields].each do |property|
@@ -52,6 +56,8 @@ module ExtJS
52
56
  else
53
57
  data[field[:name]] = {} # belongs_to assn that doesn't respond to to_record and no fields list
54
58
  end
59
+ # Append associations foreign_key to data
60
+ data[refl[:foreign_key].to_s] = self.send(refl[:foreign_key])
55
61
  elsif refl[:type] === :many
56
62
  data[field[:name]] = self.send(field[:name]).collect {|r| r.to_record} #CAREFUL!!!!!!!!!!!!1
57
63
  end
@@ -91,13 +97,13 @@ module ExtJS
91
97
  elsif assn = associations[field[:name]] || associations[field[:name].to_sym]
92
98
  assn_fields = field.delete(:fields) || nil
93
99
  if assn[:class].respond_to?(:extjs_record) # <-- exec extjs_record on assn Model.
94
- record = assn[:class].send(:extjs_record, *[assn_fields])
100
+ record = assn[:class].extjs_record(assn_fields)
95
101
  rs.concat(record["fields"].collect {|assn_field|
96
- extjs_field(assn_field, :mapping => field[:name])
102
+ extjs_field(assn_field, :mapping => field[:name], "allowBlank" => true) # <-- allowBlank on associated data?
97
103
  })
98
104
  elsif assn_fields # <-- :parent => [:id, :name]
99
105
  rs.concat(assn_fields.collect {|assn_field|
100
- extjs_field(assn_field, :mapping => field[:name])
106
+ extjs_field(assn_field, :mapping => field[:name], "allowBlank" => true)
101
107
  })
102
108
  else
103
109
  rs << extjs_field(field)
@@ -144,9 +150,9 @@ module ExtJS
144
150
  # This is to handle the case where extjs_record and to_record are called recursively, in which case
145
151
  # these fields have already been processed.
146
152
  #
147
- if params.length === 1 && params.first.kind_of?(Array) && !params.first.empty?
148
- return params.first
149
- end
153
+ #if params.length === 1 && params.first.kind_of?(Array) && !params.first.empty?
154
+ # return params.first
155
+ #end
150
156
 
151
157
  fields = []
152
158
  if !options.keys.empty?
@@ -172,9 +178,14 @@ module ExtJS
172
178
  end
173
179
 
174
180
  unless params.empty?
175
- fields.concat(params.collect {|f|
176
- {:name => f.to_s}
177
- })
181
+ params = params.first if params.length == 1 && params.first.kind_of?(Array) && !params.first.empty?
182
+ params.each do |f|
183
+ if f.kind_of?(Hash)
184
+ fields << f
185
+ else
186
+ fields << {:name => f.to_s}
187
+ end
188
+ end
178
189
  end
179
190
  fields
180
191
  end
@@ -7,25 +7,25 @@ module ExtJS
7
7
  # ClassMethods
8
8
  #
9
9
  module ClassMethods
10
-
10
+
11
11
  def extjs_primary_key
12
12
  :_id
13
13
  end
14
-
14
+
15
15
  def extjs_column_names
16
16
  self.column_names
17
17
  end
18
-
18
+
19
19
  def extjs_columns_hash
20
20
  self.keys
21
21
  end
22
-
22
+
23
23
  def extjs_associations
24
24
  if @extjs_associations.nil?
25
25
  @extjs_associations = {}
26
26
  self.associations.keys.each do |key|
27
27
  @extjs_associations[key.to_sym] = {
28
- :name => key,
28
+ :name => key,
29
29
  :type => self.associations[key].type,
30
30
  :class => self.associations[key].class_name.constantize,
31
31
  :foreign_key => self.associations[key].foreign_key
@@ -34,7 +34,7 @@ module ExtJS
34
34
  end
35
35
  @extjs_associations
36
36
  end
37
-
37
+
38
38
  def extjs_type(col)
39
39
  type = col.type.to_s
40
40
  case type
@@ -50,9 +50,9 @@ module ExtJS
50
50
  type = "auto"
51
51
  end
52
52
  end
53
-
53
+
54
54
  def extjs_allow_blank(col)
55
- (col.name === '_id') ? true : (col.options[:required] === true) ? false : true
55
+ (col.name == '_id') || (col.options[:required] != true)
56
56
  end
57
57
  end
58
58
  end
@@ -0,0 +1,20 @@
1
+ module ExtJS
2
+ module TestMacros
3
+ ##
4
+ # Asserts that the passed list of fields are specified in the extjs_fields call
5
+ # in the model class.
6
+ # @fields {Symbols} fields A list of fields
7
+ #
8
+ def should_have_extjs_fields *fields
9
+ klass = model_class
10
+ should "have the correct extjs_fields" do
11
+ fields.each do |field|
12
+ found_record = klass.extjs_record_fields.find do|record_field|
13
+ record_field[:name] == field.to_s
14
+ end
15
+ assert_not_nil found_record, "extjs field #{field} isn't listed in the #{klass.name} model"
16
+ end
17
+ end
18
+ end
19
+ end
20
+ end
File without changes
File without changes
data/test/database.yml ADDED
@@ -0,0 +1,3 @@
1
+ test:
2
+ adapter: sqlite3
3
+ database: ":memory:"