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
@@ -16,7 +16,7 @@ module ActiveScaffold::Actions
16
16
 
17
17
  protected
18
18
  def response_location
19
- url_for(params_for(:action => "show", :id => @record.id)) if successful?
19
+ url_for(params_for(:action => "show", :id => @record.to_param)) if successful?
20
20
  end
21
21
 
22
22
  def new_respond_to_html
@@ -41,8 +41,8 @@ module ActiveScaffold::Actions
41
41
  if successful?
42
42
  flash[:info] = as_(:created_model, :model => @record.to_label)
43
43
  if action = active_scaffold_config.create.action_after_create
44
- redirect_to params_for(:action => action, :id => @record.id)
45
- elsif active_scaffold_config.create.persistent
44
+ redirect_to params_for(:action => action, :id => @record.to_param)
45
+ elsif params[:dont_close]
46
46
  redirect_to params_for(:action => "new")
47
47
  else
48
48
  return_to_main
@@ -59,19 +59,27 @@ module ActiveScaffold::Actions
59
59
 
60
60
  def create_respond_to_js
61
61
  do_refresh_list if successful? && active_scaffold_config.create.refresh_list && !render_parent?
62
+ if successful? && params[:dont_close] && !render_parent?
63
+ @saved_record = @record
64
+ do_new
65
+ end
62
66
  render :action => 'on_create'
63
67
  end
64
68
 
65
69
  def create_respond_to_xml
66
- render :xml => response_object.to_xml(:only => active_scaffold_config.create.columns.names), :content_type => Mime::XML, :status => response_status, :location => response_location
70
+ render :xml => response_object.to_xml(:only => create_columns_names + [active_scaffold_config.model.primary_key], :include => association_columns(create_columns_names), :methods => virtual_columns(create_columns_names)), :content_type => Mime::XML, :status => response_status, :location => response_location
67
71
  end
68
72
 
69
73
  def create_respond_to_json
70
- render :text => response_object.to_json(:only => active_scaffold_config.create.columns.names), :content_type => Mime::JSON, :status => response_status, :location => response_location
74
+ render :text => response_object.to_json(:only => create_columns_names + [active_scaffold_config.model.primary_key], :include => association_columns(create_columns_names), :methods => virtual_columns(create_columns_names)), :content_type => Mime::JSON, :status => response_status, :location => response_location
71
75
  end
72
76
 
73
77
  def create_respond_to_yaml
74
- render :text => Hash.from_xml(response_object.to_xml(:only => active_scaffold_config.create.columns.names)).to_yaml, :content_type => Mime::YAML, :status => response_status, :location => response_location
78
+ render :text => Hash.from_xml(response_object.to_xml(:only => create_columns_names + [active_scaffold_config.model.primary_key], :include => association_columns(create_columns_names), :methods => virtual_columns(create_columns_names))).to_yaml, :content_type => Mime::YAML, :status => response_status, :location => response_location
79
+ end
80
+
81
+ def create_columns_names
82
+ active_scaffold_config.create.columns.names
75
83
  end
76
84
 
77
85
  # A simple method to find and prepare an example new record for the form
@@ -99,6 +107,7 @@ module ActiveScaffold::Actions
99
107
  rescue ActiveRecord::ActiveRecordError => ex
100
108
  flash[:error] = ex.message
101
109
  self.successful = false
110
+ @record ||= new_model # ensure @record exists or display form will fail
102
111
  end
103
112
  end
104
113
 
@@ -1,78 +1,86 @@
1
1
  module ActiveScaffold::Actions
2
2
  module FieldSearch
3
- include ActiveScaffold::Actions::CommonSearch
4
3
  def self.included(base)
5
- base.before_filter :search_authorized_filter, :only => :show_search
6
- base.before_filter :store_search_params_into_session, :only => [:index]
7
- base.before_filter :do_search, :only => [:index]
8
4
  base.helper_method :field_search_params
9
- base.helper_method :search_params
5
+ base.send :include, ActiveScaffold::Actions::CommonSearch
6
+ base.send :include, InstanceMethods
10
7
  end
8
+
9
+ module InstanceMethods
11
10
 
