active_scaffold 3.3.3 → 3.4.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 (198) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG +39 -0
  3. data/README.md +5 -3
  4. data/app/assets/images/active_scaffold/refresh.png +0 -0
  5. data/app/assets/javascripts/jquery/active_scaffold.js +182 -91
  6. data/app/assets/javascripts/jquery/date_picker_bridge.js.erb +14 -16
  7. data/app/assets/javascripts/jquery/draggable_lists.js +33 -26
  8. data/app/assets/javascripts/jquery/jquery.editinplace.js +3 -3
  9. data/app/assets/javascripts/prototype/active_scaffold.js +61 -19
  10. data/app/assets/stylesheets/active_scaffold_colors.css.scss +4 -0
  11. data/app/assets/stylesheets/active_scaffold_images.css.scss +3 -0
  12. data/app/assets/stylesheets/active_scaffold_layout.css +23 -2
  13. data/app/views/active_scaffold_overrides/_add_existing_form.html.erb +1 -3
  14. data/app/views/active_scaffold_overrides/_base_form.html.erb +7 -5
  15. data/app/views/active_scaffold_overrides/_field_search.html.erb +1 -2
  16. data/app/views/active_scaffold_overrides/_form.html.erb +6 -4
  17. data/app/views/active_scaffold_overrides/_form_association.html.erb +4 -3
  18. data/app/views/active_scaffold_overrides/_form_association_footer.html.erb +5 -5
  19. data/app/views/active_scaffold_overrides/_form_association_record.html.erb +8 -6
  20. data/app/views/active_scaffold_overrides/_horizontal_subform_header.html.erb +3 -2
  21. data/app/views/active_scaffold_overrides/_list.html.erb +8 -6
  22. data/app/views/active_scaffold_overrides/_list_column_headings.html.erb +1 -4
  23. data/app/views/active_scaffold_overrides/_list_pagination.html.erb +4 -4
  24. data/app/views/active_scaffold_overrides/_list_pagination_links.html.erb +1 -1
  25. data/app/views/active_scaffold_overrides/_list_record.html.erb +3 -3
  26. data/app/views/active_scaffold_overrides/_refresh_list.js.erb +8 -1
  27. data/app/views/active_scaffold_overrides/_search.html.erb +7 -13
  28. data/app/views/active_scaffold_overrides/_show_columns.html.erb +1 -1
  29. data/app/views/active_scaffold_overrides/on_create.js.erb +4 -4
  30. data/app/views/active_scaffold_overrides/render_field_inplace.html.erb +1 -1
  31. data/app/views/active_scaffold_overrides/row.js.erb +1 -1
  32. data/config/locales/de.yml +106 -95
  33. data/config/locales/en.yml +108 -97
  34. data/config/locales/es.yml +109 -98
  35. data/config/locales/fr.yml +108 -97
  36. data/config/locales/hu.yml +109 -98
  37. data/config/locales/ja.yml +100 -89
  38. data/config/locales/ru.yml +115 -104
  39. data/lib/active_scaffold.rb +18 -294
  40. data/lib/active_scaffold/actions/common_search.rb +50 -17
  41. data/lib/active_scaffold/actions/core.rb +93 -22
  42. data/lib/active_scaffold/actions/create.rb +15 -6
  43. data/lib/active_scaffold/actions/field_search.rb +68 -60
  44. data/lib/active_scaffold/actions/list.rb +49 -28
  45. data/lib/active_scaffold/actions/nested.rb +14 -6
  46. data/lib/active_scaffold/actions/search.rb +36 -35
  47. data/lib/active_scaffold/actions/show.rb +9 -4
  48. data/lib/active_scaffold/actions/subform.rb +1 -1
  49. data/lib/active_scaffold/actions/update.rb +22 -7
  50. data/lib/active_scaffold/active_record_permissions.rb +125 -118
  51. data/lib/active_scaffold/attribute_params.rb +84 -66
  52. data/lib/active_scaffold/bridges.rb +3 -3
  53. data/lib/active_scaffold/bridges/ancestry/ancestry_bridge.rb +10 -5
  54. data/lib/active_scaffold/bridges/cancan.rb +2 -1
  55. data/lib/active_scaffold/bridges/cancan/cancan_bridge.rb +13 -2
  56. data/lib/active_scaffold/bridges/carrierwave/form_ui.rb +11 -6
  57. data/lib/active_scaffold/bridges/chosen/helpers.rb +2 -2
  58. data/lib/active_scaffold/bridges/country_helper/country_helper_bridge.rb +45 -29
  59. data/lib/active_scaffold/bridges/date_picker/ext.rb +11 -6
  60. data/lib/active_scaffold/bridges/date_picker/helper.rb +5 -1
  61. data/lib/active_scaffold/bridges/dragonfly/form_ui.rb +10 -5
  62. data/lib/active_scaffold/bridges/dragonfly/list_ui.rb +6 -1
  63. data/lib/active_scaffold/bridges/file_column/form_ui.rb +12 -11
  64. data/lib/active_scaffold/bridges/paperclip/form_ui.rb +14 -6
  65. data/lib/active_scaffold/bridges/paperclip/list_ui.rb +1 -1
  66. data/lib/active_scaffold/bridges/record_select/helpers.rb +15 -12
  67. data/lib/active_scaffold/bridges/shared/date_bridge.rb +7 -8
  68. data/lib/active_scaffold/bridges/tiny_mce.rb +5 -3
  69. data/lib/active_scaffold/bridges/tiny_mce/helpers.rb +4 -5
  70. data/lib/active_scaffold/config/base.rb +4 -0
  71. data/lib/active_scaffold/config/core.rb +12 -5
  72. data/lib/active_scaffold/config/delete.rb +0 -2
  73. data/lib/active_scaffold/config/field_search.rb +1 -4
  74. data/lib/active_scaffold/config/form.rb +0 -2
  75. data/lib/active_scaffold/config/list.rb +31 -1
  76. data/lib/active_scaffold/config/search.rb +0 -3
  77. data/lib/active_scaffold/config/show.rb +0 -6
  78. data/lib/active_scaffold/config/subform.rb +1 -0
  79. data/lib/active_scaffold/configurable.rb +2 -2
  80. data/lib/active_scaffold/constraints.rb +11 -14
  81. data/lib/active_scaffold/core.rb +277 -0
  82. data/lib/active_scaffold/data_structures/action_columns.rb +18 -2
  83. data/lib/active_scaffold/data_structures/action_link.rb +25 -6
  84. data/lib/active_scaffold/data_structures/action_links.rb +9 -4
  85. data/lib/active_scaffold/data_structures/actions.rb +1 -1
  86. data/lib/active_scaffold/data_structures/column.rb +6 -6
  87. data/lib/active_scaffold/data_structures/columns.rb +2 -2
  88. data/lib/active_scaffold/data_structures/nested_info.rb +5 -1
  89. data/lib/active_scaffold/data_structures/sorting.rb +15 -5
  90. data/lib/active_scaffold/delayed_setup.rb +30 -0
  91. data/lib/active_scaffold/engine.rb +25 -0
  92. data/lib/active_scaffold/extensions/action_view_rendering.rb +1 -1
  93. data/lib/active_scaffold/extensions/left_outer_joins.rb +61 -21
  94. data/lib/active_scaffold/extensions/localize.rb +1 -1
  95. data/lib/active_scaffold/extensions/name_option_for_datetime.rb +13 -8
  96. data/lib/active_scaffold/extensions/paginator_extensions.rb +5 -1
  97. data/lib/active_scaffold/extensions/reverse_associations.rb +1 -0
  98. data/lib/active_scaffold/extensions/routing_mapper.rb +1 -1
  99. data/lib/active_scaffold/extensions/unsaved_record.rb +4 -6
  100. data/lib/active_scaffold/finder.rb +79 -27
  101. data/lib/active_scaffold/helpers/association_helpers.rb +48 -18
  102. data/lib/active_scaffold/helpers/controller_helpers.rb +19 -10
  103. data/lib/active_scaffold/helpers/form_column_helpers.rb +185 -87
  104. data/lib/active_scaffold/helpers/human_condition_helpers.rb +2 -1
  105. data/lib/active_scaffold/helpers/id_helpers.rb +14 -8
  106. data/lib/active_scaffold/helpers/list_column_helpers.rb +65 -56
  107. data/lib/active_scaffold/helpers/pagination_helpers.rb +5 -1
  108. data/lib/active_scaffold/helpers/search_column_helpers.rb +21 -18
  109. data/lib/active_scaffold/helpers/view_helpers.rb +102 -64
  110. data/lib/active_scaffold/responds_to_parent.rb +39 -64
  111. data/lib/active_scaffold/tableless.rb +129 -10
  112. data/lib/active_scaffold/version.rb +2 -2
  113. data/test/bridges/bridge_test.rb +1 -1
  114. data/test/bridges/date_picker_test.rb +2 -2
  115. data/test/bridges/paperclip_test.rb +10 -8
  116. data/test/bridges/tiny_mce_test.rb +2 -2
  117. data/test/company.rb +22 -10
  118. data/test/config/base_test.rb +1 -1
  119. data/test/config/core_test.rb +8 -6
  120. data/test/config/create_test.rb +6 -6
  121. data/test/config/delete_test.rb +4 -4
  122. data/test/config/field_search_test.rb +6 -6
  123. data/test/config/list_test.rb +7 -7
  124. data/test/config/nested_test.rb +8 -7
  125. data/test/config/search_test.rb +7 -7
  126. data/test/config/show_test.rb +5 -5
  127. data/test/config/subform_test.rb +1 -1
  128. data/test/config/update_test.rb +5 -4
  129. data/test/data_structures/action_columns_test.rb +15 -16
  130. data/test/data_structures/action_link_test.rb +10 -10
  131. data/test/data_structures/action_links_test.rb +6 -6
  132. data/test/data_structures/actions_test.rb +4 -4
  133. data/test/data_structures/association_column_test.rb +4 -4
  134. data/test/data_structures/column_test.rb +9 -9
  135. data/test/data_structures/columns_test.rb +7 -7
  136. data/test/data_structures/error_message_test.rb +2 -4
  137. data/test/data_structures/set_test.rb +13 -13
  138. data/test/data_structures/sorting_test.rb +8 -8
  139. data/test/data_structures/standard_column_test.rb +2 -2
  140. data/test/data_structures/validation_reflection_test.rb +8 -8
  141. data/test/data_structures/virtual_column_test.rb +5 -5
  142. data/test/extensions/active_record_test.rb +1 -1
  143. data/test/helpers/form_column_helpers_test.rb +5 -5
  144. data/test/helpers/list_column_helpers_test.rb +2 -1
  145. data/test/helpers/pagination_helpers_test.rb +1 -1
  146. data/test/misc/active_record_permissions_test.rb +23 -4
  147. data/test/misc/attribute_params_test.rb +304 -136
  148. data/test/misc/calculation_test.rb +55 -0
  149. data/test/misc/configurable_test.rb +22 -21
  150. data/test/misc/constraints_test.rb +10 -7
  151. data/test/misc/convert_numbers_format_test.rb +149 -0
  152. data/test/misc/finder_test.rb +17 -13
  153. data/test/misc/lang_test.rb +1 -1
  154. data/test/misc/tableless_test.rb +18 -0
  155. data/test/mock_app/app/controllers/addresses_controller.rb +4 -0
  156. data/test/mock_app/app/controllers/buildings_controller.rb +4 -0
  157. data/test/mock_app/app/controllers/cars_controller.rb +4 -0
  158. data/test/mock_app/app/controllers/contacts_controller.rb +4 -0
  159. data/test/mock_app/app/controllers/floors_controller.rb +6 -0
  160. data/test/mock_app/app/controllers/people_controller.rb +4 -0
  161. data/test/mock_app/app/models/address.rb +3 -0
  162. data/test/mock_app/app/models/building.rb +8 -0
  163. data/test/mock_app/app/models/car.rb +3 -0
  164. data/test/mock_app/app/models/contact.rb +3 -0
  165. data/test/mock_app/app/models/file_model.rb +19 -0
  166. data/test/mock_app/app/models/floor.rb +8 -0
  167. data/test/mock_app/app/models/person.rb +11 -0
  168. data/test/mock_app/config/application.rb +2 -0
  169. data/test/mock_app/config/environments/test.rb +1 -1
  170. data/test/mock_app/config/initializers/secret_token.rb +5 -1
  171. data/test/mock_app/config/routes.rb +1 -1
  172. data/test/mock_app/db/schema.rb +51 -0
  173. data/test/model_stub.rb +3 -3
  174. data/test/test_helper.rb +15 -12
  175. metadata +51 -50
  176. data/lib/active_scaffold/extensions/array.rb +0 -7
  177. data/lib/active_scaffold/extensions/cache_association.rb +0 -16
  178. data/lib/active_scaffold/extensions/usa_state.rb +0 -46
  179. data/lib/active_scaffold_env.rb +0 -13
  180. data/test/extensions/array_test.rb +0 -12
  181. data/test/mock_app/public/blank.html +0 -33
  182. data/test/mock_app/public/images/active_scaffold/DO_NOT_EDIT +0 -2
  183. data/test/mock_app/public/images/active_scaffold/default/add.gif +0 -0
  184. data/test/mock_app/public/images/active_scaffold/default/arrow_down.gif +0 -0
  185. data/test/mock_app/public/images/active_scaffold/default/arrow_up.gif +0 -0
  186. data/test/mock_app/public/images/active_scaffold/default/close.gif +0 -0
  187. data/test/mock_app/public/images/active_scaffold/default/cross.png +0 -0
  188. data/test/mock_app/public/images/active_scaffold/default/indicator-small.gif +0 -0
  189. data/test/mock_app/public/images/active_scaffold/default/indicator.gif +0 -0
  190. data/test/mock_app/public/images/active_scaffold/default/magnifier.png +0 -0
  191. data/test/mock_app/public/javascripts/active_scaffold/DO_NOT_EDIT +0 -2
  192. data/test/mock_app/public/javascripts/active_scaffold/default/active_scaffold.js +0 -532
  193. data/test/mock_app/public/javascripts/active_scaffold/default/dhtml_history.js +0 -867
  194. data/test/mock_app/public/javascripts/active_scaffold/default/form_enhancements.js +0 -117
  195. data/test/mock_app/public/javascripts/active_scaffold/default/rico_corner.js +0 -370
  196. data/test/mock_app/public/stylesheets/active_scaffold/DO_NOT_EDIT +0 -2
  197. data/test/mock_app/public/stylesheets/active_scaffold/default/stylesheet-ie.css +0 -35
  198. data/test/mock_app/public/stylesheets/active_scaffold/default/stylesheet.css +0 -848
