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
@@ -1,32 +1,16 @@
1
- unless Rails::VERSION::MAJOR == 3 && Rails::VERSION::MINOR >= 1
2
- raise "This version of ActiveScaffold requires Rails 3.1 or higher. Please use an earlier version."
3
- end
4
-
5
- begin
6
- require 'render_component'
7
- rescue LoadError
8
- end
9
-
10
- require 'active_scaffold/active_record_permissions'
11
- require 'active_scaffold/paginator'
12
- require 'active_scaffold/responds_to_parent'
13
-
14
- require 'active_scaffold/version'
15
- require 'active_scaffold/engine' unless defined? ACTIVE_SCAFFOLD_PLUGIN
16
- require 'json' # for js_config
17
-
18
1
  module ActiveScaffold
2
+ autoload :ActiveRecordPermissions, 'active_scaffold/active_record_permissions'
19
3
  autoload :AttributeParams, 'active_scaffold/attribute_params'
4
+ autoload :Bridges, 'active_scaffold/bridges'
20
5
  autoload :Configurable, 'active_scaffold/configurable'
21
6
  autoload :Constraints, 'active_scaffold/constraints'
7
+ autoload :Core, 'active_scaffold/core'
8
+ autoload :DelayedSetup, 'active_scaffold/delayed_setup'
22
9
  autoload :Finder, 'active_scaffold/finder'
23
10
  autoload :MarkedModel, 'active_scaffold/marked_model'
24
- autoload :Bridges, 'active_scaffold/bridges'
25
-
26
- mattr_accessor :stylesheets
27
- self.stylesheets = []
28
- mattr_accessor :javascripts
29
- self.javascripts = []
11
+ autoload :RespondsToParent, 'active_scaffold/responds_to_parent'
12
+ autoload :Tableless, 'active_scaffold/tableless'
13
+ autoload :Version, 'active_scaffold/version'
30
14
 
31
15
  def self.autoload_subdir(dir, mod=self, root = File.dirname(__FILE__))