12
- # FieldSearch uses params[:search] and not @record because search conditions do not always pass the Model's validations.
13
- # This facilitates for example, textual searches against associations via .search_sql
14
- def show_search
15
- @record = new_model
16
- respond_to_action(:field_search)
17
- end
11
+ # FieldSearch uses params[:search] and not @record because search conditions do not always pass the Model's validations.
12
+ # This facilitates for example, textual searches against associations via .search_sql
13
+ def show_search
14
+ @record = new_model
15
+ super
16
+ end
18
17
 
19
- protected
20
-
21
- def store_search_params_into_session
22
- set_field_search_default_params(active_scaffold_config.field_search.default_params) unless active_scaffold_config.field_search.default_params.nil?
23
- super
24
- active_scaffold_session_storage[:search] = nil if search_params.is_a?(String)
25
- end
26
-
27
- def set_field_search_default_params(default_params)
28
- if (params[:search].nil? && search_params.nil?) || (params[:search].is_a?(String) && params[:search].blank?)
29
- params[:search] = default_params.is_a?(Proc) ? self.instance_eval(&default_params) : default_params
18
+ protected
19
+
20
+ def search_partial
21
+ super || :field_search
22
+ end
23
+
24
+ def store_search_params_into_session
25
+ set_field_search_default_params(active_scaffold_config.field_search.default_params) unless active_scaffold_config.field_search.default_params.nil?
26
+ super
27
+ end
28
+
29
+ def set_field_search_default_params(default_params)
30
+ if (params[:search].nil? && search_params.nil?) || (params[:search].is_a?(String) && params[:search].blank?)
31
+ params[:search] = default_params.is_a?(Proc) ? self.instance_eval(&default_params) : default_params
32
+ end
33
+ end
34
+
35
+ def field_search_params
36
+ search_params.is_a?(Hash) ? search_params : {}
30
37
  end
31
- end
32
-
33
- def field_search_params
34
- search_params || {}
35
- end
36
38
 
37
- def field_search_respond_to_html
38
- render(:action => "field_search")
39
- end
40
-
41
- def field_search_respond_to_js
42
- render(:partial => "field_search")
43
- end
39
+ def field_search_respond_to_html
40
+ render(:action => "field_search")
41
+ end
42
+
43
+ def field_search_respond_to_js
44
+ render(:partial => "field_search")
45
+ end
44
46
 
45
- def do_search
46
- unless search_params.blank?
47
- filtered_columns = []
48
- text_search = active_scaffold_config.field_search.text_search
49
- columns = active_scaffold_config.field_search.columns
50
- search_params.each do |key, value|
51
- next unless columns.include? key
52
- column = active_scaffold_config.columns[key]
53
- search_condition = self.class.condition_for_column(column, value, text_search)
54
- unless search_condition.blank?
55
- self.active_scaffold_outer_joins << column.search_joins unless active_scaffold_config.list.user.count_includes.nil? && column.includes.present? && list_columns.include?(column)
56
- self.active_scaffold_conditions << search_condition
57
- filtered_columns << column
47
+ def do_search
48
+ if search_params.is_a?(Hash) && search_params.present?
49
+ filtered_columns = []
50
+ text_search = active_scaffold_config.field_search.text_search
51
+ columns = active_scaffold_config.field_search.columns
52
+ search_params.each do |key, value|
53
+ next unless columns.include? key
54
+ column = active_scaffold_config.columns[key]
55
+ search_condition = self.class.condition_for_column(column, value, text_search)
56
+ unless search_condition.blank?
57
+ if active_scaffold_config.list.user.count_includes.nil? && column.includes.present? && list_columns.include?(column)
58
+ self.active_scaffold_references << column.includes
59
+ elsif column.search_joins.present?
60
+ self.active_scaffold_outer_joins << column.search_joins
61
+ end
62
+ self.active_scaffold_conditions << search_condition
63
+ filtered_columns << column
64
+ end
58
65
  end
66
+ unless filtered_columns.blank?
67
+ @filtered = active_scaffold_config.field_search.human_conditions ? filtered_columns : true
68
+ end
69
+
70
+ active_scaffold_config.list.user.page = nil
71
+ else
72
+ super
59
73
  end
60
- unless filtered_columns.blank?
61
- @filtered = active_scaffold_config.field_search.human_conditions ? filtered_columns : true
62
- end
74
+ end
63
75
 
