active_scaffold 3.5.3 → 3.6.0.rc2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (184) hide show
  1. checksums.yaml +4 -4
  2. data/{CHANGELOG → CHANGELOG.rdoc} +73 -0
  3. data/README.md +17 -7
  4. data/app/assets/javascripts/active_scaffold.js.erb +0 -1
  5. data/app/assets/javascripts/jquery/active_scaffold.js +97 -6
  6. data/app/assets/stylesheets/active_scaffold_colors.scss +1 -1
  7. data/app/assets/stylesheets/active_scaffold_layout.css +52 -29
  8. data/app/views/active_scaffold_overrides/_base_form.html.erb +2 -2
  9. data/app/views/active_scaffold_overrides/_form.html.erb +1 -1
  10. data/app/views/active_scaffold_overrides/_form_association.html.erb +2 -1
  11. data/app/views/active_scaffold_overrides/_form_association_footer.html.erb +3 -2
  12. data/app/views/active_scaffold_overrides/_form_association_record.html.erb +9 -7
  13. data/app/views/active_scaffold_overrides/_horizontal_subform.html.erb +4 -4
  14. data/app/views/active_scaffold_overrides/_horizontal_subform_header.html.erb +2 -1
  15. data/app/views/active_scaffold_overrides/_list.html.erb +2 -1
  16. data/app/views/active_scaffold_overrides/_list_header.html.erb +5 -7
  17. data/app/views/active_scaffold_overrides/_list_messages.html.erb +1 -0
  18. data/app/views/active_scaffold_overrides/_list_record.html.erb +4 -5
  19. data/app/views/active_scaffold_overrides/_list_with_header.html.erb +1 -1
  20. data/app/views/active_scaffold_overrides/_messages.html.erb +1 -0
  21. data/app/views/active_scaffold_overrides/_refresh_list.js.erb +4 -0
  22. data/app/views/active_scaffold_overrides/_render_field.js.erb +2 -1
  23. data/app/views/active_scaffold_overrides/_show_association_horizontal.html.erb +2 -1
  24. data/app/views/active_scaffold_overrides/_show_columns.html.erb +2 -2
  25. data/app/views/active_scaffold_overrides/_show_horizontal_record.html.erb +4 -4
  26. data/app/views/active_scaffold_overrides/_update_calculations.js.erb +1 -1
  27. data/app/views/active_scaffold_overrides/_update_column.js.erb +2 -2
  28. data/app/views/active_scaffold_overrides/_vertical_subform.html.erb +2 -2
  29. data/app/views/active_scaffold_overrides/action_confirmation.html.erb +2 -2
  30. data/app/views/active_scaffold_overrides/delete.html.erb +2 -2
  31. data/app/views/active_scaffold_overrides/on_action_update.js.erb +16 -6
  32. data/app/views/active_scaffold_overrides/on_update.js.erb +1 -1
  33. data/app/views/active_scaffold_overrides/row.js.erb +1 -1
  34. data/app/views/active_scaffold_overrides/update_column.js.erb +2 -2
  35. data/config/locales/de.yml +2 -1
  36. data/config/locales/en.yml +1 -0
  37. data/config/locales/es.yml +1 -0
  38. data/config/locales/fr.yml +2 -1
  39. data/config/locales/hu.yml +1 -0
  40. data/config/locales/ja.yml +1 -0
  41. data/config/locales/ru.yml +1 -0
  42. data/lib/active_scaffold.rb +19 -16
  43. data/lib/active_scaffold/actions/common_search.rb +11 -8
  44. data/lib/active_scaffold/actions/core.rb +91 -70
  45. data/lib/active_scaffold/actions/create.rb +28 -28
  46. data/lib/active_scaffold/actions/delete.rb +3 -3
  47. data/lib/active_scaffold/actions/field_search.rb +53 -43
  48. data/lib/active_scaffold/actions/list.rb +111 -27
  49. data/lib/active_scaffold/actions/nested.rb +65 -48
  50. data/lib/active_scaffold/actions/search.rb +1 -1
  51. data/lib/active_scaffold/actions/show.rb +4 -4
  52. data/lib/active_scaffold/actions/subform.rb +23 -22
  53. data/lib/active_scaffold/actions/update.rb +96 -77
  54. data/lib/active_scaffold/active_record_permissions.rb +2 -11
  55. data/lib/active_scaffold/attribute_params.rb +102 -94
  56. data/lib/active_scaffold/bridges.rb +8 -8
  57. data/lib/active_scaffold/bridges/active_storage.rb +6 -0
  58. data/lib/active_scaffold/bridges/active_storage/active_storage_bridge.rb +34 -0
  59. data/lib/active_scaffold/bridges/active_storage/active_storage_helpers.rb +54 -0
  60. data/lib/active_scaffold/bridges/active_storage/form_ui.rb +22 -0
  61. data/lib/active_scaffold/bridges/active_storage/list_ui.rb +36 -0
  62. data/lib/active_scaffold/bridges/bitfields.rb +1 -0
  63. data/lib/active_scaffold/bridges/bitfields/bitfields_bridge.rb +12 -15
  64. data/lib/active_scaffold/bridges/calendar_date_select/as_cds_bridge.rb +1 -1
  65. data/lib/active_scaffold/bridges/cancan/cancan_bridge.rb +9 -12
  66. data/lib/active_scaffold/bridges/carrierwave/carrierwave_bridge.rb +1 -1
  67. data/lib/active_scaffold/bridges/carrierwave/list_ui.rb +2 -2
  68. data/lib/active_scaffold/bridges/chosen/helpers.rb +11 -9
  69. data/lib/active_scaffold/bridges/date_picker/ext.rb +0 -13
  70. data/lib/active_scaffold/bridges/date_picker/helper.rb +49 -44
  71. data/lib/active_scaffold/bridges/dragonfly/list_ui.rb +1 -1
  72. data/lib/active_scaffold/bridges/file_column/as_file_column_bridge.rb +1 -1
  73. data/lib/active_scaffold/bridges/file_column/file_column_helpers.rb +3 -3
  74. data/lib/active_scaffold/bridges/file_column/form_ui.rb +3 -3
  75. data/lib/active_scaffold/bridges/file_column/test/functional/file_column_keep_test.rb +10 -7
  76. data/lib/active_scaffold/bridges/paper_trail.rb +1 -1
  77. data/lib/active_scaffold/bridges/paper_trail/actions.rb +3 -1
  78. data/lib/active_scaffold/bridges/paperclip/list_ui.rb +1 -1
  79. data/lib/active_scaffold/bridges/paperclip/paperclip_bridge.rb +1 -1
  80. data/lib/active_scaffold/bridges/paperclip/paperclip_bridge_helpers.rb +2 -2
  81. data/lib/active_scaffold/bridges/record_select/helpers.rb +15 -17
  82. data/lib/active_scaffold/bridges/shared/date_bridge.rb +20 -19
  83. data/lib/active_scaffold/bridges/tiny_mce/helpers.rb +3 -1
  84. data/lib/active_scaffold/bridges/usa_state_select/usa_state_select_helper.rb +21 -4
  85. data/lib/active_scaffold/config/base.rb +133 -41
  86. data/lib/active_scaffold/config/core.rb +146 -18
  87. data/lib/active_scaffold/config/delete.rb +14 -1
  88. data/lib/active_scaffold/config/field_search.rb +7 -1
  89. data/lib/active_scaffold/config/form.rb +10 -1
  90. data/lib/active_scaffold/config/list.rb +39 -13
  91. data/lib/active_scaffold/config/mark.rb +4 -2
  92. data/lib/active_scaffold/config/nested.rb +16 -17
  93. data/lib/active_scaffold/config/search.rb +9 -0
  94. data/lib/active_scaffold/config/show.rb +4 -0
  95. data/lib/active_scaffold/config/update.rb +4 -0
  96. data/lib/active_scaffold/configurable.rb +14 -7
  97. data/lib/active_scaffold/constraints.rb +22 -20
  98. data/lib/active_scaffold/core.rb +67 -28
  99. data/lib/active_scaffold/data_structures/action_columns.rb +50 -59
  100. data/lib/active_scaffold/data_structures/action_link.rb +50 -20
  101. data/lib/active_scaffold/data_structures/action_links.rb +15 -13
  102. data/lib/active_scaffold/data_structures/association/abstract.rb +38 -15
  103. data/lib/active_scaffold/data_structures/association/active_mongoid.rb +2 -6
  104. data/lib/active_scaffold/data_structures/association/active_record.rb +6 -2
  105. data/lib/active_scaffold/data_structures/association/mongoid.rb +0 -3
  106. data/lib/active_scaffold/data_structures/column.rb +75 -66
  107. data/lib/active_scaffold/data_structures/columns.rb +3 -2
  108. data/lib/active_scaffold/data_structures/nested_info.rb +33 -19
  109. data/lib/active_scaffold/data_structures/set.rb +8 -0
  110. data/lib/active_scaffold/data_structures/sorting.rb +10 -2
  111. data/lib/active_scaffold/delayed_setup.rb +16 -5
  112. data/lib/active_scaffold/extensions/action_controller_rendering.rb +3 -2
  113. data/lib/active_scaffold/extensions/action_view_rendering.rb +34 -14
  114. data/lib/active_scaffold/extensions/cow_proxy.rb +95 -0
  115. data/lib/active_scaffold/extensions/ice_nine.rb +36 -0
  116. data/lib/active_scaffold/extensions/left_outer_joins.rb +8 -33
  117. data/lib/active_scaffold/extensions/localize.rb +3 -1
  118. data/lib/active_scaffold/extensions/routing_mapper.rb +6 -45
  119. data/lib/active_scaffold/extensions/to_label.rb +3 -2
  120. data/lib/active_scaffold/extensions/unsaved_record.rb +2 -4
  121. data/lib/active_scaffold/finder.rb +110 -77
  122. data/lib/active_scaffold/helpers/action_link_helpers.rb +62 -36
  123. data/lib/active_scaffold/helpers/association_helpers.rb +21 -19
  124. data/lib/active_scaffold/helpers/controller_helpers.rb +34 -10
  125. data/lib/active_scaffold/helpers/form_column_helpers.rb +196 -124
  126. data/lib/active_scaffold/helpers/human_condition_helpers.rb +1 -1
  127. data/lib/active_scaffold/helpers/id_helpers.rb +6 -2
  128. data/lib/active_scaffold/helpers/list_column_helpers.rb +86 -57
  129. data/lib/active_scaffold/helpers/pagination_helpers.rb +2 -2
  130. data/lib/active_scaffold/helpers/search_column_helpers.rb +29 -34
  131. data/lib/active_scaffold/helpers/show_column_helpers.rb +3 -5
  132. data/lib/active_scaffold/helpers/view_helpers.rb +38 -35
  133. data/lib/active_scaffold/marked_model.rb +2 -2
  134. data/lib/active_scaffold/orm_checks.rb +3 -7
  135. data/lib/active_scaffold/paginator.rb +7 -7
  136. data/lib/active_scaffold/registry.rb +33 -0
  137. data/lib/active_scaffold/responds_to_parent.rb +8 -11
  138. data/lib/active_scaffold/tableless.rb +67 -65
  139. data/lib/active_scaffold/version.rb +2 -2
  140. data/lib/generators/active_scaffold/controller_generator.rb +2 -2
  141. data/lib/generators/active_scaffold/install_generator.rb +1 -1
  142. data/lib/generators/active_scaffold/resource_generator.rb +2 -2
  143. data/shoulda_macros/macros.rb +3 -1
  144. data/test/bridges/date_picker_test.rb +1 -2
  145. data/test/bridges/paperclip_test.rb +6 -6
  146. data/test/class_with_finder.rb +2 -2
  147. data/test/company.rb +4 -4
  148. data/test/config/create_test.rb +4 -2
  149. data/test/config/nested_test.rb +1 -1
  150. data/test/config/show_test.rb +1 -1
  151. data/test/config/update_test.rb +7 -6
  152. data/test/data_structures/action_columns_test.rb +2 -2
  153. data/test/data_structures/action_links_test.rb +1 -1
  154. data/test/data_structures/column_test.rb +3 -6
  155. data/test/data_structures/columns_test.rb +2 -2
  156. data/test/data_structures/sorting_test.rb +7 -0
  157. data/test/extensions/active_record_test.rb +4 -4
  158. data/test/extensions/routing_mapper_test.rb +2 -2
  159. data/test/helpers/list_column_helpers_test.rb +3 -1
  160. data/test/misc/active_record_permissions_test.rb +3 -11
  161. data/test/misc/attribute_params_test.rb +12 -8
  162. data/test/misc/calculation_test.rb +1 -1
  163. data/test/misc/configurable_test.rb +10 -10
  164. data/test/misc/constraints_test.rb +2 -2
  165. data/test/misc/convert_numbers_format_test.rb +7 -3
  166. data/test/misc/lang_test.rb +1 -1
  167. data/test/misc/parse_datetime_test.rb +3 -4
  168. data/test/misc/tableless_test.rb +6 -0
  169. data/test/mock_app/Rakefile +1 -1
  170. data/test/mock_app/app/assets/config/manifest.js +0 -0
  171. data/test/mock_app/app/controllers/cars_controller.rb +1 -0
  172. data/test/mock_app/app/controllers/people_controller.rb +3 -1
  173. data/test/mock_app/config/application.rb +2 -1
  174. data/test/mock_app/config/boot.rb +1 -1
  175. data/test/mock_app/config/environment.rb +2 -2
  176. data/test/mock_app/config/routes.rb +4 -1
  177. data/test/mock_app/db/schema.rb +2 -0
  178. data/test/performance/list_cars_performance_test.rb +34 -0
  179. data/test/performance/list_people_performance_test.rb +31 -0
  180. data/test/performance_test_help.rb +3 -0
  181. data/test/test_helper.rb +10 -2
  182. metadata +55 -20
  183. data/app/assets/javascripts/prototype/rico_corner.js +0 -370
  184. data/lib/active_scaffold/bridges/file_column/test/test_helper.rb +0 -7
