active_scaffold 3.5.5 → 3.6.0.pre

Sign up to get free protection for your applications and to get access to all the features.
Files changed (131) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG +18 -2
  3. data/README.md +17 -7
  4. data/app/assets/javascripts/jquery/active_scaffold.js +28 -2
  5. data/app/views/active_scaffold_overrides/_base_form.html.erb +2 -2
  6. data/app/views/active_scaffold_overrides/_form.html.erb +1 -1
  7. data/app/views/active_scaffold_overrides/_form_association_footer.html.erb +3 -2
  8. data/app/views/active_scaffold_overrides/_form_association_record.html.erb +6 -6
  9. data/app/views/active_scaffold_overrides/_horizontal_subform.html.erb +1 -1
  10. data/app/views/active_scaffold_overrides/_horizontal_subform_header.html.erb +1 -1
  11. data/app/views/active_scaffold_overrides/_list.html.erb +2 -1
  12. data/app/views/active_scaffold_overrides/_list_messages.html.erb +1 -0
  13. data/app/views/active_scaffold_overrides/_messages.html.erb +1 -0
  14. data/app/views/active_scaffold_overrides/_render_field.js.erb +2 -1
  15. data/app/views/active_scaffold_overrides/_show_association_horizontal.html.erb +2 -1
  16. data/app/views/active_scaffold_overrides/_show_columns.html.erb +2 -2
  17. data/app/views/active_scaffold_overrides/_show_horizontal_record.html.erb +4 -4
  18. data/app/views/active_scaffold_overrides/_update_calculations.js.erb +1 -1
  19. data/app/views/active_scaffold_overrides/_update_column.js.erb +2 -2
  20. data/app/views/active_scaffold_overrides/action_confirmation.html.erb +2 -2
  21. data/app/views/active_scaffold_overrides/delete.html.erb +2 -2
  22. data/app/views/active_scaffold_overrides/on_action_update.js.erb +16 -6
  23. data/app/views/active_scaffold_overrides/on_update.js.erb +1 -1
  24. data/app/views/active_scaffold_overrides/row.js.erb +1 -1
  25. data/app/views/active_scaffold_overrides/update_column.js.erb +1 -1
  26. data/lib/active_scaffold.rb +11 -13
  27. data/lib/active_scaffold/actions/core.rb +25 -35
  28. data/lib/active_scaffold/actions/create.rb +1 -1
  29. data/lib/active_scaffold/actions/delete.rb +2 -2
  30. data/lib/active_scaffold/actions/field_search.rb +2 -2
  31. data/lib/active_scaffold/actions/list.rb +8 -7
  32. data/lib/active_scaffold/actions/nested.rb +9 -9
  33. data/lib/active_scaffold/actions/search.rb +1 -1
  34. data/lib/active_scaffold/actions/show.rb +1 -1
  35. data/lib/active_scaffold/actions/subform.rb +3 -1
  36. data/lib/active_scaffold/actions/update.rb +5 -4
  37. data/lib/active_scaffold/active_record_permissions.rb +2 -11
  38. data/lib/active_scaffold/attribute_params.rb +16 -23
  39. data/lib/active_scaffold/bridges.rb +8 -8
  40. data/lib/active_scaffold/bridges/bitfields/bitfields_bridge.rb +1 -1
  41. data/lib/active_scaffold/bridges/calendar_date_select/as_cds_bridge.rb +1 -1
  42. data/lib/active_scaffold/bridges/cancan/cancan_bridge.rb +3 -18
  43. data/lib/active_scaffold/bridges/carrierwave/carrierwave_bridge.rb +1 -1
  44. data/lib/active_scaffold/bridges/chosen/helpers.rb +7 -6
  45. data/lib/active_scaffold/bridges/date_picker/ext.rb +0 -13
  46. data/lib/active_scaffold/bridges/date_picker/helper.rb +3 -3
  47. data/lib/active_scaffold/bridges/file_column/as_file_column_bridge.rb +1 -1
  48. data/lib/active_scaffold/bridges/file_column/file_column_helpers.rb +3 -3
  49. data/lib/active_scaffold/bridges/file_column/test/functional/file_column_keep_test.rb +8 -7
  50. data/lib/active_scaffold/bridges/file_column/test/test_helper.rb +2 -4
  51. data/lib/active_scaffold/bridges/paper_trail.rb +1 -1
  52. data/lib/active_scaffold/bridges/paperclip/list_ui.rb +1 -1
  53. data/lib/active_scaffold/bridges/paperclip/paperclip_bridge.rb +1 -1
  54. data/lib/active_scaffold/bridges/paperclip/paperclip_bridge_helpers.rb +2 -2
  55. data/lib/active_scaffold/bridges/record_select/helpers.rb +9 -9
  56. data/lib/active_scaffold/bridges/shared/date_bridge.rb +3 -3
  57. data/lib/active_scaffold/bridges/usa_state_select/usa_state_select_helper.rb +1 -1
  58. data/lib/active_scaffold/config/base.rb +89 -21
  59. data/lib/active_scaffold/config/core.rb +127 -18
  60. data/lib/active_scaffold/config/delete.rb +2 -0
  61. data/lib/active_scaffold/config/field_search.rb +7 -1
  62. data/lib/active_scaffold/config/form.rb +10 -1
  63. data/lib/active_scaffold/config/list.rb +27 -11
  64. data/lib/active_scaffold/config/mark.rb +3 -1
  65. data/lib/active_scaffold/config/nested.rb +16 -17
  66. data/lib/active_scaffold/config/search.rb +9 -0
  67. data/lib/active_scaffold/config/show.rb +4 -0
  68. data/lib/active_scaffold/config/update.rb +4 -0
  69. data/lib/active_scaffold/configurable.rb +11 -6
  70. data/lib/active_scaffold/constraints.rb +1 -1
  71. data/lib/active_scaffold/core.rb +46 -16
  72. data/lib/active_scaffold/data_structures/action_columns.rb +50 -59
  73. data/lib/active_scaffold/data_structures/action_link.rb +20 -8
  74. data/lib/active_scaffold/data_structures/action_links.rb +6 -2
  75. data/lib/active_scaffold/data_structures/association/abstract.rb +9 -5
  76. data/lib/active_scaffold/data_structures/association/active_record.rb +1 -1
  77. data/lib/active_scaffold/data_structures/column.rb +51 -33
  78. data/lib/active_scaffold/data_structures/nested_info.rb +1 -1
  79. data/lib/active_scaffold/data_structures/set.rb +8 -0
  80. data/lib/active_scaffold/data_structures/sorting.rb +5 -2
  81. data/lib/active_scaffold/delayed_setup.rb +2 -1
  82. data/lib/active_scaffold/extensions/action_controller_rendering.rb +2 -1
  83. data/lib/active_scaffold/extensions/action_view_rendering.rb +1 -1
  84. data/lib/active_scaffold/extensions/cow_proxy.rb +43 -0
  85. data/lib/active_scaffold/extensions/ice_nine.rb +36 -0
  86. data/lib/active_scaffold/extensions/left_outer_joins.rb +8 -33
  87. data/lib/active_scaffold/extensions/routing_mapper.rb +4 -43
  88. data/lib/active_scaffold/extensions/unsaved_record.rb +2 -4
  89. data/lib/active_scaffold/finder.rb +26 -30
  90. data/lib/active_scaffold/helpers/action_link_helpers.rb +16 -16
  91. data/lib/active_scaffold/helpers/association_helpers.rb +5 -5
  92. data/lib/active_scaffold/helpers/controller_helpers.rb +11 -1
  93. data/lib/active_scaffold/helpers/form_column_helpers.rb +25 -24
  94. data/lib/active_scaffold/helpers/id_helpers.rb +2 -2
  95. data/lib/active_scaffold/helpers/list_column_helpers.rb +8 -6
  96. data/lib/active_scaffold/helpers/search_column_helpers.rb +4 -4
  97. data/lib/active_scaffold/helpers/view_helpers.rb +7 -13
  98. data/lib/active_scaffold/marked_model.rb +2 -2
  99. data/lib/active_scaffold/orm_checks.rb +1 -5
  100. data/lib/active_scaffold/paginator.rb +6 -4
  101. data/lib/active_scaffold/registry.rb +22 -0
  102. data/lib/active_scaffold/responds_to_parent.rb +2 -6
  103. data/lib/active_scaffold/tableless.rb +63 -59
  104. data/lib/active_scaffold/version.rb +2 -2
  105. data/lib/generators/active_scaffold/controller_generator.rb +2 -2
  106. data/lib/generators/active_scaffold/install_generator.rb +1 -1
  107. data/lib/generators/active_scaffold/resource_generator.rb +2 -2
  108. data/test/bridges/date_picker_test.rb +1 -2
  109. data/test/bridges/paperclip_test.rb +5 -5
  110. data/test/class_with_finder.rb +2 -2
  111. data/test/company.rb +2 -2
  112. data/test/config/create_test.rb +4 -2
  113. data/test/config/nested_test.rb +1 -1
  114. data/test/config/show_test.rb +1 -1
  115. data/test/config/update_test.rb +7 -6
  116. data/test/data_structures/action_links_test.rb +1 -1
  117. data/test/data_structures/sorting_test.rb +7 -0
  118. data/test/misc/active_record_permissions_test.rb +1 -9
  119. data/test/misc/attribute_params_test.rb +8 -8
  120. data/test/misc/calculation_test.rb +1 -1
  121. data/test/misc/constraints_test.rb +2 -2
  122. data/test/misc/convert_numbers_format_test.rb +3 -3
  123. data/test/misc/lang_test.rb +1 -1
  124. data/test/misc/parse_datetime_test.rb +3 -4
  125. data/test/misc/tableless_test.rb +6 -0
  126. data/test/mock_app/Rakefile +1 -1
  127. data/test/mock_app/config/application.rb +1 -1
  128. data/test/mock_app/config/boot.rb +1 -1
  129. data/test/mock_app/config/environment.rb +2 -2
  130. data/test/test_helper.rb +8 -1
  131. metadata +38 -13
