active_scaffold 3.3.3 → 3.4.0

Sign up to get free protection for your applications and to get access to all the features.
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