@@ -108,6 +108,7 @@ ja:
108
108
  refresh: Refresh
109
109
  remove: 削除
110
110
  remove_file: ファイルを削除または置換
111
+ remove_files: ファイルを削除または追加する
111
112
  replace_existing: Replace existing
112
113
  replace_with_new: 新しいもので置換
113
114
  reset: リセット
@@ -116,6 +116,7 @@ ru:
116
116
  refresh: Обновить
117
117
  remove: Удалить
118
118
  remove_file: Удалить или заменить файл
119
+ remove_files: Удалить или Добавить файлы
119
120
  replace_existing: Заменить существующим
120
121
  replace_with_new: Заменить новым
121
122
  reset: Сброс
@@ -9,6 +9,7 @@ module ActiveScaffold
9
9
  autoload :Finder, 'active_scaffold/finder'
10
10
  autoload :MarkedModel, 'active_scaffold/marked_model'
11
11
  autoload :OrmChecks, 'active_scaffold/orm_checks'
12
+ autoload :Registry, 'active_scaffold/registry'
12
13
  autoload :RespondsToParent, 'active_scaffold/responds_to_parent'
13
14
  autoload :Tableless, 'active_scaffold/tableless'
14
15
  autoload :Version, 'active_scaffold/version'
@@ -40,20 +41,22 @@ module ActiveScaffold
40
41
 