@@ -11,54 +11,56 @@ module ActiveScaffold
11
11
  end
12
12
 
13
13
  def active_scaffold_render_input(column, options)
14
- begin
15
- # first, check if the dev has created an override for this specific field
16
- if (method = override_form_field(column))
17
- send(method, options[:object] || @record, options)
18
- # second, check if the dev has specified a valid form_ui for this column
19
- elsif column.form_ui and (method = override_input(column.form_ui))
20
- send(method, column, options)
21
- # fallback: we get to make the decision
22
- else
23
- if column.association
24
- if column.form_ui.nil?
25
- # its an association and nothing is specified, we will assume form_ui :select
26
- active_scaffold_input_select(column, options)
27
- else
28
- # if we get here, it's because the column has a form_ui but not one ActiveScaffold knows about.
29
- raise "Unknown form_ui `#{column.form_ui}' for column `#{column.name}'"
30
- end
31
- elsif column.virtual?
32
- options[:value] = format_number_value((options[:object] || @record).send(column.name), column.options) if column.number?
33
- active_scaffold_input_virtual(column, options)
34
-
35
- else # regular model attribute column
36
- # if we (or someone else) have created a custom render option for the column type, use that
37
- if (method = override_input(column.column.type))
38
- send(method, column, options)
39
- # final ultimate fallback: use rails' generic input method
40
- else
41
- # for textual fields we pass different options
42
- text_types = [:text, :string, :integer, :float, :decimal, :date, :time, :datetime]
43
- options = active_scaffold_input_text_options(options) if text_types.include?(column.column.type)
44
- if column.column.type == :string && options[:maxlength].blank?
45
- options[:maxlength] = column.column.limit
46
- options[:size] ||= ActionView::Helpers::InstanceTag::DEFAULT_FIELD_OPTIONS["size"]
47
- end
48
- options[:include_blank] = true if column.column.null and [:date, :datetime, :time].include?(column.column.type)
49
- options[:value] = format_number_value((options[:object] || @record).send(column.name), column.options) if column.number?
50
- text_field(:record, column.name, options.merge(column.options))
14
+ record = options[:object]
15
+ ActiveSupport::Deprecation.warn "Relying on @record is deprecated, include :object in options with record.", caller if record.nil? # TODO Remove when relying on @record is removed
16
+ record ||= @record # TODO Remove when relying on @record is removed
17
+
18
+ # first, check if the dev has created an override for this specific field
19
+ if (method = override_form_field(column))
20
+ send(method, record, options)
21
+ # second, check if the dev has specified a valid form_ui for this column
22
+ elsif column.form_ui and (method = override_input(column.form_ui))
23
+ send(method, column, options)
24
+ # fallback: we get to make the decision
25
+ else
26
+ if column.association
27
+ if column.form_ui.nil?
28
+ # its an association and nothing is specified, we will assume form_ui :select
29
+ active_scaffold_input_select(column, options)
30
+ else
31
+ # if we get here, it's because the column has a form_ui but not one ActiveScaffold knows about.
32
+ raise "Unknown form_ui `#{column.form_ui}' for column `#{column.name}'"
33
+ end
34
+ elsif column.virtual?
35
+ options[:value] = format_number_value(record.send(column.name), column.options) if column.number?
36
+ active_scaffold_input_virtual(column, options)
37
+
38
+ else # regular model attribute column
39
+ # if we (or someone else) have created a custom render option for the column type, use that
40
+ if (method = override_input(column.column.type))
41
+ send(method, column, options)
42
+ # final ultimate fallback: use rails' generic input method
43
+ else
44
+ # for textual fields we pass different options
45
+ text_types = [:text, :string, :integer, :float, :decimal, :date, :time, :datetime]
46
+ options = active_scaffold_input_text_options(options) if text_types.include?(column.column.type)
47
+ if column.column.type == :string && options[:maxlength].blank?
48
+ options[:maxlength] = column.column.limit
49
+ options[:size] ||= options[:maxlength].to_i > 30 ? 30 : options[:maxlength]
51
50
  end
