active_scaffold 3.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 (272) hide show
  1. data/.autotest +27 -0
  2. data/CHANGELOG +152 -0
  3. data/Gemfile +4 -0
  4. data/MIT-LICENSE +20 -0
  5. data/README +51 -0
  6. data/Rakefile +24 -0
  7. data/active_scaffold.gemspec +24 -0
  8. data/environment.rb +22 -0
  9. data/frontends/default/images/add.gif +0 -0
  10. data/frontends/default/images/arrow_down.gif +0 -0
  11. data/frontends/default/images/arrow_up.gif +0 -0
  12. data/frontends/default/images/close.gif +0 -0
  13. data/frontends/default/images/cross.png +0 -0
  14. data/frontends/default/images/indicator-small.gif +0 -0
  15. data/frontends/default/images/indicator.gif +0 -0
  16. data/frontends/default/images/magnifier.png +0 -0
  17. data/frontends/default/javascripts/jquery/active_scaffold.js +957 -0
  18. data/frontends/default/javascripts/jquery/jquery.editinplace.js +726 -0
  19. data/frontends/default/javascripts/prototype/active_scaffold.js +954 -0
  20. data/frontends/default/javascripts/prototype/dhtml_history.js +867 -0
  21. data/frontends/default/javascripts/prototype/form_enhancements.js +117 -0
  22. data/frontends/default/javascripts/prototype/rico_corner.js +370 -0
  23. data/frontends/default/stylesheets/stylesheet-ie.css +35 -0
  24. data/frontends/default/stylesheets/stylesheet.css +858 -0
  25. data/frontends/default/views/_add_existing_form.html.erb +30 -0
  26. data/frontends/default/views/_base_form.html.erb +41 -0
  27. data/frontends/default/views/_create_form.html.erb +6 -0
  28. data/frontends/default/views/_create_form_on_list.html.erb +5 -0
  29. data/frontends/default/views/_field_search.html.erb +32 -0
  30. data/frontends/default/views/_form.html.erb +24 -0
  31. data/frontends/default/views/_form_association.html.erb +14 -0
  32. data/frontends/default/views/_form_association_footer.html.erb +40 -0
  33. data/frontends/default/views/_form_attribute.html.erb +15 -0
  34. data/frontends/default/views/_form_hidden_attribute.html.erb +2 -0
  35. data/frontends/default/views/_form_messages.html.erb +5 -0
  36. data/frontends/default/views/_horizontal_subform.html.erb +19 -0
  37. data/frontends/default/views/_horizontal_subform_header.html.erb +10 -0
  38. data/frontends/default/views/_horizontal_subform_record.html.erb +37 -0
  39. data/frontends/default/views/_human_conditions.html.erb +1 -0
  40. data/frontends/default/views/_list.html.erb +18 -0
  41. data/frontends/default/views/_list_actions.html.erb +16 -0
  42. data/frontends/default/views/_list_calculations.html.erb +16 -0
  43. data/frontends/default/views/_list_column_headings.html.erb +12 -0
  44. data/frontends/default/views/_list_header.html.erb +12 -0
  45. data/frontends/default/views/_list_inline_adapter.html.erb +10 -0
  46. data/frontends/default/views/_list_messages.html.erb +32 -0
  47. data/frontends/default/views/_list_pagination.html.erb +11 -0
  48. data/frontends/default/views/_list_pagination_links.html.erb +9 -0
  49. data/frontends/default/views/_list_record.html.erb +14 -0
  50. data/frontends/default/views/_list_record_columns.html.erb +8 -0
  51. data/frontends/default/views/_list_with_header.html.erb +32 -0
  52. data/frontends/default/views/_messages.html.erb +10 -0
  53. data/frontends/default/views/_render_field.js.rjs +13 -0
  54. data/frontends/default/views/_row.html.erb +12 -0
  55. data/frontends/default/views/_search.html.erb +34 -0
  56. data/frontends/default/views/_search_attribute.html.erb +10 -0
  57. data/frontends/default/views/_show.html.erb +8 -0
  58. data/frontends/default/views/_show_columns.html.erb +12 -0
  59. data/frontends/default/views/_update_actions.html.erb +9 -0
  60. data/frontends/default/views/_update_form.html.erb +5 -0
  61. data/frontends/default/views/_vertical_subform.html.erb +12 -0
  62. data/frontends/default/views/_vertical_subform_record.html.erb +38 -0
  63. data/frontends/default/views/add_existing.js.rjs +17 -0
  64. data/frontends/default/views/add_existing_form.html.erb +5 -0
  65. data/frontends/default/views/create.html.erb +5 -0
  66. data/frontends/default/views/delete.html.erb +13 -0
  67. data/frontends/default/views/destroy.js.rjs +5 -0
  68. data/frontends/default/views/edit_associated.js.rjs +11 -0
  69. data/frontends/default/views/field_search.html.erb +5 -0
  70. data/frontends/default/views/form_messages.js.rjs +1 -0
  71. data/frontends/default/views/list.html.erb +1 -0
  72. data/frontends/default/views/list.js.rjs +1 -0
  73. data/frontends/default/views/on_action_update.js.rjs +8 -0
  74. data/frontends/default/views/on_create.js.rjs +24 -0
  75. data/frontends/default/views/on_update.js.rjs +15 -0
  76. data/frontends/default/views/search.html.erb +5 -0
  77. data/frontends/default/views/show.html.erb +5 -0
  78. data/frontends/default/views/update.html.erb +8 -0
  79. data/frontends/default/views/update_column.js.rjs +13 -0
  80. data/frontends/default/views/update_row.js.rjs +1 -0
  81. data/init.rb +1 -0
  82. data/install_assets.rb +44 -0
  83. data/lib/active_record_permissions.rb +134 -0
  84. data/lib/active_scaffold.rb +279 -0
  85. data/lib/active_scaffold/actions/common_search.rb +22 -0
  86. data/lib/active_scaffold/actions/core.rb +150 -0
  87. data/lib/active_scaffold/actions/create.rb +152 -0
  88. data/lib/active_scaffold/actions/delete.rb +72 -0
  89. data/lib/active_scaffold/actions/field_search.rb +82 -0
  90. data/lib/active_scaffold/actions/list.rb +128 -0
  91. data/lib/active_scaffold/actions/mark.rb +50 -0
  92. data/lib/active_scaffold/actions/nested.rb +241 -0
  93. data/lib/active_scaffold/actions/search.rb +47 -0
  94. data/lib/active_scaffold/actions/show.rb +54 -0
  95. data/lib/active_scaffold/actions/subform.rb +17 -0
  96. data/lib/active_scaffold/actions/update.rb +134 -0
  97. data/lib/active_scaffold/attribute_params.rb +207 -0
  98. data/lib/active_scaffold/bridges/ancestry/bridge.rb +5 -0
  99. data/lib/active_scaffold/bridges/ancestry/lib/ancestry_bridge.rb +38 -0
  100. data/lib/active_scaffold/bridges/bridge.rb +52 -0
  101. data/lib/active_scaffold/bridges/calendar_date_select/bridge.rb +16 -0
  102. data/lib/active_scaffold/bridges/calendar_date_select/lib/as_cds_bridge.rb +79 -0
  103. data/lib/active_scaffold/bridges/carrierwave/bridge.rb +7 -0
  104. data/lib/active_scaffold/bridges/carrierwave/lib/carrierwave_bridge.rb +38 -0
  105. data/lib/active_scaffold/bridges/carrierwave/lib/carrierwave_bridge_helpers.rb +26 -0
  106. data/lib/active_scaffold/bridges/carrierwave/lib/form_ui.rb +35 -0
  107. data/lib/active_scaffold/bridges/carrierwave/lib/list_ui.rb +17 -0
  108. data/lib/active_scaffold/bridges/date_picker/bridge.rb +22 -0
  109. data/lib/active_scaffold/bridges/date_picker/lib/datepicker_bridge.rb +225 -0
  110. data/lib/active_scaffold/bridges/date_picker/public/javascripts/date_picker_bridge.js +22 -0
  111. data/lib/active_scaffold/bridges/file_column/bridge.rb +11 -0
  112. data/lib/active_scaffold/bridges/file_column/lib/as_file_column_bridge.rb +46 -0
  113. data/lib/active_scaffold/bridges/file_column/lib/file_column_helpers.rb +59 -0
  114. data/lib/active_scaffold/bridges/file_column/lib/form_ui.rb +37 -0
  115. data/lib/active_scaffold/bridges/file_column/lib/list_ui.rb +26 -0
  116. data/lib/active_scaffold/bridges/file_column/test/functional/file_column_keep_test.rb +43 -0
  117. data/lib/active_scaffold/bridges/file_column/test/mock_model.rb +9 -0
  118. data/lib/active_scaffold/bridges/file_column/test/test_helper.rb +15 -0
  119. data/lib/active_scaffold/bridges/paperclip/bridge.rb +12 -0
  120. data/lib/active_scaffold/bridges/paperclip/lib/form_ui.rb +27 -0
  121. data/lib/active_scaffold/bridges/paperclip/lib/list_ui.rb +16 -0
  122. data/lib/active_scaffold/bridges/paperclip/lib/paperclip_bridge.rb +38 -0
  123. data/lib/active_scaffold/bridges/paperclip/lib/paperclip_bridge_helpers.rb +26 -0
  124. data/lib/active_scaffold/bridges/semantic_attributes/bridge.rb +5 -0
  125. data/lib/active_scaffold/bridges/semantic_attributes/lib/semantic_attributes_bridge.rb +20 -0
  126. data/lib/active_scaffold/bridges/shared/date_bridge.rb +187 -0
  127. data/lib/active_scaffold/bridges/tiny_mce/bridge.rb +5 -0
  128. data/lib/active_scaffold/bridges/tiny_mce/lib/tiny_mce_bridge.rb +45 -0
  129. data/lib/active_scaffold/bridges/validation_reflection/bridge.rb +8 -0
  130. data/lib/active_scaffold/bridges/validation_reflection/lib/validation_reflection_bridge.rb +21 -0
  131. data/lib/active_scaffold/config/base.rb +54 -0
  132. data/lib/active_scaffold/config/core.rb +229 -0
  133. data/lib/active_scaffold/config/create.rb +43 -0
  134. data/lib/active_scaffold/config/delete.rb +25 -0
  135. data/lib/active_scaffold/config/field_search.rb +74 -0
  136. data/lib/active_scaffold/config/form.rb +46 -0
  137. data/lib/active_scaffold/config/list.rb +174 -0
  138. data/lib/active_scaffold/config/mark.rb +22 -0
  139. data/lib/active_scaffold/config/nested.rb +43 -0
  140. data/lib/active_scaffold/config/search.rb +68 -0
  141. data/lib/active_scaffold/config/show.rb +34 -0
  142. data/lib/active_scaffold/config/subform.rb +35 -0
  143. data/lib/active_scaffold/config/update.rb +38 -0
  144. data/lib/active_scaffold/configurable.rb +29 -0
  145. data/lib/active_scaffold/constraints.rb +179 -0
  146. data/lib/active_scaffold/data_structures/action_columns.rb +133 -0
  147. data/lib/active_scaffold/data_structures/action_link.rb +162 -0
  148. data/lib/active_scaffold/data_structures/action_links.rb +59 -0
  149. data/lib/active_scaffold/data_structures/actions.rb +45 -0
  150. data/lib/active_scaffold/data_structures/column.rb +348 -0
  151. data/lib/active_scaffold/data_structures/columns.rb +75 -0
  152. data/lib/active_scaffold/data_structures/error_message.rb +24 -0
  153. data/lib/active_scaffold/data_structures/nested_info.rb +108 -0
  154. data/lib/active_scaffold/data_structures/set.rb +62 -0
  155. data/lib/active_scaffold/data_structures/sorting.rb +168 -0
  156. data/lib/active_scaffold/finder.rb +333 -0
  157. data/lib/active_scaffold/helpers/association_helpers.rb +40 -0
  158. data/lib/active_scaffold/helpers/controller_helpers.rb +40 -0
  159. data/lib/active_scaffold/helpers/country_helpers.rb +352 -0
  160. data/lib/active_scaffold/helpers/form_column_helpers.rb +343 -0
  161. data/lib/active_scaffold/helpers/human_condition_helpers.rb +59 -0
  162. data/lib/active_scaffold/helpers/id_helpers.rb +131 -0
  163. data/lib/active_scaffold/helpers/list_column_helpers.rb +363 -0
  164. data/lib/active_scaffold/helpers/pagination_helpers.rb +55 -0
  165. data/lib/active_scaffold/helpers/search_column_helpers.rb +238 -0
  166. data/lib/active_scaffold/helpers/show_column_helpers.rb +46 -0
  167. data/lib/active_scaffold/helpers/view_helpers.rb +315 -0
  168. data/lib/active_scaffold/locale/de.rb +113 -0
  169. data/lib/active_scaffold/locale/en.rb +118 -0
  170. data/lib/active_scaffold/locale/es.yml +112 -0
  171. data/lib/active_scaffold/locale/fr.rb +113 -0
  172. data/lib/active_scaffold/locale/hu.yml +63 -0
  173. data/lib/active_scaffold/locale/ja.yml +64 -0
  174. data/lib/active_scaffold/locale/ru.yml +62 -0
  175. data/lib/active_scaffold/marked_model.rb +38 -0
  176. data/lib/dhtml_confirm.rb +54 -0
  177. data/lib/extensions/action_controller_rendering.rb +20 -0
  178. data/lib/extensions/action_view_rendering.rb +113 -0
  179. data/lib/extensions/action_view_resolver.rb +7 -0
  180. data/lib/extensions/active_record_offset.rb +12 -0
  181. data/lib/extensions/array.rb +7 -0
  182. data/lib/extensions/localize.rb +10 -0
  183. data/lib/extensions/name_option_for_datetime.rb +12 -0
  184. data/lib/extensions/nil_id_in_url_params.rb +7 -0
  185. data/lib/extensions/paginator_extensions.rb +26 -0
  186. data/lib/extensions/reverse_associations.rb +62 -0
  187. data/lib/extensions/routing_mapper.rb +34 -0
  188. data/lib/extensions/to_label.rb +8 -0
  189. data/lib/extensions/unsaved_associated.rb +61 -0
  190. data/lib/extensions/unsaved_record.rb +20 -0
  191. data/lib/extensions/usa_state.rb +46 -0
  192. data/lib/generators/active_scaffold/USAGE +29 -0
  193. data/lib/generators/active_scaffold/active_scaffold_generator.rb +20 -0
  194. data/lib/generators/active_scaffold_controller/USAGE +19 -0
  195. data/lib/generators/active_scaffold_controller/active_scaffold_controller_generator.rb +28 -0
  196. data/lib/generators/active_scaffold_controller/templates/controller.rb +4 -0
  197. data/lib/generators/active_scaffold_setup/USAGE +10 -0
  198. data/lib/generators/active_scaffold_setup/active_scaffold_setup_generator.rb +53 -0
  199. data/lib/paginator.rb +136 -0
  200. data/lib/responds_to_parent.rb +70 -0
  201. data/public/blank.html +33 -0
  202. data/shoulda_macros/macros.rb +136 -0
  203. data/test/bridges/bridge_test.rb +47 -0
  204. data/test/config/base_test.rb +15 -0
  205. data/test/config/create_test.rb +55 -0
  206. data/test/config/list_test.rb +74 -0
  207. data/test/config/show_test.rb +43 -0
  208. data/test/config/update_test.rb +17 -0
  209. data/test/const_mocker.rb +36 -0
  210. data/test/data_structures/action_columns_test.rb +113 -0
  211. data/test/data_structures/action_link_test.rb +78 -0
  212. data/test/data_structures/action_links_test.rb +78 -0
  213. data/test/data_structures/actions_test.rb +25 -0
  214. data/test/data_structures/association_column_test.rb +42 -0
  215. data/test/data_structures/column_test.rb +185 -0
  216. data/test/data_structures/columns_test.rb +69 -0
  217. data/test/data_structures/error_message_test.rb +28 -0
  218. data/test/data_structures/set_test.rb +86 -0
  219. data/test/data_structures/sorting_test.rb +126 -0
  220. data/test/data_structures/standard_column_test.rb +24 -0
  221. data/test/data_structures/virtual_column_test.rb +23 -0
  222. data/test/extensions/active_record_test.rb +45 -0
  223. data/test/extensions/array_test.rb +12 -0
  224. data/test/helpers/form_column_helpers_test.rb +31 -0
  225. data/test/helpers/list_column_helpers_test.rb +31 -0
  226. data/test/helpers/pagination_helpers_test.rb +55 -0
  227. data/test/misc/active_record_permissions_test.rb +154 -0
  228. data/test/misc/attribute_params_test.rb +110 -0
  229. data/test/misc/configurable_test.rb +96 -0
  230. data/test/misc/constraints_test.rb +193 -0
  231. data/test/misc/finder_test.rb +93 -0
  232. data/test/misc/lang_test.rb +12 -0
  233. data/test/mock_app/.gitignore +2 -0
  234. data/test/mock_app/app/controllers/application_controller.rb +10 -0
  235. data/test/mock_app/app/helpers/application_helper.rb +3 -0
  236. data/test/mock_app/config/boot.rb +110 -0
  237. data/test/mock_app/config/database.yml +16 -0
  238. data/test/mock_app/config/environment.rb +43 -0
  239. data/test/mock_app/config/environments/development.rb +17 -0
  240. data/test/mock_app/config/environments/production.rb +28 -0
  241. data/test/mock_app/config/environments/test.rb +28 -0
  242. data/test/mock_app/config/initializers/backtrace_silencers.rb +7 -0
  243. data/test/mock_app/config/initializers/inflections.rb +10 -0
  244. data/test/mock_app/config/initializers/mime_types.rb +5 -0
  245. data/test/mock_app/config/initializers/new_rails_defaults.rb +19 -0
  246. data/test/mock_app/config/initializers/session_store.rb +15 -0
  247. data/test/mock_app/config/locales/en.yml +5 -0
  248. data/test/mock_app/config/routes.rb +43 -0
  249. data/test/mock_app/db/test.sqlite3 +1 -0
  250. data/test/mock_app/public/blank.html +33 -0
  251. data/test/mock_app/public/images/active_scaffold/DO_NOT_EDIT +2 -0
  252. data/test/mock_app/public/images/active_scaffold/default/add.gif +0 -0
  253. data/test/mock_app/public/images/active_scaffold/default/arrow_down.gif +0 -0
  254. data/test/mock_app/public/images/active_scaffold/default/arrow_up.gif +0 -0
  255. data/test/mock_app/public/images/active_scaffold/default/close.gif +0 -0
  256. data/test/mock_app/public/images/active_scaffold/default/cross.png +0 -0
  257. data/test/mock_app/public/images/active_scaffold/default/indicator-small.gif +0 -0
  258. data/test/mock_app/public/images/active_scaffold/default/indicator.gif +0 -0
  259. data/test/mock_app/public/images/active_scaffold/default/magnifier.png +0 -0
  260. data/test/mock_app/public/javascripts/active_scaffold/DO_NOT_EDIT +2 -0
  261. data/test/mock_app/public/javascripts/active_scaffold/default/active_scaffold.js +532 -0
  262. data/test/mock_app/public/javascripts/active_scaffold/default/dhtml_history.js +867 -0
  263. data/test/mock_app/public/javascripts/active_scaffold/default/form_enhancements.js +117 -0
  264. data/test/mock_app/public/javascripts/active_scaffold/default/rico_corner.js +370 -0
  265. data/test/mock_app/public/stylesheets/active_scaffold/DO_NOT_EDIT +2 -0
  266. data/test/mock_app/public/stylesheets/active_scaffold/default/stylesheet-ie.css +35 -0
  267. data/test/mock_app/public/stylesheets/active_scaffold/default/stylesheet.css +839 -0
  268. data/test/model_stub.rb +55 -0
  269. data/test/run_all.rb +8 -0
  270. data/test/test_helper.rb +39 -0
  271. data/uninstall.rb +13 -0
  272. metadata +478 -0
