scaffolding_extensions 1.0.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.
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