51
+ options[:include_blank] = true if column.column.null and [:date, :datetime, :time].include?(column.column.type)
52
+ options[:value] = format_number_value(record.send(column.name), column.options) if column.number?
53
+ text_field(:record, column.name, options.merge(column.options))
52
54
  end
53
55
  end
54
- rescue Exception => e
55
- logger.error Time.now.to_s + "#{e.inspect} -- on the ActiveScaffold column = :#{column.name} in #{controller.class}"
56
- raise e
57
56
  end
57
+ rescue Exception => e
58
+ logger.error "#{e.class.name}: #{e.message} -- on the ActiveScaffold column = :#{column.name} in #{controller.class}"
59
+ raise e
58
60
  end
59
61
 
60
62
  def active_scaffold_render_subform_column(column, scope, crud_type, readonly, add_class = false, record = nil)
61
- Rails.logger.warn "Relying on @record is deprecated, call active_scaffold_render_subform_column with record. Called from #{caller.first.gsub(/(.*:\d+):.*/, '\1')}" if record.nil? # TODO Remove when relying on @record is removed
63
+ ActiveSupport::Deprecation.warn "Relying on @record is deprecated, call with record.", caller if record.nil? # TODO Remove when relying on @record is removed
62
64
  record ||= @record # TODO Remove when relying on @record is removed