41
42
  class ControllerNotFound < RuntimeError; end
42
43
  class MalformedConstraint < RuntimeError; end
43
- class RecordNotAllowed < SecurityError; end
44
- class ActionNotAllowed < SecurityError; end
44
+ class RecordNotAllowed < RuntimeError; end
45
+ class ActionNotAllowed < RuntimeError; end
45
46
  class ReverseAssociationRequired < RuntimeError; end
46
47
 
47
- mattr_accessor :delayed_setup
48
- mattr_accessor :stylesheets
48
+ mattr_accessor :delayed_setup, instance_writer: false
49
+ mattr_accessor :stylesheets, instance_writer: false
49
50
  self.stylesheets = []
50
- mattr_accessor :javascripts
51
+ mattr_accessor :javascripts, instance_writer: false
51
52
  self.javascripts = []
52
53
 
53
- def self.js_framework=(framework)
54
- @@js_framework = framework
54
+ mattr_reader :threadsafe
55
+ def self.threadsafe!
56
+ @@threadsafe = true
55
57
  end
56
58
 
59
+ mattr_writer :js_framework, instance_writer: false
57
60
  def self.js_framework
58
61
  @@js_framework ||=
59
62
  if defined? Jquery
@@ -63,10 +66,7 @@ module ActiveScaffold
63
66
  end
