active_scaffold 3.6.0.pre → 3.6.0.rc1

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 (118) hide show
  1. checksums.yaml +4 -4
  2. data/{CHANGELOG → CHANGELOG.rdoc} +39 -0
  3. data/app/assets/javascripts/active_scaffold.js.erb +0 -1
  4. data/app/assets/javascripts/jquery/active_scaffold.js +35 -4
  5. data/app/assets/stylesheets/active_scaffold_colors.scss +1 -1
  6. data/app/assets/stylesheets/active_scaffold_layout.css +52 -29
  7. data/app/views/active_scaffold_overrides/_list_header.html.erb +5 -7
  8. data/app/views/active_scaffold_overrides/_list_record.html.erb +4 -5
  9. data/app/views/active_scaffold_overrides/_list_with_header.html.erb +1 -1
  10. data/app/views/active_scaffold_overrides/_refresh_list.js.erb +4 -0
  11. data/config/locales/de.yml +2 -1
  12. data/config/locales/en.yml +1 -0
  13. data/config/locales/es.yml +1 -0
  14. data/config/locales/fr.yml +2 -1
  15. data/config/locales/hu.yml +1 -0
  16. data/config/locales/ja.yml +1 -0
  17. data/config/locales/ru.yml +1 -0
  18. data/lib/active_scaffold.rb +8 -3
  19. data/lib/active_scaffold/actions/common_search.rb +11 -8
  20. data/lib/active_scaffold/actions/core.rb +79 -51
  21. data/lib/active_scaffold/actions/create.rb +27 -27
  22. data/lib/active_scaffold/actions/delete.rb +1 -1
  23. data/lib/active_scaffold/actions/field_search.rb +52 -42
  24. data/lib/active_scaffold/actions/list.rb +106 -23
  25. data/lib/active_scaffold/actions/nested.rb +59 -42
  26. data/lib/active_scaffold/actions/show.rb +3 -3
  27. data/lib/active_scaffold/actions/subform.rb +9 -16
  28. data/lib/active_scaffold/actions/update.rb +95 -77
  29. data/lib/active_scaffold/attribute_params.rb +93 -68
  30. data/lib/active_scaffold/bridges/active_storage.rb +6 -0
  31. data/lib/active_scaffold/bridges/active_storage/active_storage_bridge.rb +33 -0
  32. data/lib/active_scaffold/bridges/active_storage/active_storage_helpers.rb +54 -0
  33. data/lib/active_scaffold/bridges/active_storage/form_ui.rb +22 -0
  34. data/lib/active_scaffold/bridges/active_storage/list_ui.rb +36 -0
  35. data/lib/active_scaffold/bridges/bitfields.rb +1 -0
  36. data/lib/active_scaffold/bridges/bitfields/bitfields_bridge.rb +12 -15
  37. data/lib/active_scaffold/bridges/cancan/cancan_bridge.rb +6 -0
  38. data/lib/active_scaffold/bridges/carrierwave/list_ui.rb +2 -2
  39. data/lib/active_scaffold/bridges/date_picker/helper.rb +46 -41
  40. data/lib/active_scaffold/bridges/dragonfly/list_ui.rb +1 -1
  41. data/lib/active_scaffold/bridges/file_column/file_column_helpers.rb +2 -2
  42. data/lib/active_scaffold/bridges/file_column/form_ui.rb +3 -3
  43. data/lib/active_scaffold/bridges/file_column/test/functional/file_column_keep_test.rb +3 -1
  44. data/lib/active_scaffold/bridges/paperclip/paperclip_bridge_helpers.rb +2 -2
  45. data/lib/active_scaffold/bridges/record_select/helpers.rb +3 -7
  46. data/lib/active_scaffold/bridges/shared/date_bridge.rb +19 -18
  47. data/lib/active_scaffold/bridges/tiny_mce/helpers.rb +3 -1
  48. data/lib/active_scaffold/bridges/usa_state_select/usa_state_select_helper.rb +20 -3
  49. data/lib/active_scaffold/config/base.rb +58 -34
  50. data/lib/active_scaffold/config/core.rb +31 -12
  51. data/lib/active_scaffold/config/delete.rb +12 -1
  52. data/lib/active_scaffold/config/list.rb +17 -7
  53. data/lib/active_scaffold/config/mark.rb +1 -1
  54. data/lib/active_scaffold/configurable.rb +5 -3
  55. data/lib/active_scaffold/constraints.rb +21 -19
  56. data/lib/active_scaffold/core.rb +35 -26
  57. data/lib/active_scaffold/data_structures/action_columns.rb +1 -1
  58. data/lib/active_scaffold/data_structures/action_link.rb +34 -16
  59. data/lib/active_scaffold/data_structures/action_links.rb +9 -11
  60. data/lib/active_scaffold/data_structures/association/abstract.rb +35 -13
  61. data/lib/active_scaffold/data_structures/association/active_mongoid.rb +2 -6
  62. data/lib/active_scaffold/data_structures/association/active_record.rb +5 -1
  63. data/lib/active_scaffold/data_structures/association/mongoid.rb +0 -3
  64. data/lib/active_scaffold/data_structures/column.rb +49 -58
  65. data/lib/active_scaffold/data_structures/columns.rb +3 -2
  66. data/lib/active_scaffold/data_structures/nested_info.rb +20 -18
  67. data/lib/active_scaffold/data_structures/sorting.rb +5 -0
  68. data/lib/active_scaffold/delayed_setup.rb +16 -6
  69. data/lib/active_scaffold/extensions/action_controller_rendering.rb +1 -1
  70. data/lib/active_scaffold/extensions/action_view_rendering.rb +34 -14
  71. data/lib/active_scaffold/extensions/cow_proxy.rb +50 -2
  72. data/lib/active_scaffold/extensions/localize.rb +3 -1
  73. data/lib/active_scaffold/extensions/routing_mapper.rb +2 -2
  74. data/lib/active_scaffold/extensions/to_label.rb +3 -2
  75. data/lib/active_scaffold/finder.rb +81 -46
  76. data/lib/active_scaffold/helpers/action_link_helpers.rb +47 -21
  77. data/lib/active_scaffold/helpers/association_helpers.rb +13 -11
  78. data/lib/active_scaffold/helpers/controller_helpers.rb +14 -11
  79. data/lib/active_scaffold/helpers/form_column_helpers.rb +133 -99
  80. data/lib/active_scaffold/helpers/human_condition_helpers.rb +1 -1
  81. data/lib/active_scaffold/helpers/id_helpers.rb +4 -0
  82. data/lib/active_scaffold/helpers/list_column_helpers.rb +76 -49
  83. data/lib/active_scaffold/helpers/pagination_helpers.rb +2 -2
  84. data/lib/active_scaffold/helpers/search_column_helpers.rb +25 -30
  85. data/lib/active_scaffold/helpers/show_column_helpers.rb +3 -5
  86. data/lib/active_scaffold/helpers/view_helpers.rb +31 -22
  87. data/lib/active_scaffold/orm_checks.rb +2 -2
  88. data/lib/active_scaffold/paginator.rb +1 -3
  89. data/lib/active_scaffold/registry.rb +11 -0
  90. data/lib/active_scaffold/responds_to_parent.rb +6 -5
  91. data/lib/active_scaffold/tableless.rb +6 -8
  92. data/lib/active_scaffold/version.rb +1 -1
  93. data/shoulda_macros/macros.rb +3 -1
  94. data/test/bridges/paperclip_test.rb +1 -1
  95. data/test/company.rb +2 -2
  96. data/test/data_structures/action_columns_test.rb +2 -2
  97. data/test/data_structures/column_test.rb +3 -6
  98. data/test/data_structures/columns_test.rb +2 -2
  99. data/test/extensions/active_record_test.rb +4 -4
  100. data/test/extensions/routing_mapper_test.rb +2 -2
  101. data/test/helpers/list_column_helpers_test.rb +3 -1
  102. data/test/misc/active_record_permissions_test.rb +2 -2
  103. data/test/misc/attribute_params_test.rb +4 -0
  104. data/test/misc/configurable_test.rb +10 -10
  105. data/test/misc/convert_numbers_format_test.rb +4 -0
  106. data/test/mock_app/app/assets/config/manifest.js +0 -0
  107. data/test/mock_app/app/controllers/cars_controller.rb +1 -0
  108. data/test/mock_app/app/controllers/people_controller.rb +3 -1
  109. data/test/mock_app/config/application.rb +1 -0
  110. data/test/mock_app/config/routes.rb +4 -1
  111. data/test/mock_app/db/schema.rb +2 -0
  112. data/test/performance/list_cars_performance_test.rb +34 -0
  113. data/test/performance/list_people_performance_test.rb +31 -0
  114. data/test/performance_test_help.rb +3 -0
  115. data/test/test_helper.rb +2 -1
  116. metadata +22 -12
  117. data/app/assets/javascripts/prototype/rico_corner.js +0 -370
  118. data/lib/active_scaffold/bridges/file_column/test/test_helper.rb +0 -5