63
65
  if add_class
64
66
  col_class = []
@@ -69,7 +71,10 @@ module ActiveScaffold
69
71
  col_class = col_class.join(' ')
70
72
  end
71
73
  unless readonly and not record.new_record? or not record.authorized_for?(:crud_type => crud_type, :column => column.name)
72
- render_column(column, record, column_renders_as(column), scope, false, col_class)
74
+ renders_as = column_renders_as(column)
75
+ html = render_column(column, record, renders_as, scope, false, col_class)
76
+ html = content_tag(:div, html, active_scaffold_subform_attributes(column)) if renders_as == :subform
77
+ html
73
78
  else
74
79
  options = active_scaffold_input_options(column, scope).except(:name)
75
80
  options[:class] = "#{options[:class]} #{col_class}" if col_class
@@ -77,6 +82,13 @@ module ActiveScaffold
77
82
  end
78
83
  end
79
84
 
85
+ def active_scaffold_subform_attributes(column, column_css_class = nil)
86
+ {
87
+ :class => "sub-form #{active_scaffold_config_for(column.association.klass).subform.layout}-sub-form #{column_css_class} #{column.name}-sub-form",
88
+ :id => sub_form_id(:association => column.name)
89
+ }
90
+ end
91
+
80
92
  # the standard active scaffold options used for textual inputs
81
93
  def active_scaffold_input_text_options(options = {})
82
94
  options[:autocomplete] = 'off'
@@ -87,9 +99,10 @@ module ActiveScaffold
87
99
  # the standard active scaffold options used for class, name and scope
88
100
  def active_scaffold_input_options(column, scope = nil, options = {})
89
101
  name = scope ? "record#{scope}[#{column.name}]" : "record[#{column.name}]"
102
+ record = options[:object]
90
103
 
91
104
  # Add some HTML5 attributes for in-browser validation and better user experience
92
- if column.required? && (!@disable_required_for_new || scope.nil? || @record.persisted?)
105
+ if column.required? && (!@disable_required_for_new || scope.nil? || record.try(:persisted?))
93
106
  options[:required] = true