64
- active_scaffold_config.list.user.page = nil
76
+ def search_ignore?
77
+ active_scaffold_config.list.always_show_search == :field_search || global_search_ignore?
65
78
  end
66
- end
67
79
 
68
- private
69
-
70
- def search_authorized_filter
71
- link = active_scaffold_config.field_search.link || active_scaffold_config.field_search.class.link
72
- raise ActiveScaffold::ActionNotAllowed unless self.send(link.security_method)
73
- end
74
- def field_search_formats
75
- (default_formats + active_scaffold_config.formats + active_scaffold_config.field_search.formats).uniq
80
+ private
81
+ def field_search_formats
82
+ (default_formats + active_scaffold_config.formats + active_scaffold_config.field_search.formats).uniq
83
+ end
76
84
  end
77
85
  end
78
86
  end
@@ -1,14 +1,19 @@
1
1
  module ActiveScaffold::Actions
2
2
  module List
3
3
  def self.included(base)
4
- base.before_filter :list_authorized_filter, :only => [:index, :row]
4
+ base.before_filter :list_authorized_filter, :only => :index
5
5
  base.helper_method :list_columns
6
6
  end
7
7
 
8
8
  def index
9
- list
9
+ if params[:id] && !params[:id].is_a?(Array) && request.xhr?
10
+ row
11
+ else
12
+ list
13
+ end
10
14
  end
11
15
 
16
+ protected
12
17
  # get just a single row
13
18
  def row
14
19
  get_row
@@ -25,29 +30,29 @@ module ActiveScaffold::Actions
25
30
  respond_to_action(:list)
26
31
  end
27
32
 
28
- protected
29
33
  def list_respond_to_html
30
- if embedded?
34
+ if loading_embedded?
31
35
  render :action => 'list', :layout => false
32
36
  else
33
37
  render :action => 'list'
34
38
  end
35
39
  end
36
40
  def list_respond_to_js
37
- if params[:adapter] || embedded?
41
+ if params[:adapter] || loading_embedded?
38
42
  render(:partial => 'list_with_header')
39
43
  else
44
+ @auto_pagination = params[:auto_pagination]
40
45
  render :partial => 'refresh_list', :formats => [:js]
41
46
  end
42
47
  end
43
48
  def list_respond_to_xml
44
- render :xml => response_object.to_xml(:only => list_columns_names), :content_type => Mime::XML, :status => response_status
49
+ render :xml => response_object.to_xml(:only => list_columns_names + [active_scaffold_config.model.primary_key], :include => association_columns(list_columns_names), :methods => virtual_columns(list_columns_names)), :content_type => Mime::XML, :status => response_status
45
50
  end
46
51
  def list_respond_to_json
47
- render :text => response_object.to_json(:only => list_columns_names), :content_type => Mime::JSON, :status => response_status
52
+ render :text => response_object.to_json(:only => list_columns_names + [active_scaffold_config.model.primary_key], :include => association_columns(list_columns_names), :methods => virtual_columns(list_columns_names)), :content_type => Mime::JSON, :status => response_status
48
53
  end
49
54
  def list_respond_to_yaml
50
- render :text => Hash.from_xml(response_object.to_xml(:only => list_columns_names)).to_yaml, :content_type => Mime::YAML, :status => response_status
55
+ render :text => Hash.from_xml(response_object.to_xml(:only => list_columns_names + [active_scaffold_config.model.primary_key], :include => association_columns(list_columns_names), :methods => virtual_columns(list_columns_names))).to_yaml, :content_type => Mime::YAML, :status => response_status
51
56
  end
52
57
 
53
58
  def row_respond_to_html
@@ -61,19 +66,21 @@ module ActiveScaffold::Actions
61
66
  # The actual algorithm to prepare for the list view
62
67
  def set_includes_for_columns(action = :list)
63
68
  @cache_associations = true
64
- columns = if respond_to?(:"#{action}_columns")
69
+ columns = if respond_to?(:"#{action}_columns", true)
65
70
  send(:"#{action}_columns")
66
71
  else
67
72
  active_scaffold_config.send(action).columns.collect_visible(:flatten => true)
68
73
  end