@@ -24,14 +24,10 @@ class ActiveScaffold::Bridges::RecordSelect
24
24
 
25
25
  def active_scaffold_record_select(record, column, options, value, multiple)
26
26
  unless column.association
27
- raise ArgumentError, "record_select can only work against associations (and #{column.name} is not). A common mistake is to specify the foreign key field (like :user_id), instead of the association (:user)."
27
+ raise ArgumentError, "record_select can only work against associations (and #{column.name} is not). "\
28
+ 'A common mistake is to specify the foreign key field (like :user_id), instead of the association (:user).'
28
29
  end
29
- klass =
30
- if column.association.polymorphic?
31
- record.send(column.association.foreign_type).constantize rescue nil
32
- else
33
- column.association.klass
34
- end
30
+ klass = column.association.klass(record)
35
31
  return content_tag :span, '', :class => options[:class] unless klass
36
32
 
37
33
  remote_controller = active_scaffold_controller_for(klass).controller_path
@@ -12,7 +12,7 @@ module ActiveScaffold
12
12
  tags << active_scaffold_search_date_bridge_trend_tag(column, options, current_search)
13
13
  tags << active_scaffold_search_date_bridge_numeric_tag(column, options, current_search)
14
14
  tags << active_scaffold_search_date_bridge_range_tag(column, options, current_search)