@@ -0,0 +1,207 @@
1
+ module ActiveScaffold
2
+ # Provides support for param hashes assumed to be model attributes.
3
+ # Support is primarily needed for creating/editing associated records using a nested hash structure.
4
+ #
5
+ # Paradigm Params Hash (should write unit tests on this):
6
+ # params[:record] = {
7
+ # # a simple record attribute
8
+ # 'name' => 'John',
9
+ # # a plural association hash
10
+ # 'roles' => {
11
+ # # associate with an existing role
12
+ # '5' => {'id' => 5}
13
+ # # associate with an existing role and edit it
14
+ # '6' => {'id' => 6, 'name' => 'designer'}
15
+ # # create and associate a new role
16
+ # '124521' => {'name' => 'marketer'}
17
+ # }
18
+ # # a singular association hash
19
+ # 'location' => {'id' => 12, 'city' => 'New York'}
20
+ # }
21
+ #
22
+ # Simpler association structures are also supported, like:
23
+ # params[:record] = {
24
+ # # a simple record attribute
25
+ # 'name' => 'John',
26
+ # # a plural association ... all ids refer to existing records
27
+ # 'roles' => ['5', '6'],
28
+ # # a singular association ... all ids refer to existing records
29
+ # 'location' => '12'
30
+ # }
31
+ module AttributeParams
32
+ protected
33
+ # Takes attributes (as from params[:record]) and applies them to the parent_record. Also looks for
34
+ # association attributes and attempts to instantiate them as associated objects.
35
+ #
36
+ # This is a secure way to apply params to a record, because it's based on a loop over the columns
37
+ # set. The columns set will not yield unauthorized columns, and it will not yield unregistered columns.
38
+ def update_record_from_params(parent_record, columns, attributes)
39
+ crud_type = parent_record.new_record? ? :create : :update
40
+ return parent_record unless parent_record.authorized_for?(:crud_type => crud_type)
41
+
42
+ multi_parameter_attributes = {}
43
+ attributes.each do |k, v|
44
+ next unless k.include? '('
45
+ column_name = k.split('(').first.to_sym
46
+ multi_parameter_attributes[column_name] ||= []
47
+ multi_parameter_attributes[column_name] << [k, v]
48
+ end
49
+
50
+ columns.each :for => parent_record, :crud_type => crud_type, :flatten => true do |column|
51
+ # Set any passthrough parameters that may be associated with this column (ie, file column "keep" and "temp" attributes)
52
+ unless column.params.empty?
53
+ column.params.each{|p| parent_record.send("#{p}=", attributes[p]) if attributes.has_key? p}
54
+ end
55
+
56
+ if multi_parameter_attributes.has_key? column.name
57
+ parent_record.send(:assign_multiparameter_attributes, multi_parameter_attributes[column.name])
58
+ elsif attributes.has_key? column.name
59
+ value = column_value_from_param_value(parent_record, column, attributes[column.name])
60
+
61
+ # we avoid assigning a value that already exists because otherwise has_one associations will break (AR bug in has_one_association.rb#replace)
62
+ parent_record.send("#{column.name}=", value) unless parent_record.send(column.name) == value
63
+
64
+ # plural associations may not actually appear in the params if all of the options have been unselected or cleared away.
65
+ # the "form_ui" check is necessary, becuase without it we have problems
66
+ # with subforms. the UI cuts out deep associations, which means they're not present in the
67
+ # params even though they're in the columns list. the result is that associations were being
68
+ # emptied out way too often.
69
+ elsif column.form_ui and column.plural_association?
70
+ parent_record.send("#{column.name}=", [])
71
+ end
72
+ end
73
+
74
+ if parent_record.new_record?
75
+ parent_record.class.reflect_on_all_associations.each do |a|
76
+ next unless [:has_one, :has_many].include?(a.macro) and not a.options[:through]
77
+ next unless association_proxy = parent_record.send(a.name)
78
+
79
+ raise ActiveScaffold::ReverseAssociationRequired, "Association #{a.name}: In order to support :has_one and :has_many where the parent record is new and the child record(s) validate the presence of the parent, ActiveScaffold requires the reverse association (the belongs_to)." unless a.reverse
80
+
81
+ association_proxy = [association_proxy] if a.macro == :has_one
82
+ association_proxy.each { |record| record.send("#{a.reverse}=", parent_record) }
83
+ end
84
+ end
85
+
86
+ parent_record
87
+ end
88
+
89
+ def manage_nested_record_from_params(parent_record, column, attributes)
90
+ record = find_or_create_for_params(attributes, column, parent_record)
91
+ if record
92
+ record_columns = active_scaffold_config_for(column.association.klass).subform.columns
93
+ update_record_from_params(record, record_columns, attributes)
94
+ record.unsaved = true
95
+ end
96
+ record
97
+ end
98
+
99
+ def column_value_from_param_value(parent_record, column, value)
100
+ # convert the value, possibly by instantiating associated objects
101
+ if value.is_a?(Hash)
102
+ column_value_from_param_hash_value(parent_record, column, value)
103
+ else
104
+ column_value_from_param_simple_value(parent_record, column, value)
105
+ end
106
+ end
107
+
108
+ def column_value_from_param_simple_value(parent_record, column, value)
109
+ if column.singular_association?
110
+ # it's a single id
111
+ column.association.klass.find(value) if value and not value.empty?
112
+ elsif column.plural_association?
113
+ # it's an array of ids
114
+ if value and not value.empty?
115
+ ids = value.select {|id| id.respond_to?(:empty?) ? !id.empty? : true}
116
+ ids.empty? ? [] : column.association.klass.find(ids)
117
+ end
118
+ elsif column.column && column.column.number? && [:i18n_number, :currency].include?(column.options[:format])
119
+ self.class.i18n_number_to_native_format(value)
120
+ else
121
+ # convert empty strings into nil. this works better with 'null => true' columns (and validations),
122
+ # and 'null => false' columns should just convert back to an empty string.
123
+ # ... but we can at least check the ConnectionAdapter::Column object to see if nulls are allowed
124
+ value = nil if value.is_a? String and value.empty? and !column.column.nil? and column.column.null
125
+ value
126
+ end
127
+ end
128
+
129
+ def column_value_from_param_hash_value(parent_record, column, value)
130
+ # this is just for backwards compatibility. we should clean this up in 2.0.
131
+ if column.form_ui == :select
132
+ ids = if column.singular_association?
133
+ value[:id]
134
+ else
135
+ value.values.collect {|hash| hash[:id]}
136
+ end
137
+ (ids and not ids.empty?) ? column.association.klass.find(ids) : nil
138
+
139
+ elsif column.singular_association?
140
+ manage_nested_record_from_params(parent_record, column, value)
141
+ elsif column.plural_association?
142
+ value.collect {|key_value_pair| manage_nested_record_from_params(parent_record, column, key_value_pair[1])}.compact
143
+ else
144
+ value
145
+ end
146
+ end
147
+
148
+ # Attempts to create or find an instance of klass (which must be an ActiveRecord object) from the
149
+ # request parameters given. If params[:id] exists it will attempt to find an existing object
150
+ # otherwise it will build a new one.
151
+ def find_or_create_for_params(params, parent_column, parent_record)
152
+ current = parent_record.send(parent_column.name)
153
+ klass = parent_column.association.klass
154
+ return nil if parent_column.show_blank_record and attributes_hash_is_empty?(params, klass)
155
+
156
+ if params.has_key? :id
157
+ # modifying the current object of a singular association
158
+ if current and current.is_a? ActiveRecord::Base and current.id.to_s == params[:id]
159
+ return current
160
+ # modifying one of the current objects in a plural association
161
+ elsif current and current.respond_to?(:any?) and current.any? {|o| o.id.to_s == params[:id]}
162
+ return current.detect {|o| o.id.to_s == params[:id]}
163
+ # attaching an existing but not-current object
164
+ else
165
+ return klass.find(params[:id])
166
+ end
167
+ else
168
+ if klass.authorized_for?(:crud_type => :create)
169
+ if parent_column.singular_association?
170
+ return parent_record.send("build_#{parent_column.name}")
171
+ else
172
+ return parent_record.send(parent_column.name).build
173
+ end
174
+ end
175
+ end
176
+ end
177
+
178
+ # Determines whether the given attributes hash is "empty".
179
+ # This isn't a literal emptiness - it's an attempt to discern whether the user intended it to be empty or not.
180
+ def attributes_hash_is_empty?(hash, klass)
181
+ ignore_column_types = [:boolean]
182
+ hash.all? do |key,value|
183
+ # convert any possible multi-parameter attributes like 'created_at(5i)' to simply 'created_at'
184
+ parts = key.to_s.split('(')
185
+ #old style date form management... ignore them too
186
+ ignore_column_types = [:boolean, :datetime, :date, :time] if parts.length > 1
187
+ column_name = parts.first
188
+ column = klass.columns_hash[column_name]
189
+
190
+ # booleans and datetimes will always have a value. so we ignore them when checking whether the hash is empty.
191
+ # this could be a bad idea. but the current situation (excess record entry) seems worse.
192
+ next true if column and ignore_column_types.include?(column.type)
193
+
194
+ # defaults are pre-filled on the form. we can't use them to determine if the user intends a new row.
195
+ next true if column and value == column.default.to_s
196
+
197
+ if value.is_a?(Hash)
198
+ attributes_hash_is_empty?(value, klass)
199
+ elsif value.is_a?(Array)
200
+ value.any? {|id| id.respond_to?(:empty?) ? !id.empty? : true}
201
+ else
202
+ value.respond_to?(:empty?) ? value.empty? : false
203
+ end
204
+ end
205
+ end
206
+ end
207
+ end
@@ -0,0 +1,5 @@
1
+ ActiveScaffold::Bridges.bridge "Ancestry" do
2
+ install do
3
+ require File.join(File.dirname(__FILE__), "lib/ancestry_bridge.rb")
4
+ end
5
+ end
@@ -0,0 +1,38 @@
1
+ ActiveScaffold::Config::Core.class_eval do
2
+ def initialize_with_ancestry(model_id)
3
+ initialize_without_ancestry(model_id)
4
+
5
+ return unless self.model.respond_to? :ancestry_column
6
+
7
+ col_config = self.columns[self.model.ancestry_column]
8
+ unless col_config.nil?
9
+ col_config.form_ui = :ancestry
10
+ create.columns.exclude :ancestry
11
+ list.columns.exclude :ancestry
12
+ end
13
+ end
14
+
15
+ alias_method_chain :initialize, :ancestry
16
+ end
17
+
18
+ module ActiveScaffold
19
+ module AncestryBridge
20
+ module FormColumnHelpers
21
+ def active_scaffold_input_ancestry(column, options)
22
+ select_options = []
23
+ traverse_ancestry = proc do|key, value|
24
+ unless key == @record
25
+ select_options << ["#{'__' * key.depth}#{key.to_label}", key.id]
26
+ value.each(&traverse_ancestry) if value.is_a?(Hash) && !value.empty?
27
+ end
28
+ end
29
+ @record.class.arrange.each(&traverse_ancestry)
30
+ select(:record, :ancestry, select_options, { :selected => @record.send(:ancestry) }, options)
31
+ end
32
+ end
33
+ end
34
+ end
35
+
36
+ ActionView::Base.class_eval do
37
+ include ActiveScaffold::AncestryBridge::FormColumnHelpers
38
+ end
@@ -0,0 +1,52 @@
1
+ module ActiveScaffold
2
+ module Bridges
3
+ def self.bridge(name, &block)
4
+ ActiveScaffold::Bridges::Bridge.new(name, &block)
5
+ end
6
+
7
+ class Bridge
8
+ attr_accessor :name
9
+ cattr_accessor :bridges
10
+ cattr_accessor :bridges_run
11
+ self.bridges = []
12
+
13
+ def initialize(name, &block)
14
+ self.name = name
15
+ @install = nil
16
+ # by convention and default, use the bridge name as the required constant for installation
17
+ @install_if = lambda { Object.const_defined?(name) }
18
+ self.instance_eval(&block)
19
+
20
+ ActiveScaffold::Bridges::Bridge.bridges << self
21
+ end
22
+
23
+ # Set the install block
24
+ def install(&block)
25
+ @install = block
26
+ end
27
+
28
+ # Set the install_if block (to check to see whether or not to install the block)
29
+ def install?(&block)
30
+ @install_if = block
31
+ end
32
+
33
+
34
+ def run
35
+ raise(ArgumentError, "install and install? not defined for bridge #{name}" ) unless @install && @install_if
36
+ @install.call if @install_if.call
37
+ end
38
+
39
+ def self.run_all
40
+ return false if self.bridges_run
41
+ ActiveScaffold::Bridges::Bridge.bridges.each{|bridge|
42
+ bridge.run
43
+ }
44
+ self.bridges_run=true
45
+ end
46
+ end
47
+ end
48
+ end
49
+
50
+ Dir[File.join(File.dirname(__FILE__), "*/bridge.rb")].each{|bridge_require|
51
+ require bridge_require
52
+ }
@@ -0,0 +1,16 @@
1
+ ActiveScaffold::Bridges.bridge "CalendarDateSelect" do
2
+ install do
3
+ # check to see if the old bridge was installed. If so, warn them
4
+ # we can detect this by checking to see if the bridge was installed before calling this code
5
+
6
+ if ActiveScaffold::Config::Core.instance_methods.include?("initialize_with_calendar_date_select")
7
+ raise RuntimeError, "We've detected that you have active_scaffold_calendar_date_select_bridge installed. This plugin has been moved to core. Please remove active_scaffold_calendar_date_select_bridge to prevent any conflicts"
8
+ end
9
+
10
+ require File.join(File.dirname(__FILE__), "lib/as_cds_bridge.rb")
11
+ end
12
+
13
+ install? do
14
+ Object.const_defined?(name) && ActiveScaffold.js_framework == :prototype
15
+ end
16
+ end
@@ -0,0 +1,79 @@
1
+ module ActiveScaffold::Config
2
+ class Core < Base
3
+
4
+ def initialize_with_calendar_date_select(model_id)
5
+ initialize_without_calendar_date_select(model_id)
6
+
7
+ calendar_date_select_fields = self.model.columns.collect{|c| c.name.to_sym if [:date, :datetime].include?(c.type) }.compact
8
+ # check to see if file column was used on the model
9
+ return if calendar_date_select_fields.empty?
10
+
11
+ # automatically set the forum_ui to a file column
12
+ calendar_date_select_fields.each{|field|
13
+ self.columns[field].form_ui = :calendar_date_select
14
+ }
15
+ end
16
+
17
+ alias_method_chain :initialize, :calendar_date_select
18
+
19
+ end
20
+ end
21
+
22
+
23
+ module ActiveScaffold
24
+ module Bridges
25
+ module CalendarDateSelectBridge
26
+ # Helpers that assist with the rendering of a Form Column
27
+ module FormColumnHelpers
28
+ def active_scaffold_input_calendar_date_select(column, options)
29
+ options[:class] = "#{options[:class]} text-input".strip
30
+ calendar_date_select("record", column.name, options.merge(column.options))
31
+ end
32
+ end
33
+
34
+ module SearchColumnHelpers
35
+ def active_scaffold_search_date_bridge_calendar_control(column, options, current_search, name)
36
+ if current_search.is_a? Hash
37
+ value = controller.class.condition_value_for_datetime(current_search[name], column.column.type == :date ? :to_date : :to_time)
38
+ else
39
+ value = current_search
40
+ end
41
+ calendar_date_select("record", column.name,
42
+ {:name => "#{options[:name]}[#{name}]",
43
+ :value => (value ? l(value) : nil),
44
+ :class => 'text-input',
45
+ :id => "#{options[:id]}_#{name}",
46
+ :time => column_datetime?(column) ? true : false,
47
+ :style => "display:#{(options[:show].nil? || options[:show]) ? '' : 'none'}"})
48
+ end
49
+ end
50
+
51
+ module ViewHelpers
52
+ # Provides stylesheets to include with +stylesheet_link_tag+
53
+ def active_scaffold_stylesheets(frontend = :default)
54
+ super + [calendar_date_select_stylesheets]
55
+ end
56
+
57
+ # Provides stylesheets to include with +stylesheet_link_tag+
58
+ def active_scaffold_javascripts(frontend = :default)
59
+ super + [calendar_date_select_javascripts]
60
+ end
61
+ end
62
+ end
63
+ end
64
+ end
65
+
66
+ ActionView::Base.class_eval do
67
+ include ActiveScaffold::Bridges::CalendarDateSelectBridge::FormColumnHelpers
68
+ include ActiveScaffold::Bridges::Shared::DateBridge::SearchColumnHelpers
69
+ alias_method :active_scaffold_search_calendar_date_select, :active_scaffold_search_date_bridge
70
+ include ActiveScaffold::Bridges::Shared::DateBridge::HumanConditionHelpers
71
+ alias_method :active_scaffold_human_condition_calendar_date_select, :active_scaffold_human_condition_date_bridge
72
+ include ActiveScaffold::Bridges::CalendarDateSelectBridge::SearchColumnHelpers
73
+ include ActiveScaffold::Bridges::CalendarDateSelectBridge::ViewHelpers
74
+ end
75
+
76
+ ActiveScaffold::Finder::ClassMethods.module_eval do
77
+ include ActiveScaffold::Bridges::Shared::DateBridge::Finder::ClassMethods
78
+ alias_method :condition_for_calendar_date_select_type, :condition_for_date_bridge_type
79
+ end
@@ -0,0 +1,7 @@
1
+ ActiveScaffold::Bridges.bridge "CarrierWave" do
2
+ install do
3
+ require File.join(File.dirname(__FILE__), "lib/form_ui")
4
+ require File.join(File.dirname(__FILE__), "lib/list_ui")
5
+ ActiveScaffold::Config::Core.send :include, ActiveScaffold::Bridges::Carrierwave::Lib::CarrierwaveBridge
6
+ end
7
+ end
@@ -0,0 +1,38 @@
1
+ module ActiveScaffold
2
+ module Bridges
3
+ module Carrierwave
4
+ module Lib
5
+ module CarrierwaveBridge
6
+ def initialize_with_carrierwave(model_id)
7
+ initialize_without_carrierwave(model_id)
8
+ return unless self.model.respond_to?(:uploaders) && self.model.uploaders.present?
9
+
10
+ self.update.multipart = true
11
+ self.create.multipart = true
12
+
13
+ self.model.uploaders.keys.each do |field|
14
+ configure_carrierwave_field(field.to_sym)
15
+ # define the "delete" helper for use with active scaffold, unless it's already defined
16
+ ActiveScaffold::Bridges::Carrierwave::Lib::CarrierwaveBridgeHelpers.generate_delete_helper(self.model, field)
17
+ end
18
+ end
19
+
20
+ def self.included(base)
21
+ base.alias_method_chain :initialize, :carrierwave
22
+ end
23
+
24
+ private
25
+ def configure_carrierwave_field(field)
26
+ self.columns << field
27
+ self.columns[field].form_ui ||= :carrierwave
28
+ self.columns[field].params.add "delete_#{field}"
29
+
30
+ # [:file_name, :content_type, :file_size, :updated_at].each do |f|
31
+ # self.columns.exclude("#{field}_#{f}".to_sym)
32
+ # end
33
+ end
34
+ end
35
+ end
36
+ end
37
+ end
38
+ end