69
- includes_for_list_columns = columns.map{ |c| c.includes }.flatten.uniq.compact
70
- self.active_scaffold_includes.concat includes_for_list_columns
74
+ sorting = active_scaffold_config.list.user.sorting
75
+ columns_for_joins, columns_for_includes = columns.select{ |c| c.includes.present? }.partition {|c| sorting.sorts_on? c }
76
+ self.active_scaffold_preload.concat columns_for_includes.map(&:includes).flatten.uniq
77
+ self.active_scaffold_references.concat columns_for_joins.map(&:includes).flatten.uniq
71
78
  end
72
79
 
73
- def get_row
80
+ def get_row(crud_type = :read)
74
81
  set_includes_for_columns
75
- klass = beginning_of_chain.includes(active_scaffold_includes)
76
- @record = find_if_allowed(params[:id], :read, klass)
82
+ klass = beginning_of_chain.preload(active_scaffold_preload)
83
+ @record = find_if_allowed(params[:id], crud_type, klass)
77
84
  end
78
85
 
79
86
  # The actual algorithm to prepare for the list view
@@ -83,15 +90,16 @@ module ActiveScaffold::Actions
83
90
  options = { :sorting => active_scaffold_config.list.user.sorting,
84
91
  :count_includes => active_scaffold_config.list.user.count_includes }
85
92
  paginate = (params[:format].nil?) ? (accepts? :html, :js) : ['html', 'js'].include?(params[:format])
86
- if paginate
87
- options.merge!({
88
- :per_page => active_scaffold_config.list.user.per_page,
89
- :page => active_scaffold_config.list.user.page,
90
- :pagination => active_scaffold_config.list.pagination
91
- })
93
+ options[:pagination] = active_scaffold_config.list.pagination if paginate
94
+ if options[:pagination]
95
+ options.merge!(
96
+ :per_page => active_scaffold_config.list.user.per_page,
97
+ :page => active_scaffold_config.list.user.page
98
+ )
92
99
  end
93
100
  if active_scaffold_config.list.auto_select_columns
94
- options[:select] = active_scaffold_config.list.columns.map(&:select_columns).compact.flatten + active_scaffold_config.columns[active_scaffold_config.model.primary_key].select_columns
101
+ auto_select_columns = list_columns + [active_scaffold_config.columns[active_scaffold_config.model.primary_key]]
102
+ options[:select] = auto_select_columns.map { |c| quoted_select_columns(c.select_columns) }.compact.flatten
95
103
  end
96
104
 
97
105
  page = find_page(options)
@@ -103,6 +111,10 @@ module ActiveScaffold::Actions
103
111
  @page, @records = page, page.items
104
112
  end
105
113
 
114
+ def quoted_select_columns(columns)
115
+ columns.map { |c| active_scaffold_config.columns[c].try(:field) || c } if columns
116
+ end
117
+
106
118
  def do_refresh_list
107
119
  params.delete(:id)
108
120
  do_search if respond_to? :do_search, true
@@ -120,7 +132,7 @@ module ActiveScaffold::Actions
120
132
  def each_record_in_scope
121
133
  do_search if respond_to? :do_search, true
122
134
  set_includes_for_columns
123
- append_to_query(beginning_of_chain, finder_options).all.each {|record| yield record}
135
+ append_to_query(beginning_of_chain, finder_options).each {|record| yield record}
124
136
  end
125
137
 
126
138
  # The default security delegates to ActiveRecordPermissions.
@@ -145,9 +157,7 @@ module ActiveScaffold::Actions
145
157
  @action_link = active_scaffold_config.action_links[action_name]
146
158
  if params[:id] && params[:id].to_i > 0
147
159
  crud_type ||= (request.post? || request.put?) ? :update : :delete
148
- set_includes_for_columns
149
- klass = beginning_of_chain.includes(active_scaffold_includes)
150
- @record = find_if_allowed(params[:id], crud_type, klass)
160
+ get_row(crud_type)
151
161
  unless @record.nil?
152
162
  yield @record
153
163
  else
@@ -176,15 +186,26 @@ module ActiveScaffold::Actions
176
186
  end
177
187
 
178
188
  def action_update_respond_to_xml
179
- render :xml => successful? ? "" : response_object.to_xml(:only => list_columns_names), :content_type => Mime::XML, :status => response_status
189
+ render :xml => successful? ? "" : response_object.to_xml(:only => list_columns_names + [active_scaffold_config.model.primary_key], :include => association_columns(list_columns_names), :methods => virtual_columns(list_columns_names)), :content_type => Mime::XML, :status => response_status
180
190
  end