94
107
  end
95
108
  options[:placeholder] = column.placeholder if column.placeholder.present?
@@ -104,29 +117,34 @@ module ActiveScaffold
104
117
  { :name => name, :class => classes, :id => id_control}.merge(options)
105
118
  end
106
119
 
107
- def update_columns_options(column, scope, options)
120
+ def current_form_columns(record, scope, subform_controller = nil)
121
+ if scope
122
+ subform_controller.active_scaffold_config.subform.columns.names
123
+ elsif [:new, :create, :edit, :update, :render_field].include? action_name.to_sym
124
+ active_scaffold_config.send(record.new_record? ? :create : :update).columns.names
125
+ end
126
+ end
127
+
128
+ def update_columns_options(column, scope, options, force = false)
108
129
  record = options[:object]
109
- Rails.logger.warn "Relying on @record is deprecated, call update_columns_options with record. Called from #{caller.first.gsub(/(.*:\d+):.*/, '\1')}" if record.nil? # TODO Remove when relying on @record is removed
130
+ ActiveSupport::Deprecation.warn "Relying on @record is deprecated, include :object in options with record.", caller if record.nil? # TODO Remove when relying on @record is removed
110
131
  record ||= @record # TODO Remove when relying on @record is removed
111
- form_action = if scope
112
- subform_controller = controller.class.active_scaffold_controller_for(record.class)
113
- subform_controller.active_scaffold_config.subform
114
- elsif [:new, :create, :edit, :update, :render_field].include? params[:action].to_sym
115
- active_scaffold_config.send(record.new_record? ? :create : :update)
116
- end
117
- if form_action && column.update_columns && (column.update_columns & form_action.columns.names).present?
118
- url_params = params_for(:action => 'render_field', :column => column.name, :id => record.id)
132
+ subform_controller = controller.class.active_scaffold_controller_for(record.class) if scope
133
+ form_columns = @main_columns.try(:names)
134
+ form_columns ||= current_form_columns(record, scope, subform_controller)
135
+ if force || (form_columns && column.update_columns && (column.update_columns & form_columns).present?)
136
+ url_params = params_for(:action => 'render_field', :column => column.name, :id => record.to_param)
119
137
  url_params = url_params.except(:parent_scaffold, :association, nested.param_name) if nested? && scope
120
138
  url_params[:eid] = params[:eid] if params[:eid]
121
139
  if scope