@@ -6,7 +6,7 @@ module ActiveScaffold
6
6
  return nil unless paperclip.file?
7
7
  content =
8
8
  if paperclip.styles.include?(ActiveScaffold::Bridges::Paperclip::PaperclipBridgeHelpers.thumbnail_style)
9
- image_tag(paperclip.url(ActiveScaffold::Bridges::Paperclip::PaperclipBridgeHelpers.thumbnail_style), :border => 0)
9
+ image_tag(paperclip.url(ActiveScaffold::Bridges::Paperclip::PaperclipBridgeHelpers.thumbnail_style), :border => 0, :alt => nil)
10
10
  else
11
11
  paperclip.original_filename
12
12
  end
@@ -9,7 +9,7 @@ module ActiveScaffold
9
9
  update.multipart = true
10
10
  create.multipart = true
11
11
 
12
- model.attachment_definitions.keys.each do |field|
12
+ model.attachment_definitions.each_key do |field|
13
13
  configure_paperclip_field(field.to_sym)
14
14
  # define the "delete" helper for use with active scaffold, unless it's already defined
15
15
  ActiveScaffold::Bridges::Paperclip::PaperclipBridgeHelpers.generate_delete_helper(model, field)
@@ -6,7 +6,7 @@ module ActiveScaffold
6
6
  self.thumbnail_style = :thumbnail