181
191
 
182
192
  def action_update_respond_to_json
183
- render :text => successful? ? "" : response_object.to_json(:only => list_columns_names), :content_type => Mime::JSON, :status => response_status
193
+ render :text => successful? ? "" : response_object.to_json(:only => list_columns_names + [active_scaffold_config.model.primary_key], :include => association_columns(list_columns_names), :methods => virtual_columns(list_columns_names)), :content_type => Mime::JSON, :status => response_status
184
194
  end
185
195
 
186
196
  def action_update_respond_to_yaml
187
- render :text => successful? ? "" : Hash.from_xml(response_object.to_xml(:only => list_columns_names)).to_yaml, :content_type => Mime::YAML, :status => response_status
197
+ render :text => successful? ? "" : Hash.from_xml(response_object.to_xml(:only => list_columns_names + [active_scaffold_config.model.primary_key], :include => association_columns(list_columns_names), :methods => virtual_columns(list_columns_names))).to_yaml, :content_type => Mime::YAML, :status => response_status
198
+ end
199
+
200
+ def objects_for_etag
201
+ objects = if @list_columns
202
+ if active_scaffold_config.list.calculate_etag
203
+ @records.to_a
204
+ elsif active_scaffold_config.list.user.sorting
205
+ {:etag => active_scaffold_config.list.user.sorting.clause}
206
+ end
207
+ end
208
+ objects.present? ? objects : super
188
209
  end
189
210
 
190
211
  private
@@ -5,7 +5,7 @@ module ActiveScaffold::Actions
5
5
  def self.included(base)
6
6
  super
7
7
  base.module_eval do
8
- prepend_before_filter :set_nested
8
+ before_filter :set_nested
9
9
  before_filter :configure_nested
10
10
  include ActiveScaffold::Actions::Nested::ChildMethods if active_scaffold_config.model.reflect_on_all_associations.any? {|a| a.macro == :has_and_belongs_to_many}
11
11
  end
@@ -16,6 +16,7 @@ module ActiveScaffold::Actions
16
16
 
17
17
  protected
18
18
  def nested
19
+ set_nested unless defined? @nested
19
20
  @nested
20
21
  end
21
22
 
@@ -76,12 +77,20 @@ module ActiveScaffold::Actions
76
77
  if nested? && nested.association
77
78
  if nested.association.collection?
78
79
  nested_parent_record.send(nested.association.name)
79
- elsif nested.association.options[:through] || nested.child_association.nil? # has_one :through doesn't need conditions, and without child_association is not possible to add them
80
+ elsif nested.association.options[:through] # has_one :through
81
+ active_scaffold_config.model.where(active_scaffold_config.model.primary_key => nested_parent_record.send(nested.association.name).try(:id))
82
+ elsif nested.child_association.nil? # without child_association is not possible to add conditions
80
83
  active_scaffold_config.model
81
84
  elsif nested.child_association.belongs_to?
82
85
  active_scaffold_config.model.where(nested.child_association.foreign_key => nested_parent_record)
83
86
  elsif nested.association.belongs_to?
84
- active_scaffold_config.model.joins(nested.child_association.name).where(nested.association.active_record.table_name => {nested.association.active_record.primary_key => nested_parent_record}).readonly(false)
87
+ chain = active_scaffold_config.model.joins(nested.child_association.name)
88
+ table_name = if active_scaffold_config.model == nested.association.active_record
89
+ dependency = ActiveRecord::Associations::JoinDependency.new(chain.klass, chain.joins_values, [])
90
+ dependency.join_associations.find {|join| join.try(:reflection).try(:name) == nested.child_association.name}.try(:table).try(:right)
91
+ end
92
+ table_name ||= nested.association.active_record.table_name
93
+ chain.where(table_name => {nested.association.active_record.primary_key => nested_parent_record}).readonly(false)
85
94
  end
86
95
  elsif nested? && nested.scope
87
96
  nested_parent_record.send(nested.scope)
@@ -96,12 +105,11 @@ module ActiveScaffold::Actions
96
105
 
97
106
  def create_association_with_parent(record)
98
107
  if nested?
