scaffolding_extensions 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (52) hide show
  1. data/LICENSE +19 -0
  2. data/README +144 -0
  3. data/contrib/scaffold_associations_tree/README +9 -0
  4. data/contrib/scaffold_associations_tree/bullet.gif +0 -0
  5. data/contrib/scaffold_associations_tree/minus.gif +0 -0
  6. data/contrib/scaffold_associations_tree/plus.gif +0 -0
  7. data/contrib/scaffold_associations_tree/scaffold_associations_tree.css +20 -0
  8. data/contrib/scaffold_associations_tree/scaffold_associations_tree.js +57 -0
  9. data/contrib/scaffold_auto_complete_style/README +8 -0
  10. data/contrib/scaffold_auto_complete_style/auto_complete.css +23 -0
  11. data/contrib/scaffold_form_focus/README +12 -0
  12. data/contrib/scaffold_form_focus/scaffold_form_focus.js +21 -0
  13. data/contrib/scaffold_jquery_autocomplete/README +8 -0
  14. data/contrib/scaffold_jquery_autocomplete/jquery.ui.se_autocomplete.css +22 -0
  15. data/contrib/scaffold_jquery_autocomplete/jquery.ui.se_autocomplete.js +121 -0
  16. data/doc/advanced.txt +154 -0
  17. data/doc/camping.txt +25 -0
  18. data/doc/controller_spec.txt +20 -0
  19. data/doc/conversion.txt +102 -0
  20. data/doc/model_spec.txt +54 -0
  21. data/doc/ramaze.txt +20 -0
  22. data/doc/sinatra.txt +20 -0
  23. data/doc/testing.txt +12 -0
  24. data/lib/scaffolding_extensions.rb +89 -0
  25. data/lib/scaffolding_extensions/controller.rb +79 -0
  26. data/lib/scaffolding_extensions/controller/action_controller.rb +116 -0
  27. data/lib/scaffolding_extensions/controller/camping.rb +150 -0
  28. data/lib/scaffolding_extensions/controller/ramaze.rb +116 -0
  29. data/lib/scaffolding_extensions/controller/sinatra.rb +183 -0
  30. data/lib/scaffolding_extensions/helper.rb +304 -0
  31. data/lib/scaffolding_extensions/jquery_helper.rb +58 -0
  32. data/lib/scaffolding_extensions/meta_controller.rb +337 -0
  33. data/lib/scaffolding_extensions/meta_model.rb +571 -0
  34. data/lib/scaffolding_extensions/model.rb +30 -0
  35. data/lib/scaffolding_extensions/model/active_record.rb +184 -0
  36. data/lib/scaffolding_extensions/model/ardm.rb +47 -0
  37. data/lib/scaffolding_extensions/model/data_mapper.rb +190 -0
  38. data/lib/scaffolding_extensions/overridable.rb +67 -0
  39. data/lib/scaffolding_extensions/prototype_helper.rb +59 -0
  40. data/scaffolds/edit.rhtml +12 -0
  41. data/scaffolds/habtm.rhtml +24 -0
  42. data/scaffolds/index.rhtml +6 -0
  43. data/scaffolds/layout.rhtml +82 -0
  44. data/scaffolds/list.rhtml +13 -0
  45. data/scaffolds/listtable.rhtml +46 -0
  46. data/scaffolds/manage.rhtml +15 -0
  47. data/scaffolds/merge.rhtml +23 -0
  48. data/scaffolds/new.rhtml +5 -0
  49. data/scaffolds/search.rhtml +11 -0
  50. data/scaffolds/show.rhtml +19 -0
  51. data/test/scaffolding_extensions_test.rb +44 -0
  52. metadata +106 -0