7
7
 
8
8
  def self.generate_delete_helper(klass, field)
9
- klass.class_eval <<-EOF, __FILE__, __LINE__ + 1 unless klass.method_defined?(:"delete_#{field}=")
9
+ klass.class_eval <<-END, __FILE__, __LINE__ + 1 unless klass.method_defined?(:"delete_#{field}=")
10
10
  attr_reader :delete_#{field}
11
11
 
12
12
  def delete_#{field}=(value)
@@ -16,7 +16,7 @@ module ActiveScaffold
16
16
  # passing nil to the file column causes the file to be deleted. Don't delete if we just uploaded a file!
17
17
  self.#{field} = nil unless self.#{field}.dirty?
18
18
  end
19
- EOF
19
+ END
20
20
  end
21
21
  end
22
22
  end
@@ -1,21 +1,21 @@
1
+ require 'active_support/concern'
2
+
1
3
  class ActiveScaffold::Bridges::RecordSelect
2
4
  module Helpers
3
- def self.included(base)
4
- base.class_eval do
5
- include FormColumnHelpers
6
- include SearchColumnHelpers
7
- end
5
+ extend ActiveSupport::Concern
6
+ included do
7
+ include FormColumnHelpers
8
+ include SearchColumnHelpers
8
9
  end
9
10
 
