active_scaffold 3.6.0.pre → 3.6.0.rc1

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