32
16
  Dir["#{root}/active_scaffold/#{dir}/*.rb"].each { |file|
@@ -54,82 +38,16 @@ module ActiveScaffold
54
38
  end
55
39
 
56
40
  class ControllerNotFound < RuntimeError; end
57
- class DependencyFailure < RuntimeError; end
58
41
  class MalformedConstraint < RuntimeError; end
59
42
  class RecordNotAllowed < SecurityError; end
60
43
  class ActionNotAllowed < SecurityError; end
61
44
  class ReverseAssociationRequired < RuntimeError; end
62
45
 
63
- def self.included(base)
64
- base.extend(ClassMethods)
65
- base.module_eval do
66
- # TODO: these should be in actions/core
67
- before_filter :handle_user_settings
68
- before_filter :check_input_device
69
- end
70
-
71
- base.helper_method :touch_device?
72
- base.helper_method :hover_via_click?
73
- base.helper_method :active_scaffold_constraints
74
- end
75
-
76
- def self.set_defaults(&block)
77
- ActiveScaffold::Config::Core.configure &block
78
- end
79
-
80
- def active_scaffold_config
81
- self.class.active_scaffold_config
82
- end
83
-
84
- def active_scaffold_config_for(klass)
85
- self.class.active_scaffold_config_for(klass)
86
- end
87
-
88
- def active_scaffold_session_storage_key(id = nil)
89
- id ||= params[:eid] || "#{params[:controller]}#{"_#{nested.parent_id}" if nested?}"
90
- "as:#{id}"
91
- end
92
-
93
- def active_scaffold_session_storage(id = nil)
94
- session_index = active_scaffold_session_storage_key(id)
95
- session[session_index] ||= {}
96
- session[session_index]
97
- end
98
-
99
- def clear_storage
100
- session_index = active_scaffold_session_storage_key
101
- session.delete(session_index) unless session[session_index].present?
102
- end
103
-
104
- # at some point we need to pass the session and params into config. we'll just take care of that before any particular action occurs by passing those hashes off to the UserSettings class of each action.
105
- def handle_user_settings
106
- if self.class.uses_active_scaffold?
107
- active_scaffold_config.actions.each do |action_name|
108
- conf_instance = active_scaffold_config.send(action_name) rescue next
109
- next if conf_instance.class::UserSettings == ActiveScaffold::Config::Base::UserSettings # if it hasn't been extended, skip it
110
- storage = active_scaffold_config.store_user_settings ? active_scaffold_session_storage : {}
111
- conf_instance.user = conf_instance.class::UserSettings.new(conf_instance, storage, params)
112
- end
113
- end
114
- end
115
-
116
- def check_input_device
117
- if request.env["HTTP_USER_AGENT"] && request.env["HTTP_USER_AGENT"][/(iPhone|iPod|iPad)/i]
118
- session[:input_device_type] = 'TOUCH'
119
- session[:hover_supported] = false
120
- else
121
- session[:input_device_type] = 'MOUSE'
122
- session[:hover_supported] = true
123
- end if session[:input_device_type].nil?
124
- end
125
-
126
- def touch_device?
127
- session[:input_device_type] == 'TOUCH'
128
- end
129
-
130
- def hover_via_click?
131
- session[:hover_supported] == false
132
- end
46
+ mattr_accessor :delayed_setup
47
+ mattr_accessor :stylesheets
48
+ self.stylesheets = []
49
+ mattr_accessor :javascripts
50
+ self.javascripts = []
133
51
 
134
52
  def self.js_framework=(framework)
135
53
  @@js_framework = framework
@@ -151,12 +69,10 @@ module ActiveScaffold
151
69
  @@js_config ||= {:scroll_on_close => :checkInViewport}
152
70
  end
153
71
 
154
- # exclude bridges you do not need
72
+ # exclude bridges you do not need, add to an initializer
155
73
  # name of bridge subdir should be used to exclude it
156
74
  # eg
157
75
  # ActiveScaffold.exclude_bridges = [:cancan, :ancestry]
158
- # if you are using Activescaffold as a gem add to initializer
159
- # if you are using Activescaffold as a plugin add to active_scaffold_env.rb
160
76
  def self.exclude_bridges=(bridges)
161
77
  @@exclude_bridges = bridges
162
78
  end
@@ -169,203 +85,11 @@ module ActiveScaffold
169
85
  File.dirname(__FILE__) + "/.."
170
86
  end
171
87
 
172
- module ClassMethods
173
- def active_scaffold(model_id = nil, &block)
174
- extend Prefixes
175
- # initialize bridges here
176
- ActiveScaffold::Bridges.run_all
177
-
178
- # converts Foo::BarController to 'bar' and FooBarsController to 'foo_bar' and AddressController to 'address'
179
- model_id = self.to_s.split('::').last.sub(/Controller$/, '').pluralize.singularize.underscore unless model_id
180
-
181
- # run the configuration
182
- @active_scaffold_config = ActiveScaffold::Config::Core.new(model_id)
183
- @active_scaffold_config_block = block
184
- self.links_for_associations
185
-
186
- self.active_scaffold_superclasses_blocks.each {|superblock| self.active_scaffold_config.configure &superblock}
187
- self.active_scaffold_config.sti_children = nil # reset sti_children if set in parent block
188
- self.active_scaffold_config.configure &block if block_given?
189
- self.active_scaffold_config._configure_sti unless self.active_scaffold_config.sti_children.nil?
190
- self.active_scaffold_config._load_action_columns
191
-
192
- # defines the attribute read methods on the model, so record.send() doesn't find protected/private methods instead
193
- klass = self.active_scaffold_config.model
194
- klass.define_attribute_methods unless klass.attribute_methods_generated?
195
- # include the rest of the code into the controller: the action core and the included actions
196
- module_eval do
197
- include ActiveScaffold::Finder
198
- include ActiveScaffold::Constraints
199
- include ActiveScaffold::AttributeParams
200
- include ActiveScaffold::Actions::Core
201
- active_scaffold_config.actions.each do |mod|
202
- name = mod.to_s.camelize
203
- include "ActiveScaffold::Actions::#{name}".constantize
204
-
205
- # sneak the action links from the actions into the main set
206
- if link = active_scaffold_config.send(mod).link rescue nil
207
- if link.is_a? Array
208
- link.each {|current| active_scaffold_config.action_links.add_to_group(current, active_scaffold_config.send(mod).action_group)}
209
- elsif link.is_a? ActiveScaffold::DataStructures::ActionLink
210
- active_scaffold_config.action_links.add_to_group(link, active_scaffold_config.send(mod).action_group)
211
- end
212
- end
213
- end
214
- end
215
- self._add_sti_create_links if self.active_scaffold_config.add_sti_create_links?
216
- end
217
-
218
- module Prefixes
219
- def parent_prefixes
220
- @parent_prefixes ||= super << 'active_scaffold_overrides'
221
- end
222
- end
223
-
224
- # To be called after include action modules
225
- def _add_sti_create_links
226
- new_action_link = active_scaffold_config.action_links.collection['new']
227
- unless new_action_link.nil? || active_scaffold_config.sti_children.empty?
228
- active_scaffold_config.action_links.collection.delete('new')
229
- active_scaffold_config.sti_children.each do |child|
230
- new_sti_link = Marshal.load(Marshal.dump(new_action_link)) # deep clone
231
- new_sti_link.label = as_(:create_model, :model => child.to_s.camelize.constantize.model_name.human)
232
- new_sti_link.parameters = {:parent_sti => controller_path}
233
- new_sti_link.controller = Proc.new { active_scaffold_controller_for(child.to_s.camelize.constantize).controller_path }
234
- active_scaffold_config.action_links.collection.create.add(new_sti_link)
235
- end
236
- end
237
- end
238
-
239
- # Create the automatic column links. Note that this has to happen when configuration is *done*, because otherwise the Nested module could be disabled. Actually, it could still be disabled later, couldn't it?
240
- def links_for_associations
241
- return unless active_scaffold_config.actions.include? :list and active_scaffold_config.actions.include? :nested
242
- active_scaffold_config.columns.each do |column|
243
- next unless column.link.nil? and column.autolink?
244
- #lazy load of action_link, cause it was really slowing down app in dev mode
245
- #and might lead to trouble cause of cyclic constantization of controllers
246
- #and might be unnecessary cause it is done before columns are configured
247
- column.set_link(Proc.new {|col| link_for_association(col)})
248
- end
249
- end
250
-
251
- def active_scaffold_controller_for_column(column, options = {})
252
- begin
253
- if column.polymorphic_association?
254
- :polymorph
255
- elsif options.include?(:controller)
256
- "#{options[:controller].to_s.camelize}Controller".constantize
257
- else
258
- active_scaffold_controller_for(column.association.klass)
259
- end
260
- rescue ActiveScaffold::ControllerNotFound
261
- nil
262
- end
263
- end
264
-
265
- def link_for_association(column, options = {})
266
- controller = active_scaffold_controller_for_column(column, options)
267
-
268
- unless controller.nil?
269
- options.reverse_merge! :position => :after, :type => :member, :controller => (controller == :polymorph ? controller : controller.controller_path), :column => column
270
- options[:parameters] ||= {}
271
- options[:parameters].reverse_merge! :association => column.association.name
272
- if column.plural_association?
273
- # note: we can't create nested scaffolds on :through associations because there's no reverse association.
274
-
275
- ActiveScaffold::DataStructures::ActionLink.new('index', options.merge(:refresh_on_close => true)) #unless column.through_association?
276
- else
277
- actions = controller.active_scaffold_config.actions unless controller == :polymorph
278
- actions ||= [:create, :update, :show]
279
- column.actions_for_association_links.delete :new unless actions.include? :create
280
- column.actions_for_association_links.delete :edit unless actions.include? :update
281
- column.actions_for_association_links.delete :show unless actions.include? :show
282
- ActiveScaffold::DataStructures::ActionLink.new(nil, options.merge(:html_options => {:class => column.name}))
283
- end
284
- end
285
- end
286
-
287
- def link_for_association_as_scope(scope, options = {})
288
- options.reverse_merge! :label => scope, :position => :after, :type => :member, :controller => controller_path
289
- options[:parameters] ||= {}
290
- options[:parameters].reverse_merge! :named_scope => scope
291
- ActiveScaffold::DataStructures::ActionLink.new('index', options)
292
- end
293
-
294
- def add_active_scaffold_path(path)
295
- as_path = File.join(ActiveScaffold::Config::Core.plugin_directory, 'app', 'views')
296
- index = view_paths.find_index { |p| p.to_s == as_path }
297
- if index
298
- self.view_paths = view_paths[0..index-1] + Array(path) + view_paths[index..-1]
299
- else
300
- append_view_path path
301
- end
302
- end
303
-
304
- def active_scaffold_config
305
- if @active_scaffold_config.nil?
306
- self.superclass.active_scaffold_config if self.superclass.respond_to? :active_scaffold_config
307
- else
308
- @active_scaffold_config
309
- end
310
- end
311
-
312
- def active_scaffold_config_block
313
- @active_scaffold_config_block
314
- end
315
-
316
- def active_scaffold_superclasses_blocks
317
- blocks = []
318
- klass = self.superclass
319
- while klass.respond_to? :active_scaffold_superclasses_blocks
320
- blocks << klass.active_scaffold_config_block
321
- klass = klass.superclass
322
- end
323
- blocks.compact.reverse
324
- end
325
-
326
- def active_scaffold_config_for(klass)
327
- begin
328
- controller = active_scaffold_controller_for(klass)
329
- rescue ActiveScaffold::ControllerNotFound
330
- config = ActiveScaffold::Config::Core.new(klass)
331
- config._load_action_columns
332
- config
333
- else
334
- controller.active_scaffold_config
335
- end
336
- end
337
-
338
- # Tries to find a controller for the given ActiveRecord model.
339
- # Searches in the namespace of the current controller for singular and plural versions of the conventional "#{model}Controller" syntax.
340
- # You may override this method to customize the search routine.
341
- def active_scaffold_controller_for(klass)
342
- controller_namespace = self.to_s.split('::')[0...-1].join('::') + '::'
343
- error_message = []
344
- [controller_namespace, ''].each do |namespace|
345
- ["#{klass.to_s.underscore.pluralize}", "#{klass.to_s.underscore.pluralize.singularize}"].each do |controller_name|
346
- begin
347
- controller = "#{namespace}#{controller_name.camelize}Controller".constantize
348
- rescue NameError => error
349
- # Only rescue NameError associated with the controller constant not existing - not other compile errors
350
- if error.message["uninitialized constant #{controller}"]
351
- error_message << "#{namespace}#{controller_name.camelize}Controller"
352
- next
353
- else
354
- raise
355
- end
356
- end
357
- raise ActiveScaffold::ControllerNotFound, "#{controller} missing ActiveScaffold", caller unless controller.uses_active_scaffold?
358
- raise ActiveScaffold::ControllerNotFound, "ActiveScaffold on #{controller} is not for #{klass} model.", caller unless controller.active_scaffold_config.model.to_s == klass.to_s
359
- return controller
360
- end
361
- end
362
- raise ActiveScaffold::ControllerNotFound, "Could not find " + error_message.join(" or "), caller
363
- end
364
-
365
- def uses_active_scaffold?
366
- !active_scaffold_config.nil?
367
- end
88
+ def self.set_defaults(&block)
89
+ ActiveScaffold::Config::Core.configure &block
368
90
  end
369
91
  end
92
+ require 'active_scaffold/engine'
93
+ # TODO: clean up extensions. some could be organized for autoloading, and others could be removed entirely.
94
+ Dir["#{File.dirname __FILE__}/active_scaffold/extensions/*.rb"].each { |file| require file }
370
95
 
371
- require 'active_scaffold_env'
@@ -1,26 +1,59 @@
1
1
  module ActiveScaffold::Actions
2
2
  module CommonSearch
3
- protected
4
- def store_search_params_into_session
5
- if active_scaffold_config.store_user_settings
6
- active_scaffold_session_storage[:search] = params.delete :search if params[:search]
7
- else
8
- @search_params = params.delete :search
3
+ def self.included(base)
4
+ unless base < InstanceMethods
5
+ base.send :include, InstanceMethods
6
+ base.before_filter :search_authorized_filter, :only => :show_search
7
+ base.before_filter :store_search_params_into_session, :only => [:index]
8
+ base.before_filter :do_search, :only => [:index]
9
+ base.helper_method :search_params
9
10
  end
10
11
  end
11
12
 
12
- def search_params
13
- @search_params || active_scaffold_session_storage[:search]
14
- end
13
+ module InstanceMethods
14
+ def show_search
15
+ respond_to_action(search_partial || :search)
16
+ end
17
+
18
+ protected
19
+ def do_search
20
+ end
21
+
22
+ def search_partial
23
+ @_search_partial ||= if params[:kind].present? && active_scaffold_config.actions.include?(params[:kind])
24
+ params.delete(:kind)
25
+ else
26
+ active_scaffold_config.list.auto_search_partial
27
+ end
28
+ end
29
+
30
+ def store_search_params_into_session
31
+ if active_scaffold_config.store_user_settings
32
+ active_scaffold_session_storage[:search] = params.delete :search if params[:search]
33
+ else
34
+ @search_params = params.delete :search
35
+ end
36
+ end
15
37
 
16
- def search_ignore?
17
- active_scaffold_config.list.always_show_search
18
- end
19
-
20
- # The default security delegates to ActiveRecordPermissions.
21
- # You may override the method to customize.
22
- def search_authorized?
23
- authorized_for?(:crud_type => :read)
38
+ def search_params
39
+ @search_params || active_scaffold_session_storage[:search]
40
+ end
41
+
42
+ def global_search_ignore?
43
+ active_scaffold_config.list.always_show_search == true
44
+ end
45
+
46
+ # The default security delegates to ActiveRecordPermissions.
47
+ # You may override the method to customize.
48
+ def search_authorized?
49
+ authorized_for?(:crud_type => :read)
50
+ end
51
+
52
+ def search_authorized_filter
53
+ action = active_scaffold_config.send(search_partial)
54
+ link = action.link || action.class.link
55
+ raise ActiveScaffold::ActionNotAllowed unless self.send(link.security_method)
56
+ end
24
57
  end
25
58
  end
26
59
  end
@@ -2,13 +2,15 @@ module ActiveScaffold::Actions
2
2
  module Core
3
3
  def self.included(base)
4
4
  base.class_eval do
5
- prepend_before_filter :register_constraints_with_action_columns, :unless => :nested?
5
+ before_filter :register_constraints_with_action_columns, :unless => :nested?
6
6
  after_filter :clear_flashes
7
7
  after_filter :clear_storage
8
8
  rescue_from ActiveScaffold::RecordNotAllowed, ActiveScaffold::ActionNotAllowed, :with => :deny_access
9
9
  end
10
10
  base.helper_method :successful?
11
11
  base.helper_method :nested?
12
+ base.helper_method :embedded?
13
+ base.helper_method :loading_embedded?
12
14
  base.helper_method :calculate_query
13
15
  base.helper_method :new_model
14
16
  end
@@ -21,8 +23,12 @@ module ActiveScaffold::Actions
21
23
  end
22
24
 
23
25
  protected
26
+ def loading_embedded?
27
+ @loading_embedded ||= params.delete(:embedded)
28
+ end
29
+
24
30
  def embedded?
25
- @embedded ||= params.delete(:embedded)
31
+ params[:eid]
26
32
  end
27
33
 
28
34
  def nested?
@@ -39,9 +45,10 @@ module ActiveScaffold::Actions
39
45
  @column = active_scaffold_config.columns[params.delete(:column)]
40
46
  unless @column.nil?
41
47
  @source_id = params.delete(:source_id)
42
- @columns = @column.update_columns
48
+ @columns = @column.update_columns || []
43
49
  @scope = params.delete(:scope)
44
50
  @main_columns = active_scaffold_config.send(@scope ? :subform : (params[:id] ? :update : :create)).columns
51
+ @columns << @column.name if @column.options[:refresh_link] && @columns.exclude?(@column.name)
45
52
 
46
53
  if @column.send_form_on_update_column
47
54
  if @scope
@@ -53,17 +60,58 @@ module ActiveScaffold::Actions
53
60
  hash = params[:record]
54
61
  id = params[:id]
55
62
  end
56
- @record = id ? find_if_allowed(id, :update) : new_model
57
- @record = update_record_from_params(@record, @main_columns, hash)
58
- else
63
+
64
+ # check permissions and support overriding to_param
65
+ record = find_if_allowed(id, :update) if id
66
+ # call update_record_from_params with new_model
67
+ # in other case some associations can be saved
59
68
  @record = new_model
69
+ copy_attributes(record, @record) if record
70
+ apply_constraints_to_record(@record) unless @scope
71
+ @record = update_record_from_params(@record, @main_columns, hash, true)
72
+ else
73
+ @record = params[:id] ? find_if_allowed(params[:id], :update) : new_model
74
+ if @record.new_record?
75
+ apply_constraints_to_record(@record) unless @scope
76
+ else
77
+ @record = @record.dup
78
+ end
60
79
  value = column_value_from_param_value(@record, @column, params.delete(:value))
61
80
  @record.send "#{@column.name}=", value
81
+ @record.id = params[:id]
62
82
  end
83
+ set_parent(@record) if @record.id.nil? && params[:parent_controller] && params[:child_association]
63
84
 
64
85
  after_render_field(@record, @column)
65
86
  end
66
87
  end
88
+
89
+ def set_parent(record)
90
+ parent_model = params[:parent_controller].singularize.camelize.constantize
91
+ association = parent_model.reflect_on_association(params[:child_association].to_sym).try(:reverse)
92
+ if association
93
+ parent = parent_model.new
94
+ copy_attributes(parent_model.find(params[:parent_id]), parent) if params[:parent_id]
95
+ parent.id = params[:parent_id]
96
+ parent = update_record_from_params(parent, active_scaffold_config_for(parent_model).send(params[:parent_id] ? :update : :create).columns, params[:record]) if @column.send_form_on_update_column
97
+ apply_constraints_to_record(parent) if params[:parent_id]
98
+ if record.class.reflect_on_association(association).collection?
99
+ record.send(association) << parent
100
+ else
101
+ record.send("#{association}=", parent)
102
+ end
103
+ end
104
+ end
105
+
106
+ def copy_attributes(orig, dst)
107
+ attributes = orig.attributes
108
+ if orig.class.respond_to? :protected_attributes
109
+ orig.class.protected_attributes.each { |attr| dst[attr] = orig[attr] }
110
+ attributes = attributes.except(*orig.class.protected_attributes)
111
+ end
112
+ dst.attributes = attributes
113
+ dst
114
+ end
67
115
 
68
116
  # override this method if you want to do something after render_field
69
117
  def after_render_field(record, column); end
@@ -134,19 +182,6 @@ module ActiveScaffold::Actions
134
182
  def return_to_main
135
183
  redirect_to main_path_to_return
136
184
  end
137
-
138
- # Override this method on your controller to define conditions to be used when querying a recordset (e.g. for List). The return of this method should be any format compatible with the :conditions clause of ActiveRecord::Base's find.
139
- def conditions_for_collection
140
- end
141
-
142
- # Override this method on your controller to define joins to be used when querying a recordset (e.g. for List). The return of this method should be any format compatible with the :joins clause of ActiveRecord::Base's find.
143
- def joins_for_collection
144
- end
145
-
146
- # Override this method on your controller to provide custom finder options to the find() call. The return of this method should be a hash.
147
- def custom_finder_options
148
- {}
149
- end
150
185
 
151
186
  #Overide this method on your controller to provide model with named scopes
152
187
  def beginning_of_chain
@@ -157,13 +192,18 @@ module ActiveScaffold::Actions
157
192
  def conditions_from_params
158
193
  @conditions_from_params ||= begin
159
194
  conditions = {}
160
- params.except(:controller, :action, :page, :sort, :sort_direction).each do |key, value|
195
+ params.except(:controller, :action, :page, :sort, :sort_direction, :id).each do |key, value|
161
196
  column = active_scaffold_config.model.columns_hash[key.to_s]
162
- key = key.to_sym
163
197
  next unless column
198
+ key = key.to_sym
199
+ not_string = [:string, :text].exclude?(column.type)
164
200
  next if active_scaffold_constraints[key]
165
201
  next if nested? and nested.param_name == key
166
- conditions[key] = column.type_cast(value)
202
+ conditions[key] = if value.is_a?(Array)
203
+ value.map {|v| v == '' && not_string ? nil : column.type_cast(v) }
204
+ else
205
+ value == '' && not_string ? nil : column.type_cast(value)
206
+ end
167
207
  end
168
208
  conditions
169
209
  end
@@ -181,8 +221,39 @@ module ActiveScaffold::Actions
181
221
  model.respond_to?(:build) ? model.build(build_options || {}) : model.new
182
222
  end
183
223
 
224
+ def objects_for_etag
225
+ @last_modified ||= @record.updated_at
226
+ [@record, ('xhr' if request.xhr?)]
227
+ end
228
+
229
+ def view_stale?
230
+ objects = objects_for_etag
231
+ if objects.is_a?(Array)
232
+ args = {:etag => objects.to_a}
233
+ args[:last_modified] = @last_modified if @last_modified
234
+ elsif objects.is_a?(Hash)
235
+ args = {:last_modified => @last_modified}.merge(objects)
236
+ else
237
+ args = objects
238
+ end
239
+ stale?(args)
240
+ end
241
+
242
+ def conditional_get_support?
243
+ request.get? && active_scaffold_config.conditional_get_support
244
+ end
245
+
246
+ def virtual_columns(columns)
247
+ columns.reject {|col| active_scaffold_config.model.columns_hash[col] || active_scaffold_config.model.reflect_on_association(col)}
248
+ end
249
+
250
+ def association_columns(columns)
251
+ columns.select {|col| active_scaffold_config.model.reflect_on_association(col)}
252
+ end
253
+
184
254
  private
185
255
  def respond_to_action(action)
256
+ return unless !conditional_get_support? || view_stale?
186
257
  respond_to do |type|
187
258
  action_formats.each do |format|
188
259
  type.send(format) do