10
11
  module FormColumnHelpers
11
12
  # requires RecordSelect plugin to be installed and configured.
12
13
  def active_scaffold_input_record_select(column, options)
13
14
  record = options.delete(:object)
14
- if column.association.try(:singular?)
15
- multiple = false
16
- multiple = column.options[:html_options][:multiple] if column.options[:html_options] && column.options[:html_options][:multiple]
15
+ if column.association&.singular?
16
+ multiple = column.options.dig(:html_options, :multiple)
17
17
  active_scaffold_record_select(record, column, options, record.send(column.name), multiple)
18
- elsif column.association.try(:collection?)
18
+ elsif column.association&.collection?
19
19
  active_scaffold_record_select(record, column, options, record.send(column.name), true)
20
20
  else
21
21
  active_scaffold_record_select_autocomplete(record, column, options)
@@ -66,7 +66,7 @@ module ActiveScaffold
66
66
  :class => 'text-input', :id => nil)
67
67
  content_tag('span', range_controls.html_safe,
68
68
  :id => "#{options[:id]}_range", :class => 'search-date-range',
69
- :style => (current_search['opt'] == 'RANGE') ? nil : 'display: none')
69
+ :style => ('display: none' unless current_search['opt'] == 'RANGE'))
70
70
  end
71
71
 
72
72
  def column_datetime?(column)
@@ -120,9 +120,9 @@ module ActiveScaffold
120
120
  column.search_sql.call(from_value, to_value, operator)
121
121
  else
122
122
  if operator.nil?
123
- ['%{search_sql} BETWEEN ? AND ?', from_value.to_s(:db), to_value.to_s(:db)] unless from_value.nil? || to_value.nil?
123
+ ['%<search_sql>s BETWEEN ? AND ?', from_value.to_s(:db), to_value.to_s(:db)] unless from_value.nil? || to_value.nil?
124
124
  else
125
- ["%{search_sql} #{value['opt']} ?", from_value.to_s(:db)] unless from_value.nil?
125
+ ["%<search_sql>s #{value['opt']} ?", from_value.to_s(:db)] unless from_value.nil?
126
126
  end
127
127
  end
128
128
  end
@@ -23,7 +23,7 @@ module ActiveScaffold::Bridges
23
23
  options_for_select([])
24
24
  end
25
25
 
26
- state_options += if priority_states && priority_states.include?(selected)
26
+ state_options += if priority_states&.include?(selected)
27
27
  options_for_select(USASTATES - priority_states, :selected => selected)
28
28
  else
29
29
  options_for_select(USASTATES, :selected => selected)
@@ -2,6 +2,7 @@ module ActiveScaffold::Config
2
2
  class Base
3
3
  include ActiveScaffold::Configurable
4
4
  extend ActiveScaffold::Configurable
5
+ NO_FORMATS = [].freeze
5
6
 
6
7
  def initialize(core_config)
7
8
  @core = core_config
@@ -37,8 +38,22 @@ module ActiveScaffold::Config
37
38
  @label.nil? ? model : as_(@label, :model => model)
38
39
  end
39
40
 
41
+ def model_id
42
+ (core || self).model_id
43
+ end
44
+
45
+ def user_settings_key
46
+ :"#{model_id}_#{self.class.name.underscore}"
47
+ end
48
+
40
49
  # the user property gets set to the instantiation of the local UserSettings class during the automatic instantiation of this class.
41
- attr_accessor :user
50
+ def user
51
+ ActiveScaffold::Registry.user_settings[user_settings_key]
52
+ end
53
+
54
+ def new_user_settings(storage, params)
55
+ ActiveScaffold::Registry.user_settings[user_settings_key] = self.class::UserSettings.new(self, storage, params)
56
+ end
42
57
 