@@ -0,0 +1,30 @@
1
+ # Instance methods shared by all models
2
+ module ScaffoldingExtensions::Model
3
+ # an array of strings describing problems with the object (empty if none)
4
+ def scaffold_error_messages
5
+ errors.full_messages
6
+ end
7
+
8
+ # The name given to the item that is used in various places in the scaffold. For example,
9
+ # it is used whenever the record is displayed in a select box. Should be unique for each record,
10
+ # but that is not required. Should be overridden by subclasses unless they have a unique attribute
11
+ # named 'name'.
12
+ def scaffold_name
13
+ scaffold_attribute_value(:name) || scaffold_id.to_s
14
+ end
15
+
16
+ # scaffold_name prefixed with id, used for scaffold autocompleting
17
+ def scaffold_name_with_id
18
+ "#{scaffold_id} - #{scaffold_name}"
19
+ end
20
+
21
+ # the value of the field if not an association, or the scaffold_name of the associated object
22
+ def scaffold_value(field)
23
+ if self.class.scaffold_association(field)
24
+ obj = send(field)
25
+ obj.scaffold_name if obj
26
+ else
27
+ send(field)
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,184 @@
1
+ require 'scaffolding_extensions/model/ardm'
2
+
3
+ ScaffoldingExtensions::MODEL_SUPERCLASSES << ::ActiveRecord::Base
4
+
5
+ # Instance methods added to ActiveRecord::Base to allow it to work with Scaffolding Extensions.
6
+ module ScaffoldingExtensions::ActiveRecord
7
+ # Get value for given attribute
8
+ def scaffold_attribute_value(field)
9
+ self[field]
10
+ end
11
+ end
12
+
13
+ # Class methods added to ActiveRecord::Base to allow it to work with Scaffolding Extensions.
14
+ module ScaffoldingExtensions::MetaActiveRecord
15
+ SCAFFOLD_OPTIONS = ::ScaffoldingExtensions::MetaModel::SCAFFOLD_OPTIONS
16
+
17
+ # Add the associated object to the object's association
18
+ def scaffold_add_associated_object(association, object, associated_object)
19
+ association_proxy = object.send(association)
20
+ next if association_proxy.include?(associated_object)
21
+ association_proxy << associated_object
22
+ end
23
+
24
+ # Array of all association reflections for this model
25
+ def scaffold_all_associations
26
+ reflect_on_all_associations
27
+ end
28
+
29
+ # The class that this model is associated with via the association
30
+ def scaffold_associated_class(association)
31
+ scaffold_association(association).klass
32
+ end
33
+
34
+ # The association reflection for this association
35
+ def scaffold_association(association)
36
+ reflect_on_association(association)
37
+ end
38
+
39
+ # The type of association, either :new for :has_many (as you can create new objects
40
+ # associated with the current object), :edit for :has_and_belongs_to_many (since you
41
+ # can edit the list of associated objects), or :one for other associations. I'm not
42
+ # sure that :has_one is supported, as I don't use it.
43
+ def scaffold_association_type(association)
44
+ case reflect_on_association(association).macro
45
+ when :has_many
46
+ :new
47
+ when :has_and_belongs_to_many
48
+ :edit
49
+ else
50
+ :one
51
+ end
52
+ end
53
+
54
+ # List of symbols for associations to display on the scaffolded edit page. Defaults to
55
+ # all associations that aren't :through or :polymorphic. Can be set with an instance variable.
56
+ def scaffold_associations
57
+ @scaffold_associations ||= scaffold_all_associations.reject{|r| r.options.include?(:through) || r.options.include?(:polymorphic)}.collect{|r| r.name}.sort_by{|name| name.to_s}
58
+ end
59
+
60
+ # Destroys the object
61
+ def scaffold_destroy(object)
62
+ object.destroy
63
+ end
64
+
65
+ # The error to raise, should match other errors raised by the underlying library.
66
+ def scaffold_error_raised
67
+ ::ActiveRecord::RecordNotFound
68
+ end
69
+
70
+ # Returns the list of fields to display on the scaffolded forms. Defaults
71
+ # to displaying all columns with the exception of primary key column, timestamp columns,
72
+ # count columns, and inheritance columns. Also includes belongs_to associations, replacing
73
+ # the foriegn keys with the association itself. Can be set with an instance variable.
74
+ def scaffold_fields(action = :default)
75
+ return @scaffold_fields if @scaffold_fields
76
+ fields = columns.reject{|c| c.primary || c.name =~ /(\A(created|updated)_at|_count)\z/ || c.name == inheritance_column}.collect{|c| c.name}
77
+ scaffold_all_associations.each do |reflection|
78
+ next if reflection.macro != :belongs_to || reflection.options.include?(:polymorphic)
79
+ fields.delete(reflection.primary_key_name)
80
+ fields.push(reflection.name.to_s)
81
+ end
82
+ @scaffold_fields = fields.sort.collect{|f| f.to_sym}
83
+ end
84
+
85
+ # The foreign key for the given reflection
86
+ def scaffold_foreign_key(reflection)
87
+ reflection.primary_key_name
88
+ end
89
+
90
+ # Retrieve a single model object given an id
91
+ def scaffold_get_object(id)
92
+ find(id.to_i)
93
+ end
94
+
95
+ # Retrieve multiple objects given a hash of options
96
+ def scaffold_get_objects(options)
97
+ options[:conditions] = scaffold_merge_conditions(options[:conditions])
98
+ find(:all, options)
99
+ end
100
+
101
+ # Return the class, left foreign key, right foreign key, and join table for this habtm association
102
+ def scaffold_habtm_reflection_options(association)
103
+ reflection = reflect_on_association(association)
104
+ [reflection.klass, reflection.primary_key_name, reflection.association_foreign_key, reflection.options[:join_table]]
105
+ end
106
+
107
+ # Which associations to include when querying for multiple objects.
108
+ # Can be set with an instance variable.
109
+ def scaffold_include(action = :default)
110
+ @scaffold_include
111
+ end
112
+
113
+ # Returns a hash of values to be used as url parameters on the link to create a new
114
+ # :has_many associated object. Defaults to setting the foreign key field to the
115
+ # record's primary key, and the STI type to this model's name, if :as is one of
116
+ # the association's reflection's options.
117
+ def scaffold_new_associated_object_values(association, record)
118
+ reflection = reflect_on_association(association)
119
+ vals = {reflection.primary_key_name=>record.id}
120
+ vals["#{reflection.options[:as]}_type"] = name if reflection.options.include?(:as)
121
+ vals
122
+ end
123
+
124
+ # The primary key for the given table
125
+ def scaffold_primary_key
126
+ primary_key
127
+ end
128
+
129
+ # Saves the object.
130
+ def scaffold_save(action, object)
131
+ object.save
132
+ end
133
+
134
+ # The column type for the given table column, or nil if it isn't a table column
135
+ def scaffold_table_column_type(column)
136
+ column = column.to_s
137
+ column = columns_hash[column]
138
+ column.type if column
139
+ end
140
+
141
+ # The name of the underlying table
142
+ def scaffold_table_name
143
+ table_name
144
+ end
145
+
146
+ private
147
+ # The associations to include when loading the association
148
+ def scaffold_include_association(association)
149
+ scaffold_associated_class(association).scaffold_include(:association)
150
+ end
151
+
152
+ # Updates associated records for a given reflection and from record to point to the
153
+ # to record
154
+ def scaffold_reflection_merge(reflection, from, to)
155
+ foreign_key = reflection.primary_key_name
156
+ sql = case reflection.macro
157
+ when :has_one, :has_many
158
+ return if reflection.options[:through]
159
+ "UPDATE #{reflection.klass.table_name} SET #{foreign_key} = #{to} WHERE #{foreign_key} = #{from}#{" AND #{reflection.options[:as]}_type = #{quote_value(name.to_s)}" if reflection.options[:as]}"
160
+ when :has_and_belongs_to_many
161
+ "UPDATE #{reflection.options[:join_table]} SET #{foreign_key} = #{to} WHERE #{foreign_key} = #{from}"
162
+ else
163
+ return
164
+ end
165
+ connection.update(sql)
166
+ end
167
+ end
168
+
169
+ # Add the class methods and instance methods from Scaffolding Extensions
170
+ class ActiveRecord::Base
171
+ SCAFFOLD_OPTIONS = ::ScaffoldingExtensions::MetaModel::SCAFFOLD_OPTIONS
172
+ include ScaffoldingExtensions::Model
173
+ include ScaffoldingExtensions::ARDM
174
+ include ScaffoldingExtensions::ActiveRecord
175
+ extend ScaffoldingExtensions::MetaModel
176
+ extend ScaffoldingExtensions::MetaARDM
177
+ extend ScaffoldingExtensions::MetaActiveRecord
178
+ extend ScaffoldingExtensions::Overridable
179
+ class << self
180
+ extend ScaffoldingExtensions::MetaOverridable
181
+ scaffold_override_methods(:add_associated_objects, :associated_objects, :association_find_object, :association_find_objects, :find_object, :find_objects, :new_associated_object_values, :remove_associated_objects, :save, :unassociated_objects, :filter_attributes)
182
+ scaffold_override_iv_methods(:associated_human_name, :association_use_auto_complete, :fields, :include, :select_order, :attributes, :include_association, :select_order_association)
183
+ end
184
+ end
@@ -0,0 +1,47 @@
1
+ # Instance methods used by both ActiveRecord and Datamapper
2
+ module ScaffoldingExtensions::ARDM
3
+ # the value of the primary key for this object
4
+ def scaffold_id
5
+ id
6
+ end
7
+ end
8
+
9
+ # Class methods used by both ActiveRecord and DataMapper
10
+ module ScaffoldingExtensions::MetaARDM
11
+ private
12
+ # Merge an array of conditions into a single condition array
13
+ def scaffold_merge_conditions(conditions)
14
+ new_conditions = [[]]
15
+ if Array === conditions
16
+ if conditions.length == 0 || (conditions.length == 1 && conditions[0].nil?)
17
+ nil
18
+ elsif Array === conditions[0]
19
+ conditions.each do |cond|
20
+ next unless cond
21
+ new_conditions[0] << cond.shift
22
+ cond.each{|c| new_conditions << c}
23
+ end
24
+ if new_conditions[0].length > 0
25
+ new_conditions[0] = "(#{new_conditions[0].join(") AND (")})"
26
+ new_conditions
27
+ else
28
+ nil
29
+ end
30
+ else
31
+ conditions
32
+ end
33
+ else
34
+ conditions
35
+ end
36
+ end
37
+
38
+ # Remove the associated object from object's association
39
+ def scaffold_remove_associated_object(association, object, associated_object)
40
+ object.send(association).delete(associated_object)
41
+ end
42
+
43
+ # Set the object's attributes with the given attributes
44
+ def scaffold_set_attributes(object, attributes)
45
+ object.attributes = attributes
46
+ end
47
+ end
@@ -0,0 +1,190 @@
1
+ require 'scaffolding_extensions/model/ardm'
2
+
3
+ ScaffoldingExtensions::MODEL_SUPERCLASSES << ::DataMapper::Base
4
+
5
+ # Instance methods added to DataMapper::Base to allow it to work with Scaffolding Extensions.
6
+ module ScaffoldingExtensions::DataMapper
7
+ # Get value for given attribute
8
+ def scaffold_attribute_value(field)
9
+ attributes[field]
10
+ end
11
+ end
12
+
13
+ # Class methods added to DataMapper::Base to allow it to work with Scaffolding Extensions.
14
+ module ScaffoldingExtensions::MetaDataMapper
15
+ SCAFFOLD_OPTIONS = ::ScaffoldingExtensions::MetaModel::SCAFFOLD_OPTIONS
16
+
17
+ # Add the associated object to the object's association
18
+ def scaffold_add_associated_object(association, object, associated_object)
19
+ association_proxy = object.send(association)
20
+ next if association_proxy.include?(associated_object)
21
+ association_proxy << associated_object
22
+ object.save
23
+ end
24
+
25
+ # Array of all association reflections for this model
26
+ def scaffold_all_associations
27
+ database.schema[self].associations.to_a
28
+ end
29
+
30
+ # The class that this model is associated with via the association
31
+ def scaffold_associated_class(association)
32
+ case reflection = scaffold_association(association)
33
+ when DataMapper::Associations::HasManyAssociation
34
+ reflection.associated_constant
35
+ else
36
+ reflection.constant
37
+ end
38
+ end
39
+
40
+ # The association reflection for this association
41
+ def scaffold_association(association)
42
+ database.schema[self].associations.each{|assoc| return assoc if assoc.name == association}
43
+ nil
44
+ end
45
+
46
+ # The type of association, either :new for :has_many (as you can create new objects
47
+ # associated with the current object), :edit for :has_and_belongs_to_many (since you
48
+ # can edit the list of associated objects), or :one for other associations. I'm not
49
+ # sure that :has_one is supported, as I don't use it.
50
+ def scaffold_association_type(association)
51
+ case scaffold_association(association)
52
+ when DataMapper::Associations::HasManyAssociation
53
+ :new
54
+ when DataMapper::Associations::HasAndBelongsToManyAssociation
55
+ :edit
56
+ else
57
+ :one
58
+ end
59
+ end
60
+
61
+ # List of symbols for associations to display on the scaffolded edit page. Defaults to
62
+ # all associations that aren't :through or :polymorphic. Can be set with an instance variable.
63
+ def scaffold_associations
64
+ @scaffold_associations ||= scaffold_all_associations.collect{|assoc| assoc.name}.sort_by{|name| name.to_s}
65
+ end
66
+
67
+ # Destroys the object
68
+ def scaffold_destroy(object)
69
+ object.destroy!
70
+ end
71
+
72
+ # The error to raise, should match other errors raised by the underlying library.
73
+ # I'm not sure that this is the correct error, but it is the most common error I've
74
+ # received.
75
+ def scaffold_error_raised
76
+ ::DataObject::ReaderClosed
77
+ end
78
+
79
+ # Returns the list of fields to display on the scaffolded forms. Defaults
80
+ # to displaying all columns with the exception of primary key column, timestamp columns,
81
+ # count columns, and inheritance columns. Also includes belongs_to associations, replacing
82
+ # the foriegn keys with the association itself. Can be set with an instance variable.
83
+ def scaffold_fields(action = :default)
84
+ return @scaffold_fields if @scaffold_fields
85
+ schema = database.schema[self]
86
+ key = schema.key.name
87
+ fields = schema.columns.to_a.collect{|x| x.name}.reject{|x| x == key}
88
+ schema.associations.each do |r|
89
+ next unless DataMapper::Associations::BelongsToAssociation === r
90
+ fields << r.name
91
+ fields.delete(r.foreign_key_name.to_sym)
92
+ end
93
+ @scaffold_fields = fields.sort_by{|x| x.to_s}
94
+ end
95
+
96
+ # The foreign key for the given reflection
97
+ def scaffold_foreign_key(reflection)
98
+ reflection.foreign_key_name
99
+ end
100
+
101
+ # Retrieve a single model object given an id
102
+ def scaffold_get_object(id)
103
+ self[id]
104
+ end
105
+
106
+ # Retrieve multiple objects given a hash of options
107
+ def scaffold_get_objects(options)
108
+ options.delete(:include)
109
+ options[:conditions] = scaffold_merge_conditions(options[:conditions])
110
+ all(options)
111
+ end
112
+
113
+ # Return the class, left foreign key, right foreign key, and join table for this habtm association
114
+ def scaffold_habtm_reflection_options(association)
115
+ reflection = scaffold_association(association)
116
+ [reflection.constant, reflection.left_foreign_key, reflection.right_foreign_key, reflection.join_table]
117
+ end
118
+
119
+ # DataMapper doesn't use includes, so this is always nil
120
+ def scaffold_include(action = :default)
121
+ nil
122
+ end
123
+
124
+ # Returns a hash of values to be used as url parameters on the link to create a new
125
+ # :has_many associated object. Defaults to setting the foreign key field to the
126
+ # record's primary key.
127
+ def scaffold_new_associated_object_values(association, record)
128
+ {scaffold_foreign_key(scaffold_association(association))=>record.id}
129
+ end
130
+
131
+ # The primary key for the given table
132
+ def scaffold_primary_key
133
+ database.schema[self].key.name
134
+ end
135
+
136
+ # Saves the object.
137
+ def scaffold_save(action, object)
138
+ object.save rescue false
139
+ end
140
+
141
+ # The column type for the given table column, or nil if it isn't a table column
142
+ def scaffold_table_column_type(column)
143
+ column = database.schema[self][column]
144
+ column.type if column
145
+ end
146
+
147
+ # The name of the underlying table
148
+ def scaffold_table_name
149
+ database.schema[self].name
150
+ end
151
+
152
+ private
153
+ # DataMapper doesn't need to include, so this is always nil
154
+ def scaffold_include_association(association)
155
+ nil
156
+ end
157
+
158
+ # Updates associated records for a given reflection and from record to point to the
159
+ # to record
160
+ def scaffold_reflection_merge(reflection, from, to)
161
+ sql = case reflection
162
+ when DataMapper::Associations::HasManyAssociation
163
+ foreign_key = scaffold_foreign_key(reflection)
164
+ "UPDATE #{reflection.associated_constant.scaffold_table_name} SET #{foreign_key} = #{to} WHERE #{foreign_key} = #{from}"
165
+ when DataMapper::Associations::HasAndBelongsToManyAssociation
166
+ foreign_key = reflection.left_foreign_key
167
+ "UPDATE #{reflection.join_table} SET #{foreign_key} = #{to} WHERE #{foreign_key} = #{from}"
168
+ else
169
+ return
170
+ end
171
+ database.execute(sql)
172
+ end
173
+ end
174
+
175
+ # Add the class methods and instance methods from Scaffolding Extensions
176
+ class DataMapper::Base
177
+ SCAFFOLD_OPTIONS = ::ScaffoldingExtensions::MetaModel::SCAFFOLD_OPTIONS
178
+ include ScaffoldingExtensions::Model
179
+ include ScaffoldingExtensions::ARDM
180
+ include ScaffoldingExtensions::DataMapper
181
+ extend ScaffoldingExtensions::MetaModel
182
+ extend ScaffoldingExtensions::MetaARDM
183
+ extend ScaffoldingExtensions::MetaDataMapper
184
+ extend ScaffoldingExtensions::Overridable
185
+ class << self
186
+ extend ScaffoldingExtensions::MetaOverridable
187
+ scaffold_override_methods(:add_associated_objects, :associated_objects, :association_find_object, :association_find_objects, :find_object, :find_objects, :new_associated_object_values, :remove_associated_objects, :save, :unassociated_objects, :filter_attributes)
188
+ scaffold_override_iv_methods(:associated_human_name, :association_use_auto_complete, :fields, :select_order, :attributes, :select_order_association)
189
+ end
190
+ end