122
- url_params[:parent_controller] ||= url_params[:controller]
140
+ url_params[:parent_controller] ||= url_params[:controller].gsub(/^\//, '')
123
141
  url_params[:controller] = subform_controller.controller_path
124
142
  url_params[:scope] = scope
125
143
  url_params[:parent_id] = params[:parent_id] || params[:id]
126
144
  end
127
145
 
128
146
  options[:class] = "#{options[:class]} update_form".strip
129
- options['data-update_url'] = url_for(url_params)
147
+ options['data-update_url'] = url_for(url_params.merge(:_added => nil, :_removed => nil))
130
148
  options['data-update_send_form'] = column.send_form_on_update_column
131
149
  options['data-update_send_form_selector'] = column.options[:send_form_selector] if column.options[:send_form_selector]
132
150
  end
@@ -171,6 +189,10 @@ module ActiveScaffold
171
189
  def label_for(column, options)
172
190
  options[:id] unless column.form_ui == :select && column.plural_association?
173
191
  end
192
+
193
+ def subform_label(column, hidden)
194
+ column.label unless hidden
195
+ end
174
196
 
175
197
  def form_hidden_attribute(column, record, scope = nil)
176
198
  %|<dl style="display: none;"><dt></dt><dd>
@@ -178,14 +200,41 @@ module ActiveScaffold
178
200
  </dd></dl>|.html_safe
179
201
  end
180
202
 
203
+ # Should this column be displayed in the subform?
204
+ def in_subform?(column, parent_record)
205
+ return true unless column.association
206
+
207
+ # Polymorphic associations can't appear because they *might* be the reverse association, and because you generally don't assign an association from the polymorphic side ... I think.
208
+ return false if column.polymorphic_association?
209
+
210
+ # A column shouldn't be in the subform if it's the reverse association to the parent
211
+ return false if column.association.inverse_for?(parent_record.class)
212
+
213
+ return true
214
+ end
215
+
216
+ def column_show_add_existing(column, record = nil)
217
+ ActiveSupport::Deprecation.warn "Relying on @record is deprecated, call with record.", caller if record.nil? # TODO Remove when relying on @record is removed
218
+ record ||= @record # TODO Remove when relying on @record is removed
219
+ (column.allow_add_existing and options_for_association_count(column.association, record) > 0)
220
+ end
221
+
222
+ def column_show_add_new(column, associated, record)
223
+ value = (column.plural_association? && !column.readonly_association?) || column.singular_association?
224
+ value &&= false unless column.association.klass.authorized_for?(:crud_type => :create)
225
+ value
226
+ end
227
+
181
228
  ##
182
229
  ## Form input methods
183
230
  ##
184
231
 
185
232
  def active_scaffold_grouped_options(column, select_options, optgroup)
186
- group_label = active_scaffold_config_for(column.association.klass).columns[optgroup].try(:association) ? :to_label : :to_s
233
+ group_column = active_scaffold_config_for(column.association.klass).columns[optgroup]
234
+ group_label = group_column.options[:label_method] if group_column
235
+ group_label ||= group_column.try(:association) ? :to_label : :to_s
187
236
  select_options.group_by(&optgroup.to_sym).collect do |group, options|
188
- [group.send(group_label), options.collect {|r| [r.to_label, r.id]}]
237
+ [group.send(group_label), options.collect {|r| [r.send(column.options[:label_method] || :to_label), r.id]}]
189
238
  end
190
239
  end
191
240
 
@@ -196,41 +245,70 @@ module ActiveScaffold
196
245
  end
197
246
 
198
247
  def active_scaffold_input_singular_association(column, html_options)
199
- associated = @record.send(column.association.name)
248
+ record = html_options.delete(:object)
249
+ ActiveSupport::Deprecation.warn "Relying on @record is deprecated, include :object in html_options with record.", caller if record.nil? # TODO Remove when relying on @record is removed
250
+ record ||= @record # TODO Remove when relying on @record is removed
251
+ associated = record.send(column.association.name)
200
252
 
201
- select_options = sorted_association_options_find(column.association)
253
+ select_options = sorted_association_options_find(column.association, nil, record)
202
254
  select_options.unshift(associated) unless associated.nil? || select_options.include?(associated)
203
255
 
204
256
  method = column.name
205
- options = {:selected => associated.try(:id), :include_blank => as_(:_select_), :object => html_options.delete(:object)}
257
+ options = {:selected => associated.try(:id), :include_blank => as_(:_select_), :object => record}
206
258
 
207
- html_options.update(column.options[:html_options] || {})
208
- options.update(column.options)
259
+ html_options.merge!(column.options[:html_options] || {})
260
+ options.merge!(column.options)
209
261
  html_options[:name] = "#{html_options[:name]}[]" if html_options[:multiple] == true && !html_options[:name].to_s.ends_with?("[]")
210
262
  active_scaffold_translate_select_options(options)
211
263
 
212
- if optgroup = options.delete(:optgroup)
264
+ html = if optgroup = options.delete(:optgroup)
213
265
  select(:record, method, active_scaffold_grouped_options(column, select_options, optgroup), options, html_options)
214
266
  else
215
- collection_select(:record, method, select_options, :id, :to_label, options, html_options)
267
+ collection_select(:record, method, select_options, :id, column.options[:label_method] || :to_label, options, html_options)
216
268
  end
269
+ html << active_scaffold_refresh_link(column, html_options, record) if column.options[:refresh_link]
270
+ html
217
271
  end
218
272
 
219
- def active_scaffold_plural_association_options(column)
220
- associated_options = @record.send(column.association.name)
221
- [associated_options, associated_options | sorted_association_options_find(column.association)]
273
+ def active_scaffold_refresh_link(column, html_options, record)
274
+ link_options = {:object => record}
275
+ if html_options['data-update_url']
276
+ link_options['data-update_send_form'] = html_options['data-update_send_form']
277
+ link_options['data-update_send_form_selector'] = html_options['data-update_send_form_selector']
278
+ else
279
+ scope = html_options[:name].scan(/^record((\[[^\]]*\])*)\[#{column.name}\]/)[0].try(:first) if html_options[:name]
280
+ link_options = update_columns_options(column, scope, link_options, true)
281
+ end
282
+ link_options[:class] = 'refresh-link'
283
+ link_to(as_(:refresh), link_options.delete('data-update_url') || html_options['data-update_url'], link_options)
222
284
  end
223
285
 
224
- def active_scaffold_input_plural_association(column, options)
225
- associated_options, select_options = active_scaffold_plural_association_options(column)
226
- return content_tag(:span, as_(:no_options), :class => options[:class], :id => options[:id]) if select_options.empty?
286
+ def active_scaffold_plural_association_options(column, record = nil)
287
+ ActiveSupport::Deprecation.warn "Relying on @record is deprecated, call with record.", caller if record.nil? # TODO Remove when relying on @record is removed
288
+ record ||= @record # TODO Remove when relying on @record is removed
289
+ associated_options = record.send(column.association.name)
290
+ [associated_options, associated_options | sorted_association_options_find(column.association, nil, record)]
291
+ end
227
292
 
228
- active_scaffold_checkbox_list(column, select_options.collect {|r| [r.to_label, r.id]}, associated_options.collect(&:id), options)
293
+ def active_scaffold_input_plural_association(column, options)
294
+ record = options.delete(:object)
295
+ ActiveSupport::Deprecation.warn "Relying on @record is deprecated, include :object in options with record.", caller if record.nil? # TODO Remove when relying on @record is removed
296
+ record ||= @record # TODO Remove when relying on @record is removed
297
+ associated_options, select_options = active_scaffold_plural_association_options(column, record)
298
+
299
+ html = if select_options.empty?
300
+ content_tag(:span, as_(:no_options), :class => "#{options[:class]} no-options", :id => options[:id])
301
+ else
302
+ method = column.options[:label_method] || :to_label
303
+ active_scaffold_checkbox_list(column, select_options.collect {|r| [r.send(method), r.id]}, associated_options.collect(&:id), options)
304
+ end
305
+ html << active_scaffold_refresh_link(column, options, record) if column.options[:refresh_link]
306
+ html
229
307
  end
230
308
 
231
309
  def active_scaffold_checkbox_list(column, select_options, associated_ids, options)
232
310
  html = hidden_field_tag("#{options[:name]}[]", '', :id => nil)
233
- html << content_tag(:ul, :class => "#{options[:class]} checkbox-list", :id => options[:id]) do
311
+ html << content_tag(:ul, options.merge(:class => "#{options[:class]} checkbox-list#{' draggable-lists' if column.options[:draggable_lists]}")) do
234
312
  content = ''.html_safe
235
313
  select_options.each_with_index do |option, i|
236
314
  label, id = option
@@ -242,7 +320,7 @@ module ActiveScaffold
242
320
  end
243
321
  content
244
322
  end
245
- html << javascript_tag("ActiveScaffold.draggable_lists('#{options[:id]}')") if column.options[:draggable_lists]
323
+ html << javascript_tag("ActiveScaffold.draggable_lists('#{options[:id]}')") if column.options[:draggable_lists] && ActiveScaffold.js_framework == :prototype
246
324
  html
247
325
  end
248
326
 
@@ -251,17 +329,20 @@ module ActiveScaffold
251
329
  [(text.is_a?(Symbol) ? column.active_record_class.human_attribute_name(text) : text), value]
252
330
  end
253
331
 
254
- def active_scaffold_enum_options(column)
332
+ def active_scaffold_enum_options(column, record = nil)
255
333
  column.options[:options]
256
334
  end
257
335
 
258
336
  def active_scaffold_input_enum(column, html_options)
259
- options = { :selected => @record.send(column.name), :object => html_options.delete(:object) }
260
- options_for_select = active_scaffold_enum_options(column).collect do |text, value|
337
+ record = html_options.delete(:object)
338
+ ActiveSupport::Deprecation.warn "Relying on @record is deprecated, include :object in html_options with record.", caller if record.nil? # TODO Remove when relying on @record is removed
339
+ record ||= @record # TODO Remove when relying on @record is removed
340
+ options = { :selected => record.send(column.name), :object => record }
341
+ options_for_select = active_scaffold_enum_options(column, record).collect do |text, value|
261
342
  active_scaffold_translated_option(column, text, value)
262
343
  end
263
- html_options.update(column.options[:html_options] || {})
264
- options.update(column.options)
344
+ html_options.merge!(column.options[:html_options] || {})
345
+ options.merge!(column.options)
265
346
  active_scaffold_translate_select_options(options)
266
347
  select(:record, column.name, options_for_select, options, html_options)
267
348
  end
@@ -277,10 +358,21 @@ module ActiveScaffold
277
358
  end
278
359
 
279
360
  def active_scaffold_input_radio(column, html_options)
280
- html_options.update(column.options[:html_options] || {})
281
- column.options[:options].inject('') do |html, (text, value)|
282
- text, value = active_scaffold_translated_option(column, text, value)
283
- html << content_tag(:label, radio_button(:record, column.name, value, html_options.merge(:id => html_options[:id] + '-' + value.to_s)) + text)
361
+ record = html_options[:object]
362
+ html_options.merge!(column.options[:html_options] || {})
363
+ options = if column.association
364
+ sorted_association_options_find(column.association, nil, record)
365
+ else
366
+ active_scaffold_enum_options(column, record)
367
+ end
368
+ id_key = html_options[:"data-id"] ? :"data-id" : :id
369
+ options.inject('') do |html, (text, value)|
370
+ method = column.options[:label_method] || :to_label if column.association
371
+ text, value = column.association ? [text.send(method), text.id] : active_scaffold_translated_option(column, text, value)
372
+ checked = {:checked => html_options[:object].send(column.association.name).try(:id) == value} if column.association
373
+ radio_options = html_options.merge(id_key => html_options[id_key] + '-' + value.to_s)
374
+ radio_options.merge!(checked) if checked
375
+ html << content_tag(:label, radio_button(:record, column.name, value, radio_options) + text)
284
376
  end.html_safe
285
377
  end
286
378
 
@@ -342,12 +434,15 @@ module ActiveScaffold
342
434
  #
343
435
 
344
436
  def active_scaffold_input_boolean(column, options)
437
+ record = options.delete(:object)
438
+ ActiveSupport::Deprecation.warn "Relying on @record is deprecated, include :object in options with record.", caller if record.nil? # TODO Remove when relying on @record is removed
439
+ record ||= @record # TODO Remove when relying on @record is removed
345
440
  select_options = []
346
441
  select_options << [as_(:_select_), nil] if !column.virtual? && column.column.null
347
442
  select_options << [as_(:true), true]
348
443
  select_options << [as_(:false), false]
349
444
 
350
- select_tag(options[:name], options_for_select(select_options, @record.send(column.name)), options)
445
+ select_tag(options[:name], options_for_select(select_options, record.send(column.name)), options)
351
446
  end
352
447
 
353
448
  def onsubmit
@@ -402,7 +497,7 @@ module ActiveScaffold
402
497
  ##
403
498
 
404
499
  def column_renders_as(column)
405
- if column.is_a? ActiveScaffold::DataStructures::ActionColumns
500
+ if column.respond_to? :each
406
501
  return :subsection
407
502
  elsif column.active_record_class.locking_column.to_s == column.name.to_s or column.form_ui == :hidden
408
503
  return :hidden
@@ -414,7 +509,7 @@ module ActiveScaffold
414
509
  end
415
510
 
416
511
  def column_scope(column, scope = nil, record = nil)
417
- Rails.logger.warn "Relying on @record is deprecated, call column_scope with record. Called from #{caller.first.gsub(/(.*:\d+):.*/, '\1')}" if record.nil? # TODO Remove when relying on @record is removed
512
+ ActiveSupport::Deprecation.warn "Relying on @record is deprecated, call with record.", caller if record.nil? # TODO Remove when relying on @record is removed
418
513
  if column.plural_association?
419
514
  "#{scope}[#{column.name}][#{record.id || generate_temporary_id(record)}]"
420
515
  else
@@ -423,13 +518,16 @@ module ActiveScaffold
423
518
  end
424
519
 
425
520
  def active_scaffold_add_existing_input(options)
521
+ record = options.delete(:object)
522
+ ActiveSupport::Deprecation.warn "Relying on @record is deprecated, include :object in options with record.", caller if record.nil? # TODO Remove when relying on @record is removed
523
+ record ||= @record # TODO Remove when relying on @record is removed
426
524
  if ActiveScaffold.js_framework == :prototype && controller.respond_to?(:record_select_config, true)
427
525
  remote_controller = active_scaffold_controller_for(record_select_config.model).controller_path
428
526
  options.merge!(:controller => remote_controller)
429
527
  options.merge!(active_scaffold_input_text_options)
430
- record_select_field(options[:name], @record, options)
528
+ record_select_field(options[:name], record, options)
431
529
  else
432
- select_options = sorted_association_options_find(nested.association)
530
+ select_options = sorted_association_options_find(nested.association, nil, record)
433
531
  select_options ||= active_scaffold_config.model.all
434
532
  select_options = options_from_collection_for_select(select_options, :id, :to_label)
435
533
  select_tag 'associated_id', ('<option value="">' + as_(:_select_) + '</option>' + select_options).html_safe unless select_options.empty?
@@ -27,7 +27,8 @@ module ActiveScaffold
27
27
  associated = value
28
28
  associated = [associated].compact unless associated.is_a? Array
29
29
  if column.association
30
- associated = column.association.klass.where(:id => associated.map(&:to_i)).collect(&:to_label)
30
+ method = column.options[:label_method] || :to_label
31
+ associated = column.association.klass.where(:id => associated.map(&:to_i)).collect(&method)
31
32
  elsif column.options[:options]
32
33
  associated = associated.collect do |value|
33
34
  text, val = column.options[:options].find {|text, val| (val.nil? ? text : val).to_s == value.to_s}
@@ -10,8 +10,12 @@ module ActiveScaffold
10
10
  controller_id ||= 'as_' + id_from_controller(controller)
11
11
  end
12
12
 
13
+ def nested_parent_id
14
+ nested_parent_record.id
15
+ end
16
+
13
17
  def nested_id
14
- "#{nested.parent_scaffold.controller_path}-#{nested.parent_id}-#{params[:controller]}" if nested?
18
+ "#{nested.parent_scaffold.controller_path}-#{nested_parent_id}-#{params[:controller]}" if nested?
15
19
  end
16
20
 
17
21
  def active_scaffold_id
@@ -58,14 +62,14 @@ module ActiveScaffold
58
62
  def element_row_id(options = {})
59
63
  options[:action] ||= params[:action]
60
64
  options[:id] ||= params[:id]
61
- options[:id] ||= nested.parent_id if nested?
65
+ options[:id] ||= nested_parent_id if nested?
62
66
  clean_id "#{options[:controller_id] || controller_id}-#{options[:action]}-#{options[:id]}-row"
63
67
  end
64
68
 
65
69
  def element_cell_id(options = {})
66
70
  options[:action] ||= params[:action]
67
71
  options[:id] ||= params[:id]
68
- options[:id] ||= nested.parent_id if nested?
72
+ options[:id] ||= nested_parent_id if nested?
69
73
  options[:name] ||= params[:name]
70
74
  clean_id "#{controller_id}-#{options[:action]}-#{options[:id]}-#{options[:name]}-cell"
71
75
  end
@@ -73,7 +77,7 @@ module ActiveScaffold
73
77
  def element_form_id(options = {})
74
78
  options[:action] ||= params[:action]
75
79
  options[:id] ||= params[:id]
76
- options[:id] ||= nested.parent_id if nested?
80
+ options[:id] ||= nested_parent_id if nested?
77
81
  clean_id "#{controller_id}-#{options[:action]}-#{options[:id]}-form"
78
82
  end
79
83
 
@@ -84,31 +88,33 @@ module ActiveScaffold
84
88
 
85
89
  def loading_indicator_id(options = {})
86
90
  options[:action] ||= params[:action]
91
+ options[:id] ||= params[:id]
92
+ options[:id] ||= nested_parent_id if nested?
87
93
  clean_id "#{controller_id}-#{options[:action]}-#{options[:id]}-loading-indicator"
88
94
  end
89
95
 
90
96
  def sub_section_id(options = {})
91
97
  options[:id] ||= params[:id]
92
- options[:id] ||= nested.parent_id if nested?
98
+ options[:id] ||= nested_parent_id if nested?
93
99
  clean_id "#{controller_id}-#{options[:id]}-#{options[:sub_section]}-subsection"
94
100
  end
95
101
 
96
102
  def sub_form_id(options = {})
97
103
  options[:id] ||= params[:id]
98
- options[:id] ||= nested.parent_id if nested?
104
+ options[:id] ||= nested_parent_id if nested?
99
105
  clean_id "#{controller_id}-#{options[:id]}-#{options[:association]}-subform"
100
106
  end
101
107
 
102
108
  def sub_form_list_id(options = {})
103
109
  options[:id] ||= params[:id]
104
- options[:id] ||= nested.parent_id if nested?
110
+ options[:id] ||= nested_parent_id if nested?
105
111
  clean_id "#{controller_id}-#{options[:id]}-#{options[:association]}-subform-list"
106
112
  end
107
113
 
108
114
  def element_messages_id(options = {})
109
115
  options[:action] ||= params[:action]
110
116
  options[:id] ||= params[:id]
111
- options[:id] ||= nested.parent_id if nested?
117
+ options[:id] ||= nested_parent_id if nested?
112
118
  clean_id "#{controller_id}-#{options[:action]}-#{options[:id]}-messages"
113
119
  end
114
120