43
58
  # define a default action_group for this action
44
59
  # e.g. 'members.crud'
@@ -47,10 +62,39 @@ module ActiveScaffold::Config
47
62
  # action_group this action should belong to
48
63
  attr_accessor :action_group
49
64
 
65
+ def formats
66
+ return @formats || NO_FORMATS if frozen?
67
+ @formats ||= NO_FORMATS.dup
68
+ end
69
+ attr_writer :formats
70
+
50
71
  class UserSettings
72
+ # define setter and getter for names
73
+ # values will be saved for current request only
74
+ # getter will return value set with setter, or value from conf
75
+ def self.user_attr(*names)
76
+ attr_writer(*names)
77
+ names.each do |name|
78
+ define_method(name) do
79
+ instance_variable_defined?("@#{name}") ? instance_variable_get("@#{name}") : @conf.send(name)
80
+ end
81
+ end
82
+ end
83
+
84
+ # define setter and getter for names
85
+ # values will be saved in session if store_user_settings is enabled,
86
+ # in other case for current request only
87
+ # getter will return value set with setter, or value from conf
88
+ def self.session_attr(*names)
89
+ names.each do |name|
90
+ define_method(name) { |value| self[name] = value }
91
+ define_method(name) { key?(name) ? self[name] : @conf.send(name) }
92
+ end
93
+ end
94
+
51
95
  def initialize(conf, storage, params, action = :base)
52
96
  # the session hash relevant to this action
53
- @session = storage
97
+ @storage = storage
54
98
  # all the request params
55
99
  @params = params
56
100
  # the configuration object for this action
@@ -58,51 +102,75 @@ module ActiveScaffold::Config
58
102
  @action = action.to_s
59
103
  end
60
104
 
105
+ def user
106
+ self
107
+ end
108
+
109
+ def core
110
+ @conf.core.user
111
+ end
112
+
61
113
  def [](key)
62
- @session[@action][key] if @action && @session[@action]
114
+ @storage[@action][key.to_s] if @action && @storage[@action]
63
115
  end
64
116
 
65
117
  def []=(key, value)
66
- @session[@action] ||= {}
118
+ @storage[@action] ||= {}
67
119
  if value
68
- @session[@action][key] = value
120
+ @storage[@action][key.to_s] = value
69
121
  else
70
- @session[@action].delete key
71
- @session.delete @action if @session[@action].empty?
122
+ @storage[@action].delete key.to_s
123
+ @storage.delete @action if @storage[@action].empty?
72
124
  end
73
125
  end
74
- end
75
126
 
76
- def formats
77
- @formats ||= []
127
+ def key?(key)
128
+ @storage[@action].key? key.to_s if @action && @storage[@action]
129
+ end
130
+
131
+ def method_missing(name, *args)
132
+ @conf.respond_to?(name, true) ? @conf.send(name, *args) : super
133
+ end
134
+
135
+ def respond_to_missing?(name, include_all = false)
136
+ @conf.respond_to?(name, include_all) || super
137
+ end
78
138
  end
79
- attr_writer :formats
80
139
 
81
140
  private
82
141
 
83
142
  def build_action_columns(val)
84
- columns =
85
- if val.is_a?(ActiveScaffold::DataStructures::ActionColumns)
86
- val.dup
87
- else
88
- ActiveScaffold::DataStructures::ActionColumns.new(*val)
89
- end
90
- columns.action = self
91
- columns.set_columns(@core.columns)
92
- columns
143
+ @core.build_action_columns self, val
93
144
  end
94
145
 
146
+ class_attribute :columns_collections
147
+
95
148
  def self.columns_accessor(*names, &block)
96
149
  options = names.extract_options!
150
+ self.columns_collections = ((columns_collections || []) + names).uniq
97
151
  names.each do |name|
98
152
  var = "@#{name}"
99
153
  define_method "#{name}=" do |val|
100
154
  if instance_variable_defined?(var)
101
155
  instance_variable_get(var).set_values(*val)
156
+ instance_variable_get(var)
102
157
  else
103
158
  instance_variable_set(var, build_action_columns(val))
104
159
  end
