active_scaffold 3.5.5 → 3.6.0.pre

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (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