64
67
  end
65
68
 
66
- def self.js_config=(config)
67
- @@js_config = config
68
- end
69
-
69
+ mattr_writer :js_config, instance_writer: false
70
70
  def self.js_config
71
71
  @@js_config ||= {:scroll_on_close => :checkInViewport}
72
72
  end
@@ -75,10 +75,7 @@ module ActiveScaffold
75
75
  # name of bridge subdir should be used to exclude it
76
76
  # eg
77
77
  # ActiveScaffold.exclude_bridges = [:cancan, :ancestry]
78
- def self.exclude_bridges=(bridges)
79
- @@exclude_bridges = bridges
80
- end
81
-
78
+ mattr_writer :exclude_bridges, instance_writer: false
82
79
  def self.exclude_bridges
83
80
  @@exclude_bridges ||= []
84
81
  end
@@ -87,12 +84,18 @@ module ActiveScaffold
87
84
  File.dirname(__FILE__) + '/..'
88
85
  end
89
86
 
90
- def self.set_defaults(&block)
87
+ def self.set_defaults(&block) # rubocop:disable Naming/AccessorMethodName
88
+ ActiveSupport::Deprecation.warn 'use ActiveScaffold.defaults'
89
+ defaults(&block)
90
+ end
91
+
92
+ def self.defaults(&block)
91
93
  ActiveScaffold::Config::Core.configure(&block)
92
94
  end
93
95
  end
94
96
  require 'active_scaffold/engine'
95
97
  require 'ice_nine'
96
98
  require 'ice_nine/core_ext/object'
99
+ require 'request_store'
97
100
  # TODO: clean up extensions. some could be organized for autoloading, and others could be removed entirely.
98
101
  Dir["#{File.dirname __FILE__}/active_scaffold/extensions/*.rb"].each { |file| require file }
@@ -1,13 +1,12 @@
1
1
  module ActiveScaffold::Actions
2
2
  module CommonSearch
3
3
  def self.included(base)
4
- unless base < InstanceMethods
5
- base.send :include, InstanceMethods
6
- base.before_action :search_authorized_filter, :only => :show_search
7
- base.before_action :store_search_params_into_session, :only => [:index]
8
- base.before_action :do_search, :only => [:index]
9
- base.helper_method :search_params
10
- end
4
+ return if base < InstanceMethods
5
+ base.send :include, InstanceMethods
6
+ base.before_action :search_authorized_filter, :only => :show_search
7
+ base.before_action :store_search_params_into_session, :only => [:index]
8
+ base.before_action :do_search, :only => [:index]
9
+ base.helper_method :search_params
11
10
  end
12
11
 
13
12
  module InstanceMethods
@@ -34,7 +33,11 @@ module ActiveScaffold::Actions
34
33
 
35
34
  def store_search_params_into_session
36
35
  if active_scaffold_config.store_user_settings