15
- safe_join tags, '&nbsp;'.html_safe
15
+ safe_join tags, '&nbsp;'.html_safe # rubocop:disable Rails/OutputSafety
16
16
  end
17
17
 
18
18
  def active_scaffold_search_date_bridge_comparator_options(column)
@@ -21,17 +21,18 @@ module ActiveScaffold
21
21
  end
22
22
 
23
23
  def active_scaffold_search_date_bridge_comparator_tag(column, options, current_search)
24
- select_tag("#{options[:name]}[opt]", options_for_select(active_scaffold_search_date_bridge_comparator_options(column), current_search['opt']), :id => "#{options[:id]}_opt", :class => 'as_search_range_option as_search_date_time_option')
24
+ choices = options_for_select(active_scaffold_search_date_bridge_comparator_options(column), current_search['opt'])
25
+ select_tag("#{options[:name]}[opt]", choices, :id => "#{options[:id]}_opt", :class => 'as_search_range_option as_search_date_time_option')
25
26
  end
26
27
 
27
28
  def active_scaffold_search_date_bridge_numeric_tag(column, options, current_search)
28
- numeric_controls =
29
- '' <<
30
- active_scaffold_search_date_bridge_calendar_control(column, options, current_search, 'from') <<
31
- content_tag(:span, (' - ' + active_scaffold_search_date_bridge_calendar_control(column, options, current_search, 'to')).html_safe,
29
+ numeric_controls = [
30
+ active_scaffold_search_date_bridge_calendar_control(column, options, current_search, 'from'),
31
+ content_tag(:span, safe_join([' - ', active_scaffold_search_date_bridge_calendar_control(column, options, current_search, 'to')]),
32
32
  :id => "#{options[:id]}_between", :class => 'as_search_range_between',
33
33
  :style => current_search['opt'] == 'BETWEEN' ? nil : 'display: none')
34
- content_tag('span', numeric_controls.html_safe,
34
+ ]
35
+ content_tag('span', safe_join(numeric_controls),
35
36
  :id => "#{options[:id]}_numeric", :class => 'search-date-numeric',
36
37
  :style => ActiveScaffold::Finder::NUMERIC_COMPARATORS.include?(current_search['opt']) ? nil : 'display: none')
37
38
  end
@@ -44,12 +45,13 @@ module ActiveScaffold
44
45
  end
45
46
 
46
47
  def active_scaffold_date_bridge_trend_tag(column, options, trend_options)
47
- trend_controls =
48
- text_field_tag("#{options[:name]}[number]", trend_options[:number_value], :class => 'text-input', :size => 10, :autocomplete => 'off') << ' ' <<
48
+ trend_controls = [
49
+ text_field_tag("#{options[:name]}[number]", trend_options[:number_value], :class => 'text-input', :size => 10, :autocomplete => 'off'),
49
50
  select_tag("#{options[:name]}[unit]",
50
51
  options_for_select(active_scaffold_search_date_bridge_trend_units(column), trend_options[:unit_value]),
51
52
  :class => 'text-input')
52
- content_tag('span', trend_controls.html_safe,
53
+ ]
54
+ content_tag('span', safe_join(trend_controls, ' '),
53
55
  :id => "#{options[:id]}_trend", :class => 'search-date-trend',
54
56
  :style => trend_options[:show] ? nil : 'display: none')
55
57
  end
@@ -61,10 +63,11 @@ module ActiveScaffold
61
63
  end
62
64
 
63
65
  def active_scaffold_search_date_bridge_range_tag(column, options, current_search)
66
+ values = ActiveScaffold::Finder::DATE_RANGES.collect { |range| [as_(range.downcase.to_sym), range] }
64
67
  range_controls = select_tag("#{options[:name]}[range]",
65
- options_for_select(ActiveScaffold::Finder::DATE_RANGES.collect { |range| [as_(range.downcase.to_sym), range] }, current_search['range']),
68
+ options_for_select(values, current_search['range']),
66
69
  :class => 'text-input', :id => nil)
67
- content_tag('span', range_controls.html_safe,
70
+ content_tag('span', range_controls,
68
71
  :id => "#{options[:id]}_range", :class => 'search-date-range',
69
72
  :style => ('display: none' unless current_search['opt'] == 'RANGE'))
70
73
  end
@@ -80,7 +83,7 @@ module ActiveScaffold
80
83
  when 'RANGE'
81
84
  range_type, range = value['range'].downcase.split('_')
82
85
  format = active_scaffold_human_condition_date_bridge_range_format(range_type, range)
83
- from, to = controller.class.date_bridge_from_to(column, value)
86
+ from, = controller.class.date_bridge_from_to(column, value)
84
87
  "#{column.active_record_class.human_attribute_name(column.name)} = #{as_(value['range'].downcase).downcase} (#{I18n.l(from, :format => format)})"
85
88
  when 'PAST', 'FUTURE'
86
89
  from, to = controller.class.date_bridge_from_to(column, value)
@@ -118,12 +121,10 @@ module ActiveScaffold
118
121
 
119
122
  if column.search_sql.is_a? Proc
120
123
  column.search_sql.call(from_value, to_value, operator)
124
+ elsif operator.nil?
125
+ ['%<search_sql>s BETWEEN ? AND ?', from_value.to_s(:db), to_value.to_s(:db)] unless from_value.nil? || to_value.nil?
121
126
  else
122
- if operator.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
- else
125
- ["%<search_sql>s #{value['opt']} ?", from_value.to_s(:db)] unless from_value.nil?
126
- end
127
+ ["%<search_sql>s #{value['opt']} ?", from_value.to_s(:db)] unless from_value.nil?
127
128
  end
128
129
  end
129
130
 
@@ -24,7 +24,9 @@ class ActiveScaffold::Bridges::TinyMce
24
24
 
25
25
  html = []
26
26
  html << send(override_input(:textarea), column, options)
27
- html << javascript_tag("tinyMCE.settings = #{settings.to_json}; tinyMCE.execCommand('mceAddEditor', false, '#{options[:id]}');") if ActiveScaffold.js_framework == :prototype && (request.xhr? || params[:iframe])
27
+ if ActiveScaffold.js_framework == :prototype && (request.xhr? || params[:iframe])
28
+ html << javascript_tag("tinyMCE.settings = #{settings.to_json}; tinyMCE.execCommand('mceAddEditor', false, '#{options[:id]}');")
29
+ end
28
30
  safe_join html
29
31
  end
30
32
 
@@ -32,15 +32,32 @@ module ActiveScaffold::Bridges
32
32
  state_options
33
33
  end
34
34
 
35
- USASTATES = [%w[Alabama AL], %w[Alaska AK], %w[Arizona AZ], %w[Arkansas AR], %w[California CA], %w[Colorado CO], %w[Connecticut CT], %w[Delaware DE], ['District of Columbia', 'DC'], %w[Florida FL], %w[Georgia GA], %w[Hawaii HI], %w[Idaho ID], %w[Illinois IL], %w[Indiana IN], %w[Iowa IA], %w[Kansas KS], %w[Kentucky KY], %w[Louisiana LA], %w[Maine ME], %w[Maryland MD], %w[Massachusetts MA], %w[Michigan MI], %w[Minnesota MN], %w[Mississippi MS], %w[Missouri MO], %w[Montana MT], %w[Nebraska NE], %w[Nevada NV], ['New Hampshire', 'NH'], ['New Jersey', 'NJ'], ['New Mexico', 'NM'], ['New York', 'NY'], ['North Carolina', 'NC'], ['North Dakota', 'ND'], %w[Ohio OH], %w[Oklahoma OK], %w[Oregon OR], %w[Pennsylvania PA], ['Rhode Island', 'RI'], ['South Carolina', 'SC'], ['South Dakota', 'SD'], %w[Tennessee TN], %w[Texas TX], %w[Utah UT], %w[Vermont VT], %w[Virginia VA], %w[Washington WA], %w[Wisconsin WI], ['West Virginia', 'WV'], %w[Wyoming WY]].freeze unless const_defined?('USASTATES')
35
+ unless const_defined?('USASTATES')
36
+ USASTATES = [
37
+ %w[Alabama AL], %w[Alaska AK], %w[Arizona AZ], %w[Arkansas AR], %w[California CA], %w[Colorado CO],
38
+ %w[Connecticut CT], %w[Delaware DE], ['District of Columbia', 'DC'], %w[Florida FL], %w[Georgia GA],
39
+ %w[Hawaii HI], %w[Idaho ID], %w[Illinois IL], %w[Indiana IN], %w[Iowa IA], %w[Kansas KS], %w[Kentucky KY],
40
+ %w[Louisiana LA], %w[Maine ME], %w[Maryland MD], %w[Massachusetts MA], %w[Michigan MI], %w[Minnesota MN],
41
+ %w[Mississippi MS], %w[Missouri MO], %w[Montana MT], %w[Nebraska NE], %w[Nevada NV],
42
+ ['New Hampshire', 'NH'], ['New Jersey', 'NJ'], ['New Mexico', 'NM'], ['New York', 'NY'],
43
+ ['North Carolina', 'NC'], ['North Dakota', 'ND'], %w[Ohio OH], %w[Oklahoma OK], %w[Oregon OR],
44
+ %w[Pennsylvania PA], ['Rhode Island', 'RI'], ['South Carolina', 'SC'], ['South Dakota', 'SD'],
45
+ %w[Tennessee TN], %w[Texas TX], %w[Utah UT], %w[Vermont VT], %w[Virginia VA], %w[Washington WA],
46
+ %w[Wisconsin WI], ['West Virginia', 'WV'], %w[Wyoming WY]
47
+ ].freeze
48
+ end
36
49
  end
37
50
 
38
51
  module InstanceTagMethods
39
52
  def to_usa_state_select_tag(priority_states, options, html_options)
40
53
  html_options = html_options.stringify_keys
41
54
  add_default_name_and_id(html_options)
42
- value = value(object)
43
- selected_value = options.key?(:selected) ? options[:selected] : value
55
+ selected_value =
56
+ if options.key?(:selected)
57
+ options[:selected]
58
+ else
59
+ method(:value).parameters.any? ? value(object) : value
60
+ end
44
61
  content_tag('select', add_options(usa_state_options_for_select(selected_value, priority_states), options, selected_value), html_options)
45
62
  end
46
63
  end
@@ -10,7 +10,13 @@ module ActiveScaffold::Config
10
10
 
11
11
  # start with the ActionLink defined globally
12
12
  @link = self.class.link.clone if self.class.respond_to?(:link) && self.class.link
13
+ setup_user_setting_key
13
14
  end
15
+
16
+ def setup_user_setting_key
17
+ @user_settings_key = :"#{model_id}_#{self.class.name.underscore}"
18
+ end
19
+
14
20
  attr_reader :core
15
21
 
16
22
  def self.inherited(subclass)
@@ -42,9 +48,7 @@ module ActiveScaffold::Config
42
48
  (core || self).model_id
43
49
  end
44
50
 
45
- def user_settings_key
46
- :"#{model_id}_#{self.class.name.underscore}"
47
- end
51
+ attr_reader :user_settings_key
48
52
 
49
53
  # the user property gets set to the instantiation of the local UserSettings class during the automatic instantiation of this class.
50
54
  def user
@@ -116,7 +120,7 @@ module ActiveScaffold::Config
116
120
 
117
121
  def []=(key, value)
118
122
  @storage[@action] ||= {}
119
- if value
123
+ if value.present?
120
124
  @storage[@action][key.to_s] = value
121
125
  else
122
126
  @storage[@action].delete key.to_s
@@ -129,11 +133,23 @@ module ActiveScaffold::Config
129
133
  end
130
134
 
131
135
  def method_missing(name, *args)
132
- @conf.respond_to?(name, true) ? @conf.send(name, *args) : super
136
+ proxy_to_conf?(name, true) ? @conf.send(name, *args) : super
133
137
  end
134
138
 
135
139
  def respond_to_missing?(name, include_all = false)
136
- @conf.respond_to?(name, include_all) || super
140
+ proxy_to_conf?(name, include_all) || super
141
+ end
142
+
143
+ def proxy_to_conf?(name, include_all)
144
+ name !~ /=$/ && @conf.respond_to?(name, include_all)
145
+ end
146
+
147
+ private
148
+
149
+ def proxy_columns(columns)
150
+ proxy = ::CowProxy.wrap(columns)
151
+ proxy.action = self
152
+ proxy
137
153
  end
138
154
  end
139
155
 
@@ -145,52 +161,60 @@ module ActiveScaffold::Config
145
161
 
146
162
  class_attribute :columns_collections
147
163
 
164
+ def self.columns_writer(name)
165
+ var = "@#{name}"
166
+ define_method "#{name}=" do |val|
167
+ if instance_variable_defined?(var)
168
+ instance_variable_get(var).set_values(*val)
169
+ instance_variable_get(var)
170
+ else
171
+ instance_variable_set(var, build_action_columns(val))
172
+ end
173
+ end
174
+ end
175
+
176
+ def self.columns_reader(name, options, &block)
177
+ var = "@#{name}"
178
+ define_method name do
179
+ unless instance_variable_defined?(var) # lazy evaluation
180
+ action, columns = options[:copy] if options[:copy]
181
+ if action && @core.actions.include?(action)
182
+ action_columns = @core.send(action).send(columns || :columns).clone
183
+ action_columns.action = self
184
+ instance_variable_set(var, action_columns)
185
+ else
186
+ send("#{name}=", @core.columns._inheritable)
187
+ end
188
+ instance_exec(&block) if block
189
+ end
190
+ instance_variable_get(var)
191
+ end
192
+ end
193
+
148
194
  def self.columns_accessor(*names, &block)
149
195
  options = names.extract_options!
150
196
  self.columns_collections = ((columns_collections || []) + names).uniq
151
197
  names.each do |name|
152
- var = "@#{name}"
153
- define_method "#{name}=" do |val|
154
- if instance_variable_defined?(var)
155
- instance_variable_get(var).set_values(*val)
156
- instance_variable_get(var)
157
- else
158
- instance_variable_set(var, build_action_columns(val))
159
- end
160
- end
198
+ columns_writer name
199
+ columns_reader name, options, &block unless method_defined? name
161
200
 
162
201
  if self::UserSettings == ActiveScaffold::Config::Base::UserSettings
163
202
  const_set 'UserSettings', Class.new(ActiveScaffold::Config::Base::UserSettings)
164
203
  end
165
204
 
205
+ var = "@#{name}"
166
206
  self::UserSettings.class_eval do
167
207
  define_method "#{name}=" do |val|
168
- instance_variable_set var, ::CowProxy.wrap(build_action_columns(val))
208
+ instance_variable_set var, proxy_columns(build_action_columns(val))
169
209
  end
170
210
  define_method name do
171
211
  instance_variable_get(var) ||
172
- instance_variable_set(var, ::CowProxy.wrap(@conf.send(name)))
212
+ instance_variable_set(var, proxy_columns(@conf.send(name)))
173
213
  end
174
214
  end
175
-
176
- return if method_defined? name
177
- define_method name do
178
- unless instance_variable_defined?(var) # lazy evaluation
179
- action, columns = options[:copy] if options[:copy]
180
- if action && @core.actions.include?(action)
181
- action_columns = @core.send(action).send(columns || :columns).clone
182
- action_columns.action = self
183
- instance_variable_set(var, action_columns)
184
- else
185
- send("#{name}=", @core.columns._inheritable)
186
- end
187
- instance_exec(&block) if block
188
- end
189
- instance_variable_get(var)
190
- end
191
215
  end
192
216
  end
193
217
 
194
- private_class_method :columns_accessor
218
+ private_class_method :columns_accessor, :columns_reader, :columns_writer
195
219
  end
196
220
  end
@@ -88,6 +88,10 @@ module ActiveScaffold::Config
88
88
  cattr_accessor :highlight_messages, instance_accessor: false
89
89
  @@highlight_messages = nil
90
90
 
91
+ # method names or procs to be called after all configure blocks
92
+ cattr_reader :after_config_callbacks, instance_accessor: false
93
+ @@after_config_callbacks = [:_configure_sti]
94
+
91
95
  def self.freeze
92
96
  super
93
97
  security.freeze
@@ -160,6 +164,7 @@ module ActiveScaffold::Config
160
164
  def initialize(model_id)
161
165
  # model_id is the only absolutely required configuration value. it is also not publicly accessible.
162
166
  @model_id = model_id
167
+ setup_user_setting_key
163
168
 
164
169
  # inherit the actions list directly from the global level
165
170
  @actions = self.class.actions.clone
@@ -196,9 +201,6 @@ module ActiveScaffold::Config
196
201
  # To be called before freezing
197
202
  def _cache_lazy_values
198
203
  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
204
  columns.select(&:sortable?).each(&:sort)
203
205
  columns.select(&:searchable?).each(&:search_sql)
204
206
  actions.each do |action_name|
@@ -209,6 +211,7 @@ module ActiveScaffold::Config
209
211
 
210
212
  # To be called after your finished configuration
211
213
  def _configure_sti
214
+ return if sti_children.nil?
212
215
  column = model.inheritance_column
213
216
  if sti_create_links
214
217
  columns[column].form_ui ||= :hidden
@@ -235,7 +238,7 @@ module ActiveScaffold::Config
235
238
  end
236
239
 
237
240
  def respond_to_missing?(name, include_all = false)
238
- self.class.config_class?(name) && @actions.include?(action_name.to_s.underscore.to_sym) || super
241
+ self.class.config_class?(name) && @actions.include?(name.to_sym) || super
239
242
  end
240
243
 
241
244
  def [](action_name)
@@ -243,12 +246,11 @@ module ActiveScaffold::Config
243
246
  return unless klass
244
247
 
245
248
  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
249
+ unless @actions.include? underscored_name
250
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 = [...])."
251
251
  end
252
+ @action_configs ||= {}
253
+ @action_configs[underscored_name] ||= klass.new(self)
252
254
  end
253
255
 
254
256
  def []=(action_name, action_config)
@@ -258,8 +260,7 @@ module ActiveScaffold::Config
258
260
  private :[]=
259
261
 
260
262
  def self.method_missing(name, *args)
261
- klass = config_class(name) if @@actions.include?(name.to_s.underscore)
262
- klass || super
263
+ config_class(name) || super
263
264
  end
264
265
 
265
266
  def self.config_class(name)
@@ -349,21 +350,39 @@ module ActiveScaffold::Config
349
350
  def action_links
350
351
  @action_links ||= CowProxy.wrap(@conf.action_links)
351
352
  end
353
+
354
+ def model
355
+ @conf.model # for performance, called many times, so we avoid method_missing
356
+ end
357
+
358
+ def actions
359
+ @conf.actions # for performance, called many times, so we avoid method_missing
360
+ end
352
361
  end
353
362
 
354
363
  class UserColumns
364
+ include Enumerable
365
+
355
366
  def initialize(columns)
356
367
  @global_columns = columns
357
368
  @columns = {}
358
369
  end
359
370
 
360
371
  def [](name)
372
+ return nil unless @global_columns[name]
361
373
  @columns[name.to_sym] ||= CowProxy.wrap @global_columns[name]
362
374
  end
363
375
 
364
- def method_missing(name, *args)
376
+ def each
377
+ return enum_for(:each) unless block_given?
378
+ @global_columns.each do |col|
379
+ yield self[col.name]
380
+ end
381
+ end
382
+
383
+ def method_missing(name, *args, &block)
365
384
  if @global_columns.respond_to?(name, true)
366
- @global_columns.send(name, *args)
385
+ @global_columns.send(name, *args, &block)
367
386
  else
368
387
  super
369
388
  end
@@ -12,7 +12,18 @@ module ActiveScaffold::Config
12
12
 
13
13
  # the ActionLink for this action
14
14
  cattr_accessor :link, instance_accessor: false
15
- @@link = ActiveScaffold::DataStructures::ActionLink.new('destroy', :label => :delete, :type => :member, :confirm => :are_you_sure_to_delete, :method => :delete, :crud_type => :delete, :position => false, :parameters => {:destroy_action => true}, :security_method => :delete_authorized?, :ignore_method => :delete_ignore?)
15
+ @@link = ActiveScaffold::DataStructures::ActionLink.new(
16
+ 'destroy',
17
+ :label => :delete,
18
+ :type => :member,
19
+ :method => :delete,
20
+ :crud_type => :delete,
21
+ :confirm => :are_you_sure_to_delete,
22
+ :position => false,
23
+ :parameters => {:destroy_action => true},
24
+ :security_method => :delete_authorized?,
25
+ :ignore_method => :delete_ignore?
26
+ )
16
27
 
17
28
  # whether we should refresh list after destroy or not
18
29
  cattr_accessor :refresh_list, instance_accessor: false
@@ -186,8 +186,8 @@ module ActiveScaffold::Config
186
186
  def search_partial
187
187
  if @always_show_search == true
188
188
  auto_search_partial
189
- else
190
- @always_show_search.to_s if @core.actions.include? @always_show_search
189
+ elsif @core.actions.include? @always_show_search
190
+ @always_show_search.to_s
191
191
  end
192
192
  end
193
193
 
@@ -219,11 +219,12 @@ module ActiveScaffold::Config
219
219
  # order clause will be used for ETag when calculate_etag is disabled, so query for records can be avoided
220
220
  attr_accessor :calculate_etag
221
221
 
222
- UserSettings.class_eval do # defined with columns_accessor
222
+ # don't inherit, defined with columns_accessor, class_eval would complain about block too long
223
+ class UserSettings
223
224
  user_attr :page_links_inner_window, :page_links_outer_window, :refresh_with_header, :empty_field_text,
224
225
  :association_join_text, :messages_above_header, :wrap_tag, :auto_select_columns, :calculate_etag,
225
226
  :no_entries_message, :filtered_message, :show_search_reset, :always_show_create, :always_show_search,
226
- :hide_nested_column
227
+ :hide_nested_column, :pagination, :auto_pagination
227
228
 
228
229
  def initialize(conf, storage, params)
229
230
  super(conf, storage, params, :list)
@@ -261,12 +262,12 @@ module ActiveScaffold::Config
261
262
  attr_reader :nested_default_sorting
262
263
 
263
264
  def nested_default_sorting=(options)
264
- @nested_default_sorting ||= @conf.sorting.dup
265
+ @nested_default_sorting ||= sorting_dup
265
266
  @nested_default_sorting.set_nested_sorting(options[:table_name], options[:default_sorting])
266
267
  end
267
268
 
268
269
  def default_sorting
269
- nested_default_sorting.nil? || @sorting.present? ? @conf.sorting.dup : nested_default_sorting
270
+ nested_default_sorting.nil? || @sorting.present? ? sorting_dup : nested_default_sorting
270
271
  end
271
272
 
272
273
  # TODO: programatically set sorting, for per-request configuration, priority @params, then @sort
@@ -286,7 +287,7 @@ module ActiveScaffold::Config
286
287
  self['sort'] = nil if @params['sort_direction'] == 'reset'
287
288
 
288
289
  if self['sort'] && @conf.core.columns[self['sort'][0]]
289
- sorting = @conf.sorting.dup
290
+ sorting = sorting_dup
290
291
  sorting.set(*self['sort'])
291
292
  @_sorting = sorting
292
293
  else
@@ -303,6 +304,15 @@ module ActiveScaffold::Config
303
304
  def count_includes
304
305
  @conf.count_includes
305
306
  end
307
+
308
+ protected
309
+
310
+ def sorting_dup
311
+ sorting = @conf.sorting.dup
312
+ # access to config instance columns instead of config class columns, in case columns are changed in this request
313
+ sorting.instance_variable_set :@columns, core.columns
314
+ sorting
315
+ end
306
316
  end
307
317
  end
308
318
  end