105
- instance_variable_get(var)
160
+ end
161
+
162
+ if self::UserSettings == ActiveScaffold::Config::Base::UserSettings
163
+ const_set 'UserSettings', Class.new(ActiveScaffold::Config::Base::UserSettings)
164
+ end
165
+
166
+ self::UserSettings.class_eval do
167
+ define_method "#{name}=" do |val|
168
+ instance_variable_set var, ::CowProxy.wrap(build_action_columns(val))
169
+ end
170
+ define_method name do
171
+ instance_variable_get(var) ||
172
+ instance_variable_set(var, ::CowProxy.wrap(@conf.send(name)))
173
+ end
106
174
  end
107
175
 
108
176
  return if method_defined? name
@@ -60,6 +60,11 @@ module ActiveScaffold::Config
60
60
  ActiveScaffold::ActiveRecordPermissions
61
61
  end
62
62
 
63
+ # access to default column configuration.
64
+ def self.column
65
+ ActiveScaffold::DataStructures::Column
66
+ end
67
+
63
68
  # columns that should be ignored for every model. these should be metadata columns like change dates, versions, etc.
64
69
  # values in this array may be symbols or strings.
65
70
  def self.ignore_columns
@@ -83,6 +88,12 @@ module ActiveScaffold::Config
83
88
  cattr_accessor :highlight_messages, instance_accessor: false
84
89
  @@highlight_messages = nil
85
90
 
91
+ def self.freeze
92
+ super
93
+ security.freeze
94
+ column.freeze
95
+ end
96
+
86
97
  # instance-level configuration
87
98
  # ----------------------------
88
99
 
@@ -182,12 +193,17 @@ module ActiveScaffold::Config
182
193
  @highlight_messages = self.class.highlight_messages
183
194
  end
184
195
 
185
- # To be called after your finished configuration
186
- def _load_action_columns
187
- # then, register the column objects
196
+ # To be called before freezing
197
+ def _cache_lazy_values
198
+ action_links.each(&:name_to_cache) if cache_action_link_urls
199
+ # ensure member and collection groups are cached, if no custom link has been added
200
+ action_links.member
201
+ action_links.collection
202
+ columns.select(&:sortable?).each(&:sort)
203
+ columns.select(&:searchable?).each(&:search_sql)
188
204
  actions.each do |action_name|
189
205
  action = send(action_name)
190
- action.columns.set_columns(columns) if action.respond_to?(:columns)
206
+ Array(action.class.columns_collections).each { |method| action.send(method) }
191
207
  end
192
208
  end
193
209
 
@@ -205,28 +221,57 @@ module ActiveScaffold::Config
205
221
  end
206
222
  end
207
223
 
224
+ def _setup_action(action)
225
+ define_singleton_method action do
226
+ self[action]
227
+ end
228
+ end
229
+
208
230
  # configuration routing.
209
231
  # we want to route calls named like an activated action to that action's global or local Config class.
210
232
  # ---------------------------
211
233
  def method_missing(name, *args)
212
- @action_configs ||= {}
213
- titled_name = name.to_s.camelcase
214
- underscored_name = name.to_s.underscore.to_sym
215
- klass = "ActiveScaffold::Config::#{titled_name}".constantize rescue nil
216
- if klass
217
- if @actions.include? underscored_name
218
- return @action_configs[underscored_name] ||= klass.new(self)
219
- else
220
- raise "#{titled_name} is not enabled. Please enable it or remove any references in your configuration (e.g. config.#{underscored_name}.columns = [...])."
221
- end
234
+ self[name] || super
235
+ end
236
+
237
+ def respond_to_missing?(name, include_all = false)
238
+ self.class.config_class?(name) && @actions.include?(action_name.to_s.underscore.to_sym) || super
239
+ end
240
+
241
+ def [](action_name)
242
+ klass = self.class.config_class(action_name)
243
+ return unless klass
244
+
245
+ underscored_name = action_name.to_s.underscore.to_sym
246
+ if @actions.include? underscored_name
247
+ @action_configs ||= {}
248
+ @action_configs[underscored_name] ||= klass.new(self)
249
+ else
250
+ raise "#{action_name.to_s.camelcase} is not enabled. Please enable it or remove any references in your configuration (e.g. config.#{underscored_name}.columns = [...])."
222
251
  end