37
- active_scaffold_session_storage['search'] = permitted_search_params if params[:search]
36
+ if params[:search].present?
37
+ active_scaffold_session_storage['search'] = permitted_search_params
38
+ elsif params.key? :search
39
+ active_scaffold_session_storage.delete 'search'
40
+ end
38
41
  else
39
42
  @search_params = permitted_search_params
40
43
  end
@@ -3,13 +3,13 @@ module ActiveScaffold::Actions
3
3
  def self.included(base)
4
4
  base.class_eval do
5
5
  before_action :set_vary_accept_header
6
- before_action :handle_user_settings
7
6
  before_action :check_input_device
8
7
  before_action :register_constraints_with_action_columns, :unless => :nested?
9
8
  after_action :clear_flashes
10
- after_action :clear_storage
9
+ around_action :clear_storage
11
10
  rescue_from ActiveScaffold::RecordNotAllowed, ActiveScaffold::ActionNotAllowed, :with => :deny_access
12
11
  end
12
+ base.helper_method :active_scaffold_config
13
13
  base.helper_method :successful?
14
14
  base.helper_method :nested?
15
15
  base.helper_method :grouped_search?
@@ -72,7 +72,8 @@ module ActiveScaffold::Actions
72
72
  else
73
73
  updated_record_with_column(@column, params.delete(:value), @scope)
74
74
  end
75
- set_parent(@record) if main_form_controller && @scope
75
+ # if @scope has more than 2 ] then it's subform inside subform, and assign parent would fail (found associotion may be through association)
76
+ setup_parent(@record) if main_form_controller && @scope && @scope.scan(']').size == 2
76
77
  after_render_field(@record, @column)
77
78
  end
78
79
 
@@ -104,16 +105,16 @@ module ActiveScaffold::Actions
104
105
  end
105
106
 
106
107
  def subform_child_association