108
+ # has_many is done by beginning_of_chain and rails
99
109
  if (nested.belongs_to? || nested.has_one? || nested.habtm?) && nested.child_association
100
110
  parent = nested_parent_record(:read)
101
111
  case nested.child_association.macro
102
- when :has_one
103
- record.send("#{nested.child_association.name}=", parent)
104
- when :belongs_to
112
+ when :has_one, :belongs_to
105
113
  record.send("#{nested.child_association.name}=", parent)
106
114
  when :has_many, :has_and_belongs_to_many
107
115
  record.send("#{nested.child_association.name}").send(:<<, parent)
@@ -1,48 +1,49 @@
1
1
  module ActiveScaffold::Actions
2
2
  module Search
3
- include ActiveScaffold::Actions::CommonSearch
4
3
  def self.included(base)
5
- base.before_filter :search_authorized_filter, :only => :show_search
6
- base.before_filter :store_search_params_into_session, :only => [:index]
7
- base.before_filter :do_search, :only => [:index]
8
- base.helper_method :search_params
4
+ base.send :include, ActiveScaffold::Actions::CommonSearch
5
+ base.send :include, InstanceMethods
9
6
  end
7
+
8
+ module InstanceMethods
10
9
 
11
- def show_search
12
- respond_to_action(:search)
13
- end
10
+ protected
11
+ def search_respond_to_html
12
+ render(:action => "search")
13
+ end
14
+ def search_respond_to_js
15
+ render(:partial => "search")
16
+ end
17
+ def do_search
18
+ if search_params.is_a?(String) && search_params.present?
19
+ query = search_params.to_s.strip
20
+ columns = active_scaffold_config.search.columns
21
+ text_search = active_scaffold_config.search.text_search
22
+ query = query.split(active_scaffold_config.search.split_terms) if active_scaffold_config.search.split_terms
23
+ search_conditions = self.class.create_conditions_for_columns(query, columns, text_search)
24
+ @filtered = !search_conditions.blank?
25
+ self.active_scaffold_conditions.concat search_conditions if @filtered
14
26
 
15
- protected
16
- def search_respond_to_html
17
- render(:action => "search")
18
- end
19
- def search_respond_to_js
20
- render(:partial => "search")
21
- end
22
- def do_search
23
- query = search_params.to_s.strip rescue ''
24
- unless query.empty?
25
- columns = active_scaffold_config.search.columns
26
- text_search = active_scaffold_config.search.text_search
27
- query = query.split(active_scaffold_config.search.split_terms) if active_scaffold_config.search.split_terms
28
- search_conditions = self.class.create_conditions_for_columns(query, columns, text_search)
29
- @filtered = !search_conditions.blank?
30
- self.active_scaffold_conditions.concat search_conditions if @filtered
27
+ references, outer_joins = columns.partition{ |column| column.includes.present? && list_columns.include?(column)}
28
+ outer_joins.collect! { |column| column.search_joins}
29
+ references.collect! { |column| column.includes }
30
+ self.active_scaffold_outer_joins.concat outer_joins.flatten.uniq.compact
31
+ self.active_scaffold_references.concat references.flatten.uniq.compact
31
32
 
32
- outer_joins = columns.collect{ |column| column.search_joins unless column.includes.present? && list_columns.include?(column)}
33
- self.active_scaffold_outer_joins.concat outer_joins.flatten.uniq.compact
33
+ active_scaffold_config.list.user.page = nil
34
+ else
35
+ super
36
+ end
37
+ end
34
38
 
35
- active_scaffold_config.list.user.page = nil
39
+ def search_ignore?
40
+ active_scaffold_config.list.always_show_search == :search || global_search_ignore?
36
41
  end
37
- end
38
42
 
39
- private
40
- def search_authorized_filter
41
- link = active_scaffold_config.search.link || active_scaffold_config.search.class.link
42
- raise ActiveScaffold::ActionNotAllowed unless self.send(link.security_method)
43
- end
44
- def search_formats
45
- (default_formats + active_scaffold_config.formats + active_scaffold_config.search.formats).uniq
43
+ private
44
+ def search_formats
45
+ (default_formats + active_scaffold_config.formats + active_scaffold_config.search.formats).uniq
46
+ end
46
47
  end
47
48
  end
48
49
  end