223
- super
224
252
  end
225
253
 
254
+ def []=(action_name, action_config)
255
+ @action_configs ||= {}
256
+ @action_configs[action_name] = action_config
257
+ end
258
+ private :[]=
259
+
226
260
  def self.method_missing(name, *args)
227
- klass = "ActiveScaffold::Config::#{name.to_s.camelcase}".constantize rescue nil
228
- return klass if @@actions.include?(name.to_s.underscore) && klass
229
- super
261
+ klass = config_class(name) if @@actions.include?(name.to_s.underscore)
262
+ klass || super
263
+ end
264
+
265
+ def self.config_class(name)
266
+ "ActiveScaffold::Config::#{name.to_s.camelcase}".constantize if config_class?(name)
267
+ end
268
+
269
+ def self.config_class?(name)
270
+ ActiveScaffold::Config.const_defined? name.to_s.camelcase
271
+ end
272
+
273
+ def self.respond_to_missing?(name, include_all = false)
274
+ config_class?(name) && @@actions.include?(name.to_s.underscore) || super
230
275
  end
231
276
  # some utility methods
232
277
  # --------------------
@@ -247,6 +292,17 @@ module ActiveScaffold::Config
247
292
  @inherited_view_paths ||= []
248
293
  end
249
294
 
295
+ def build_action_columns(action, columns)
296
+ action_columns =
297
+ if columns.is_a?(ActiveScaffold::DataStructures::ActionColumns)
298
+ columns.dup
299
+ else
300
+ ActiveScaffold::DataStructures::ActionColumns.new(*columns)
301
+ end
302
+ action_columns.action = action.is_a?(Symbol) ? send(action) : action
303
+ action_columns
304
+ end
305
+
250
306
  # must be a class method so the layout doesn't depend on a controller that uses active_scaffold
251
307
  # note that this is unaffected by per-controller frontend configuration.
252
308
  def self.asset_path(filename, frontend = self.frontend)
@@ -264,5 +320,58 @@ module ActiveScaffold::Config
264
320
  frontends_dir = Rails.root.join('vendor', 'plugins', ActiveScaffold::Config::Core.plugin_directory, 'frontends')
265
321
  Dir.entries(frontends_dir).reject { |e| e.match(/^\./) } # Get rid of files that start with .
266
322
  end
323
+
324
+ class UserSettings < UserSettings
325
+ include ActiveScaffold::Configurable
326
+ user_attr :cache_action_link_urls, :cache_association_options, :conditional_get_support,
327
+ :timestamped_messages, :highlight_messages
328
+
329
+ def method_missing(name, *args)
330
+ value = @conf.actions.include?(name) ? @conf.send(name) : super
331
+ value.is_a?(Base) ? action_user_settings(value) : value
332
+ end
333
+
334
+ def respond_to_missing?(name, include_all = false)
335
+ super # avoid rubocop warning
336
+ end
337
+
338
+ def action_user_settings(action_config)
339
+ if action_config.user.nil? && action_config.respond_to?(:new_user_settings)
340
+ action_config.new_user_settings @storage, @params
341
+ end
342
+ action_config.user || action_config
343
+ end
344
+
345
+ def columns
346
+ @columns ||= UserColumns.new(@conf.columns)
347
+ end
348
+
349
+ def action_links
350
+ @action_links ||= CowProxy.wrap(@conf.action_links)
351
+ end
352
+ end
353
+
354
+ class UserColumns
355
+ def initialize(columns)
356
+ @global_columns = columns
357
+ @columns = {}
358
+ end
359
+
360
+ def [](name)
361
+ @columns[name.to_sym] ||= CowProxy.wrap @global_columns[name]
362
+ end
363
+
364
+ def method_missing(name, *args)
365
+ if @global_columns.respond_to?(name, true)
366
+ @global_columns.send(name, *args)
367
+ else
368
+ super
369
+ end
370
+ end
371
+
372
+ def respond_to_missing?(name, include_all = false)
373
+ @global_columns.respond_to?(name, include_all) || super
374
+ end
375
+ end
267
376
  end
268
377
  end