107
- params[:child_association].presence || (@scope.split(']').first.sub(/^\[/, '').presence if @scope)
108
+ params[:child_association].presence || @scope&.split(']')&.first&.sub(/^\[/, '').presence
108
109
  end
109
110
 
110
111
  def parent_controller_name
111
112
  "#{params[:parent_controller].camelize}Controller"
112
113
  end
113
114
 
114
- def set_parent(record)
115
+ def setup_parent(record)
115
116
  cfg = main_form_controller.active_scaffold_config
116
- association = cfg.columns[subform_child_association].try(:association).try(:reverse_association)
117
+ association = cfg.columns[subform_child_association]&.association&.reverse_association
117
118
  return if association.nil?
118
119
 
119
120
  parent_model = cfg.model
@@ -129,8 +130,8 @@ module ActiveScaffold::Actions
129
130
  end
130
131
 
131
132
  if params[:nested] # form in nested scaffold, set nested parent_record to parent
132
- nested = ActiveScaffold::DataStructures::NestedInfo.get(parent.class, params.delete(:nested))
133
- if nested.child_association
133
+ nested = ActiveScaffold::DataStructures::NestedInfo.get(parent.class, params[:nested])
134
+ if nested&.child_association && !nested.child_association.polymorphic?
134
135
  apply_constraints_to_record(parent, constraints: {nested.child_association.name => nested.parent_id})
135
136
  end
136
137
  end
@@ -179,14 +180,12 @@ module ActiveScaffold::Actions
179
180
  # ex: accepts? :html, :xml
180
181
  def accepts?(*types)
181
182
  request.accepts.compact.each do |priority|
182
- if priority == Mime::ALL
183
- # Because IE always sends */* in the accepts header and we assume
184
- # that if you really wanted XML or something else you would say so
185
- # explicitly, we will assume */* to only ask for :html
186
- return types.include?(:html)
187
- elsif types.include?(priority.to_sym)
188
- return true
189
- end
183
+ # Because IE always sends */* in the accepts header and we assume
184
+ # that if you really wanted XML or something else you would say so
185
+ # explicitly, we will assume */* to only ask for :html
186
+ return types.include?(:html) if priority == Mime::ALL
187
+
188
+ return true if types.include?(priority.to_sym)
190
189
  end
191
190
  false
192
191
  end
@@ -204,6 +203,18 @@ module ActiveScaffold::Actions
204
203
  @response_object ||= successful? ? (@record || @records) : @record.errors
205
204
  end
206
205
 
206
+ def response_to_api(format, columns_names, options = {})
207
+ render(
208
+ options.reverse_merge(
209
+ format => response_object,
210
+ :only => columns_names + [active_scaffold_config.model.primary_key],
211
+ :include => association_columns(columns_names),
212
+ :methods => virtual_columns(columns_names),
213
+ :status => response_status
214
+ )
215
+ )
216
+ end
217
+
207
218
  # Success is the existence of one or more model objects. Most actions
208
219
  # circumvent this method by setting @success directly.
209
220
  def successful?
@@ -234,24 +245,32 @@ module ActiveScaffold::Actions
234
245
  # Builds search conditions by search params for column names. This allows urls like "contacts/list?company_id=5".
235
246
  def conditions_from_params
236
247
  @conditions_from_params ||= begin
237
- conditions = {}
248
+ conditions = [{}]
238
249
  params.except(:controller, :action, :page, :sort, :sort_direction, :format, :id).each do |key, value|
239
- column = active_scaffold_config._columns_hash[key.to_s]
250
+ distinct = true if key =~ /!$/
251
+ column = active_scaffold_config._columns_hash[key.to_s[0..(distinct ? -2 : -1)]]
240
252
  next unless column
241
- key = key.to_sym
253
+ key = column.name.to_sym
242
254
  not_string = %i[string text].exclude?(column.type)
243
255
  next if active_scaffold_constraints[key]
244
256
  next if nested? && nested.param_name == key
245
257
 
246
- range = %i[date datetime].include?(column.type) && value.is_a?(String) && value.scan('..').size == 1
258
+ range = %i[date datetime integer decimal float bigint].include?(column.type) && value.is_a?(String) && value.scan('..').size == 1
247
259
  value = value.split('..') if range
248
- conditions[key] =
260
+ value =
249
261
  if value.is_a?(Array)
250
262
  value.map { |v| v == '' && not_string ? nil : ActiveScaffold::Core.column_type_cast(v, column) }
263
+ elsif value == '' && (not_string || column.null)
264
+ ActiveScaffold::Core.column_type_cast(column.default, column)
251
265
  else
252
- value == '' && not_string ? nil : ActiveScaffold::Core.column_type_cast(value, column)
266
+ ActiveScaffold::Core.column_type_cast(value, column)
253
267
  end
254
- conditions[key] = Range.new(*conditions[key]) if range
268
+ value = Range.new(*value) if range
269
+ if distinct
270
+ conditions << active_scaffold_config.model.arel_table[key].not_eq(value)
271
+ else
272
+ conditions[0][key] = value
273
+ end
255
274
  end
256
275
  conditions
257
276
  end
@@ -259,39 +278,38 @@ module ActiveScaffold::Actions
259
278
 
260
279
  def new_model
261
280
  relation = beginning_of_chain
262
- config = active_scaffold_config_for(relation.klass) if nested? && nested.plural_association?
263
- if config && config._columns_hash[column = relation.klass.inheritance_column]
264
- model_name = params.delete(column) # in new action inheritance_column must be in params
265
- model_name ||= params[:record].delete(column) if params[:record].present? # in create action must be inside record key
266
- model_name = model_name.camelize if model_name
267
- model_name ||= active_scaffold_config.model.name
268
- build_options = {column.to_sym => model_name} if model_name
281
+ if nested? && nested.plural_association? && nested.match_model?(active_scaffold_config.model)
282
+ build_options = sti_nested_build_options(relation.klass)
269
283
  end
270
284
  relation.respond_to?(:build) ? relation.build(build_options || {}) : relation.new
271
285
  end
272
286
 
287
+ def sti_nested_build_options(klass)
288
+ config = active_scaffold_config_for(klass)
289
+ return unless config
290
+ column = klass.inheritance_column
291
+ return unless column && config._columns_hash[column]
292
+
293
+ model_name = params.delete(column) # in new action inheritance_column must be in params
294
+ model_name ||= params[:record]&.delete(column) # in create action must be inside record key
295
+ model_name = model_name.camelize if model_name
296
+ model_name ||= active_scaffold_config.model.name
297
+ {column.to_sym => model_name} if model_name
298
+ end
299
+
273
300
  def get_row(crud_type_or_security_options = :read)
274
301
  klass = beginning_of_chain
275
302
  klass = klass.preload(active_scaffold_preload) unless active_scaffold_config.mongoid?
276
303
  @record = find_if_allowed(params[:id], crud_type_or_security_options, klass)
277
304
  end
278
305
 
279
- def active_scaffold_session_storage_key(id = nil)
280
- id ||= params[:eid] || "#{params[:controller]}#{"_#{nested_parent_id}" if nested?}"
281
- "as:#{id}"
282
- end
283
-
284
- def active_scaffold_session_storage(id = nil)
285
- session_index = active_scaffold_session_storage_key(id)
286
- session[session_index] ||= {}
287
- session[session_index]
288
- end
289
-
290
306
  def active_scaffold_embedded_params
291
307
  params[:embedded] || {}
292
308
  end
293
309
 
294
310
  def clear_storage
311
+ yield if block_given?
312
+ ensure
295
313
  session_index = active_scaffold_session_storage_key
296
314
  session.delete(session_index) if session[session_index].blank?
297
315
  end
@@ -300,25 +318,14 @@ module ActiveScaffold::Actions
300
318
  response.headers['Vary'] = 'Accept'
301
319
  end
302
320
 
303
- # at some point we need to pass the session and params into config. we'll just take care of that before any particular action occurs by passing those hashes off to the UserSettings class of each action.
304
- def handle_user_settings
305
- storage = active_scaffold_config.store_user_settings ? active_scaffold_session_storage : {}
306
- active_scaffold_config.actions.each do |action_name|
307
- conf_instance = active_scaffold_config.send(action_name) rescue next
308
- next if conf_instance.class::UserSettings == ActiveScaffold::Config::Base::UserSettings # if it hasn't been extended, skip it
309
- conf_instance.user = conf_instance.class::UserSettings.new(conf_instance, storage, params)
310
- end
311
- end
312
-
313
321
  def check_input_device
314
- if session[:input_device_type].nil?
315
- if request.env['HTTP_USER_AGENT'] && request.env['HTTP_USER_AGENT'][/(iPhone|iPod|iPad)/i]
316
- session[:input_device_type] = 'TOUCH'
317
- session[:hover_supported] = false
318
- else
319
- session[:input_device_type] = 'MOUSE'
320
- session[:hover_supported] = true
321
- end
322
+ return unless session[:input_device_type].nil?
323
+ if request.env['HTTP_USER_AGENT'] =~ /(iPhone|iPod|iPad)/i
324
+ session[:input_device_type] = 'TOUCH'
325
+ session[:hover_supported] = false
326
+ else
327
+ session[:input_device_type] = 'MOUSE'
328
+ session[:hover_supported] = true
322
329
  end
323
330
  end
324
331
 
@@ -340,7 +347,7 @@ module ActiveScaffold::Actions
340
347
 
341
348
  def params_hash(value)
342
349
  if controller_params?(value)
343
- Rails.version < '4.2' ? value.clone.permit! : value.to_unsafe_h.with_indifferent_access
350
+ value.to_unsafe_h.with_indifferent_access
344
351
  else
345
352
  value
346
353
  end
@@ -361,7 +368,7 @@ module ActiveScaffold::Actions
361
368
  else
362
369
  @action_link = active_scaffold_config.action_links[action_name]
363
370
  if params[:id]
364
- crud_type_or_security_options ||= {:crud_type => (request.post? || request.put?) ? :update : :delete, :action => action_name}
371
+ crud_type_or_security_options ||= {:crud_type => request.post? || request.put? ? :update : :delete, :action => action_name}
365
372
  get_row(crud_type_or_security_options)
366
373
  if @record.nil?
367
374
  self.successful = false
@@ -381,20 +388,24 @@ module ActiveScaffold::Actions
381
388
  render :action => 'action_confirmation', :locals => {:record => @record, :link => link}
382
389
  end
383
390
 
391
+ def action_update_respond_on_iframe
392
+ responds_to_parent { action_update_respond_to_js }
393
+ end
394
+
384
395
  def action_update_respond_to_html
385
396
  redirect_to :action => 'index'
386
397
  end
387
398
 
388
399
  def action_update_respond_to_js
389
- render(:action => 'on_action_update')
400
+ render :action => 'on_action_update', :formats => [:js], :layout => false
390
401
  end
391
402
 
392
403
  def action_update_respond_to_xml
393
- render :xml => successful? ? '' : response_object, :only => list_columns_names + [active_scaffold_config.model.primary_key], :include => association_columns(list_columns_names), :methods => virtual_columns(list_columns_names), :status => response_status
404
+ response_to_api(:xml, list_columns_names)
394
405
  end
395
406
 
396
407
  def action_update_respond_to_json
397
- render :json => successful? ? '' : response_object, :only => list_columns_names + [active_scaffold_config.model.primary_key], :include => association_columns(list_columns_names), :methods => virtual_columns(list_columns_names), :status => response_status
408
+ response_to_api(:json, list_columns_names)
398
409
  end
399
410
 
400
411
  def objects_for_etag
@@ -420,11 +431,13 @@ module ActiveScaffold::Actions
420
431
  end
421
432
 
422
433
  def virtual_columns(columns)
423
- columns.reject { |col| active_scaffold_config.model.columns_hash[col.to_s] || active_scaffold_config.columns[col].try(:association) }
434
+ columns.reject do |col|
435
+ active_scaffold_config._columns_hash[col.to_s] || active_scaffold_config.columns[col]&.association
436
+ end
424
437
  end
425
438
 
426
439
  def association_columns(columns)
427
- columns.select { |col| active_scaffold_config.columns[col].try(:association) }
440
+ columns.select { |col| active_scaffold_config.columns[col]&.association }
428
441
  end
429
442
 
430
443
  private
@@ -434,14 +447,22 @@ module ActiveScaffold::Actions
434
447
  respond_to do |type|
435
448
  action_formats.each do |format|
436
449
  type.send(format) do
437
- if respond_to?(method_name = "#{action}_respond_to_#{format}", true)
438
- send(method_name)
439
- end
450
+ method_name = respond_method_for(action, format)
451
+ send(method_name) if method_name
440
452
  end
441
453
  end
442
454
  end
443
455
  end
444
456
 
457
+ def respond_method_for(action, format)
458
+ if format == :html && params[:iframe] == 'true'
459
+ method_name = "#{action}_respond_on_iframe"
460
+ return method_name if respond_to?(method_name, true)
461
+ end
462
+ method_name = "#{action}_respond_to_#{format}"
463
+ method_name if respond_to?(method_name, true)
464
+ end
465
+
445
466
  def action_formats
446
467
  @action_formats ||=
447
468
  if respond_to? "#{action_name}_formats", true
@@ -457,7 +478,7 @@ module ActiveScaffold::Actions
457
478
  klass = klass.superclass
458
479
  controller = self.class.active_scaffold_controller_for(klass)
459
480
  cfg = controller.active_scaffold_config if controller.uses_active_scaffold?
460
- next unless cfg && cfg.add_sti_create_links?
481
+ next unless cfg&.add_sti_create_links?
461
482
  return controller if cfg.sti_children.map(&:to_s).include? self.class.active_scaffold_config.model.name.underscore
462
483
  end
463
484
  rescue ActiveScaffold::ControllerNotFound => ex
@@ -32,51 +32,51 @@ module ActiveScaffold::Actions
32
32
  render(:partial => 'create_form')
33
33
  end
34
34
 
35
+ def create_respond_on_iframe
36
+ do_refresh_list if successful? && active_scaffold_config.create.refresh_list && !render_parent?
37
+ responds_to_parent do
38
+ render :action => 'on_create', :formats => [:js], :layout => false
39
+ end
40
+ end
41
+
35
42
  def create_respond_to_html
36
- if params[:iframe] == 'true' # was this an iframe post ?
37
- do_refresh_list if successful? && active_scaffold_config.create.refresh_list && !render_parent?
38
- responds_to_parent do
39
- render :action => 'on_create', :formats => [:js], :layout => false
40
- end
41
- else
42
- if successful?
43
- flash[:info] = as_(:created_model, :model => ERB::Util.h(@record.to_label))
44
- if (action = active_scaffold_config.create.action_after_create)
45
- redirect_to params_for(:action => action, :id => @record.to_param)
46
- elsif params[:dont_close]
47
- redirect_to params_for(:action => 'new')
48
- else
49
- return_to_main
50
- end
43
+ if successful?
44
+ flash[:info] = as_(:created_model, :model => ERB::Util.h(@record.to_label))
45
+ if (action = active_scaffold_config.create.action_after_create)
46
+ redirect_to params_for(:action => action, :id => @record.to_param)
47
+ elsif params[:dont_close]
48
+ redirect_to params_for(:action => 'new')
51
49
  else
52
- if active_scaffold_config.actions.include?(:list) && active_scaffold_config.list.always_show_create
53
- list
54
- else
55
- render(:action => 'create')
56
- end
50
+ return_to_main
57
51
  end
52
+ elsif active_scaffold_config.actions.include?(:list) && active_scaffold_config.list.always_show_create
53
+ list
54
+ else
55
+ render(:action => 'create')
58
56
  end
59
57
  end
60
58
 
61
59
  def create_respond_to_js
62
- do_refresh_list if successful? && active_scaffold_config.create.refresh_list && !render_parent?
63
- if successful? && params[:dont_close] && !render_parent?
64
- @saved_record = @record
65
- do_new
60
+ if successful? && !render_parent?
61
+ do_refresh_list if active_scaffold_config.create.refresh_list
62
+ if params[:dont_close]
63
+ @saved_record = @record
64
+ do_new
65
+ end
66
66
  end
67
67
  render :action => 'on_create'
68
68
  end
69
69
 
70
70
  def create_respond_to_xml
71
- render :xml => response_object, :only => create_columns_names + [active_scaffold_config.model.primary_key], :include => association_columns(create_columns_names), :methods => virtual_columns(create_columns_names), :status => response_status, :location => response_location
71
+ response_to_api(:xml, create_columns_names, location: response_location)
72
72
  end
73
73
 
74
74
  def create_respond_to_json
75
- render :json => response_object, :only => create_columns_names + [active_scaffold_config.model.primary_key], :include => association_columns(create_columns_names), :methods => virtual_columns(create_columns_names), :status => response_status, :location => response_location
75
+ response_to_api(:json, create_columns_names, location: response_location)
76
76
  end
77
77
 
78
78
  def create_columns_names
79
- active_scaffold_config.create.columns.names
79
+ active_scaffold_config.create.columns.visible_columns_names
80
80
  end
81
81
 
82
82
  # A simple method to find and prepare an example new record for the form
@@ -136,7 +136,7 @@ module ActiveScaffold::Actions
136
136
  private
137
137
 
138
138
  def create_authorized_filter
139
- link = active_scaffold_config.create.link || active_scaffold_config.create.class.link
139
+ link = active_scaffold_config.create.link || self.class.active_scaffold_config.create.class.link
140
140
  raise ActiveScaffold::ActionNotAllowed unless send(link.security_method)
141
141
  end
142
142