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.
- checksums.yaml +4 -4
- data/{CHANGELOG → CHANGELOG.rdoc} +39 -0
- data/app/assets/javascripts/active_scaffold.js.erb +0 -1
- data/app/assets/javascripts/jquery/active_scaffold.js +35 -4
- data/app/assets/stylesheets/active_scaffold_colors.scss +1 -1
- data/app/assets/stylesheets/active_scaffold_layout.css +52 -29
- data/app/views/active_scaffold_overrides/_list_header.html.erb +5 -7
- data/app/views/active_scaffold_overrides/_list_record.html.erb +4 -5
- data/app/views/active_scaffold_overrides/_list_with_header.html.erb +1 -1
- data/app/views/active_scaffold_overrides/_refresh_list.js.erb +4 -0
- data/config/locales/de.yml +2 -1
- data/config/locales/en.yml +1 -0
- data/config/locales/es.yml +1 -0
- data/config/locales/fr.yml +2 -1
- data/config/locales/hu.yml +1 -0
- data/config/locales/ja.yml +1 -0
- data/config/locales/ru.yml +1 -0
- data/lib/active_scaffold.rb +8 -3
- data/lib/active_scaffold/actions/common_search.rb +11 -8
- data/lib/active_scaffold/actions/core.rb +79 -51
- data/lib/active_scaffold/actions/create.rb +27 -27
- data/lib/active_scaffold/actions/delete.rb +1 -1
- data/lib/active_scaffold/actions/field_search.rb +52 -42
- data/lib/active_scaffold/actions/list.rb +106 -23
- data/lib/active_scaffold/actions/nested.rb +59 -42
- data/lib/active_scaffold/actions/show.rb +3 -3
- data/lib/active_scaffold/actions/subform.rb +9 -16
- data/lib/active_scaffold/actions/update.rb +95 -77
- data/lib/active_scaffold/attribute_params.rb +93 -68
- data/lib/active_scaffold/bridges/active_storage.rb +6 -0
- data/lib/active_scaffold/bridges/active_storage/active_storage_bridge.rb +33 -0
- data/lib/active_scaffold/bridges/active_storage/active_storage_helpers.rb +54 -0
- data/lib/active_scaffold/bridges/active_storage/form_ui.rb +22 -0
- data/lib/active_scaffold/bridges/active_storage/list_ui.rb +36 -0
- data/lib/active_scaffold/bridges/bitfields.rb +1 -0
- data/lib/active_scaffold/bridges/bitfields/bitfields_bridge.rb +12 -15
- data/lib/active_scaffold/bridges/cancan/cancan_bridge.rb +6 -0
- data/lib/active_scaffold/bridges/carrierwave/list_ui.rb +2 -2
- data/lib/active_scaffold/bridges/date_picker/helper.rb +46 -41
- data/lib/active_scaffold/bridges/dragonfly/list_ui.rb +1 -1
- data/lib/active_scaffold/bridges/file_column/file_column_helpers.rb +2 -2
- data/lib/active_scaffold/bridges/file_column/form_ui.rb +3 -3
- data/lib/active_scaffold/bridges/file_column/test/functional/file_column_keep_test.rb +3 -1
- data/lib/active_scaffold/bridges/paperclip/paperclip_bridge_helpers.rb +2 -2
- data/lib/active_scaffold/bridges/record_select/helpers.rb +3 -7
- data/lib/active_scaffold/bridges/shared/date_bridge.rb +19 -18
- data/lib/active_scaffold/bridges/tiny_mce/helpers.rb +3 -1
- data/lib/active_scaffold/bridges/usa_state_select/usa_state_select_helper.rb +20 -3
- data/lib/active_scaffold/config/base.rb +58 -34
- data/lib/active_scaffold/config/core.rb +31 -12
- data/lib/active_scaffold/config/delete.rb +12 -1
- data/lib/active_scaffold/config/list.rb +17 -7
- data/lib/active_scaffold/config/mark.rb +1 -1
- data/lib/active_scaffold/configurable.rb +5 -3
- data/lib/active_scaffold/constraints.rb +21 -19
- data/lib/active_scaffold/core.rb +35 -26
- data/lib/active_scaffold/data_structures/action_columns.rb +1 -1
- data/lib/active_scaffold/data_structures/action_link.rb +34 -16
- data/lib/active_scaffold/data_structures/action_links.rb +9 -11
- data/lib/active_scaffold/data_structures/association/abstract.rb +35 -13
- data/lib/active_scaffold/data_structures/association/active_mongoid.rb +2 -6
- data/lib/active_scaffold/data_structures/association/active_record.rb +5 -1
- data/lib/active_scaffold/data_structures/association/mongoid.rb +0 -3
- data/lib/active_scaffold/data_structures/column.rb +49 -58
- data/lib/active_scaffold/data_structures/columns.rb +3 -2
- data/lib/active_scaffold/data_structures/nested_info.rb +20 -18
- data/lib/active_scaffold/data_structures/sorting.rb +5 -0
- data/lib/active_scaffold/delayed_setup.rb +16 -6
- data/lib/active_scaffold/extensions/action_controller_rendering.rb +1 -1
- data/lib/active_scaffold/extensions/action_view_rendering.rb +34 -14
- data/lib/active_scaffold/extensions/cow_proxy.rb +50 -2
- data/lib/active_scaffold/extensions/localize.rb +3 -1
- data/lib/active_scaffold/extensions/routing_mapper.rb +2 -2
- data/lib/active_scaffold/extensions/to_label.rb +3 -2
- data/lib/active_scaffold/finder.rb +81 -46
- data/lib/active_scaffold/helpers/action_link_helpers.rb +47 -21
- data/lib/active_scaffold/helpers/association_helpers.rb +13 -11
- data/lib/active_scaffold/helpers/controller_helpers.rb +14 -11
- data/lib/active_scaffold/helpers/form_column_helpers.rb +133 -99
- data/lib/active_scaffold/helpers/human_condition_helpers.rb +1 -1
- data/lib/active_scaffold/helpers/id_helpers.rb +4 -0
- data/lib/active_scaffold/helpers/list_column_helpers.rb +76 -49
- data/lib/active_scaffold/helpers/pagination_helpers.rb +2 -2
- data/lib/active_scaffold/helpers/search_column_helpers.rb +25 -30
- data/lib/active_scaffold/helpers/show_column_helpers.rb +3 -5
- data/lib/active_scaffold/helpers/view_helpers.rb +31 -22
- data/lib/active_scaffold/orm_checks.rb +2 -2
- data/lib/active_scaffold/paginator.rb +1 -3
- data/lib/active_scaffold/registry.rb +11 -0
- data/lib/active_scaffold/responds_to_parent.rb +6 -5
- data/lib/active_scaffold/tableless.rb +6 -8
- data/lib/active_scaffold/version.rb +1 -1
- data/shoulda_macros/macros.rb +3 -1
- data/test/bridges/paperclip_test.rb +1 -1
- data/test/company.rb +2 -2
- data/test/data_structures/action_columns_test.rb +2 -2
- data/test/data_structures/column_test.rb +3 -6
- data/test/data_structures/columns_test.rb +2 -2
- data/test/extensions/active_record_test.rb +4 -4
- data/test/extensions/routing_mapper_test.rb +2 -2
- data/test/helpers/list_column_helpers_test.rb +3 -1
- data/test/misc/active_record_permissions_test.rb +2 -2
- data/test/misc/attribute_params_test.rb +4 -0
- data/test/misc/configurable_test.rb +10 -10
- data/test/misc/convert_numbers_format_test.rb +4 -0
- data/test/mock_app/app/assets/config/manifest.js +0 -0
- data/test/mock_app/app/controllers/cars_controller.rb +1 -0
- data/test/mock_app/app/controllers/people_controller.rb +3 -1
- data/test/mock_app/config/application.rb +1 -0
- data/test/mock_app/config/routes.rb +4 -1
- data/test/mock_app/db/schema.rb +2 -0
- data/test/performance/list_cars_performance_test.rb +34 -0
- data/test/performance/list_people_performance_test.rb +31 -0
- data/test/performance_test_help.rb +3 -0
- data/test/test_helper.rb +2 -1
- metadata +22 -12
- data/app/assets/javascripts/prototype/rico_corner.js +0 -370
- data/lib/active_scaffold/bridges/file_column/test/test_helper.rb +0 -5
@@ -4,6 +4,20 @@ module CowProxy
|
|
4
4
|
module ActiveScaffold
|
5
5
|
module DataStructures
|
6
6
|
class Column < ::CowProxy::WrapClass(::ActiveScaffold::DataStructures::Column)
|
7
|
+
# readonly and called many times in list action
|
8
|
+
delegate :name, :cache_key, :delegated_association, :association, to: :__getobj__
|
9
|
+
|
10
|
+
def link
|
11
|
+
return @link if defined?(@link)
|
12
|
+
if __getobj__.frozen?
|
13
|
+
link_var = __getobj__.instance_variable_get(:@link)
|
14
|
+
if link_var.is_a?(Proc)
|
15
|
+
@link = link_var.call self
|
16
|
+
return @link
|
17
|
+
end
|
18
|
+
end
|
19
|
+
super
|
20
|
+
end
|
7
21
|
end
|
8
22
|
|
9
23
|
class Set < ::CowProxy::WrapClass(::ActiveScaffold::DataStructures::Set)
|
@@ -20,15 +34,34 @@ module CowProxy
|
|
20
34
|
end
|
21
35
|
end
|
22
36
|
|
37
|
+
class ActionColumns < ::CowProxy::WrapClass(::ActiveScaffold::DataStructures::ActionColumns)
|
38
|
+
def each_column(options = {})
|
39
|
+
__getobj__.each_column(options.reverse_merge(core_columns: action.core.columns)) do |column|
|
40
|
+
if column.is_a?(::ActiveScaffold::DataStructures::ActionColumns)
|
41
|
+
yield ::CowProxy.wrap(column).tap { |group| group.action = action }
|
42
|
+
else
|
43
|
+
yield column
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
23
49
|
class ActionLinks < ::CowProxy::WrapClass(::ActiveScaffold::DataStructures::ActionLinks)
|
24
50
|
def method_missing(name, *args, &block)
|
51
|
+
CowProxy.debug { "method missing #{name} in #{__getobj__.name}" }
|
25
52
|
return super if name =~ /[!?]$/
|
26
|
-
__copy_on_write__ if frozen?
|
27
53
|
subgroup =
|
28
54
|
if _instance_variable_defined?("@#{name}")
|
29
55
|
_instance_variable_get("@#{name}")
|
30
56
|
else
|
31
|
-
|
57
|
+
__copy_on_write__ if __getobj__.frozen?
|
58
|
+
group = __getobj__.subgroup(name, args.first)
|
59
|
+
if group.frozen?
|
60
|
+
group = __wrap__(group)
|
61
|
+
else
|
62
|
+
CowProxy.debug { "created subgroup #{group.name}" }
|
63
|
+
end
|
64
|
+
_instance_variable_set("@#{name}", group)
|
32
65
|
end
|
33
66
|
yield subgroup if block
|
34
67
|
subgroup
|
@@ -37,6 +70,21 @@ module CowProxy
|
|
37
70
|
def respond_to_missing?(name, *)
|
38
71
|
name !~ /[!?]$/
|
39
72
|
end
|
73
|
+
|
74
|
+
protected
|
75
|
+
|
76
|
+
# Copy wrapped values to duplicated wrapped object
|
77
|
+
# @see CowProxy::Base#__copy_on_write__
|
78
|
+
# @return duplicated wrapped object
|
79
|
+
def __copy_on_write__(*)
|
80
|
+
index = @parent_proxy.instance_variable_get(:@set).index(__getobj__) if @parent_proxy
|
81
|
+
super.tap do
|
82
|
+
CowProxy.debug { "replace #{index} with proxy obj in parent #{@parent_proxy.name}" } if index
|
83
|
+
@parent_proxy.instance_variable_get(:@set)[index] = self if index
|
84
|
+
new_set = __getobj__.instance_variable_get(:@set).dup
|
85
|
+
__getobj__.instance_variable_set(:@set, new_set)
|
86
|
+
end
|
87
|
+
end
|
40
88
|
end
|
41
89
|
end
|
42
90
|
end
|
@@ -1,7 +1,9 @@
|
|
1
1
|
class Object
|
2
2
|
def as_(key, options = {})
|
3
3
|
if key.present?
|
4
|
-
|
4
|
+
scope = [:active_scaffold, *options.delete(:scope)]
|
5
|
+
options = options.reverse_merge(:scope => scope, :default => key.is_a?(String) ? key : key.to_s.titleize)
|
6
|
+
text = I18n.translate(key.to_s, options).html_safe # rubocop:disable Rails/OutputSafety
|
5
7
|
# text = nil if text.include?('translation missing:')
|
6
8
|
end
|
7
9
|
text || key
|
@@ -16,9 +16,9 @@ module ActiveScaffold
|
|
16
16
|
|
17
17
|
def get_actions(actions_hash, options)
|
18
18
|
default_actions = default_actions(actions_hash)
|
19
|
-
if only = options[:only]
|
19
|
+
if (only = options[:only])
|
20
20
|
Array(only).map(&:to_sym)
|
21
|
-
elsif except = options[:except]
|
21
|
+
elsif (except = options[:except])
|
22
22
|
default_actions - Array(except).map(&:to_sym)
|
23
23
|
else
|
24
24
|
default_actions
|
@@ -1,8 +1,9 @@
|
|
1
1
|
# the ever-useful to_label method
|
2
2
|
class ActiveRecord::Base
|
3
3
|
def to_label
|
4
|
-
|
5
|
-
|
4
|
+
to_label_method = ActiveScaffold::Registry.cache :to_label, self.class.name do
|
5
|
+
%i[name label title to_s].find { |attribute| respond_to?(attribute) }
|
6
6
|
end
|
7
|
+
send(to_label_method).to_s if to_label_method
|
7
8
|
end
|
8
9
|
end
|
@@ -1,7 +1,7 @@
|
|
1
1
|
module ActiveScaffold
|
2
2
|
module Finder
|
3
3
|
def self.like_operator
|
4
|
-
@@like_operator ||= ::ActiveRecord::Base.connection.adapter_name
|
4
|
+
@@like_operator ||= ::ActiveRecord::Base.connection.adapter_name.in?(%w[PostgreSQL PostGIS]) ? 'ILIKE' : 'LIKE'
|
5
5
|
end
|
6
6
|
|
7
7
|
module ClassMethods
|
@@ -68,7 +68,9 @@ module ActiveScaffold
|
|
68
68
|
value = columns_token[column.name]
|
69
69
|
value = /#{value}/ if column.text?
|
70
70
|
column.search_sql.map do |search_sql|
|
71
|
-
|
71
|
+
# call .to_s so String is returned from CowProxy::String in threadsafe mode
|
72
|
+
# in other case, or method from Mongoid would fail
|
73
|
+
{search_sql.to_s => value}
|
72
74
|
end
|
73
75
|
end.flatten
|
74
76
|
active_scaffold_config.model.or(token_conditions).selector
|
@@ -101,12 +103,10 @@ module ActiveScaffold
|
|
101
103
|
sql, *values =
|
102
104
|
if search_ui && respond_to?("condition_for_#{search_ui}_type")
|
103
105
|
send("condition_for_#{search_ui}_type", column, value, like_pattern)
|
106
|
+
elsif column.search_sql.instance_of? Proc
|
107
|
+
column.search_sql.call(value)
|
104
108
|
else
|
105
|
-
|
106
|
-
column.search_sql.call(value)
|
107
|
-
else
|
108
|
-
condition_for_search_ui(column, value, like_pattern, search_ui)
|
109
|
-
end
|
109
|
+
condition_for_search_ui(column, value, like_pattern, search_ui)
|
110
110
|
end
|
111
111
|
return nil unless sql
|
112
112
|
|
@@ -176,12 +176,14 @@ module ActiveScaffold
|
|
176
176
|
end
|
177
177
|
|
178
178
|
def tables_for_translating_days_and_months(format)
|
179
|
+
# rubocop:disable Style/FormatStringToken
|
179
180
|
keys = {
|
180
181
|
'%A' => 'date.day_names',
|
181
182
|
'%a' => 'date.abbr_day_names',
|
182
183
|
'%B' => 'date.month_names',
|
183
184
|
'%b' => 'date.abbr_month_names'
|
184
185
|
}
|
186
|
+
# rubocop:enable Style/FormatStringToken
|
185
187
|
key_index = keys.keys.map { |key| [key, format.index(key)] }.to_h
|
186
188
|
keys.select! { |k, _| key_index[k] }
|
187
189
|
keys.sort_by { |k, _| key_index[k] }.map do |_, k|
|
@@ -226,37 +228,60 @@ module ActiveScaffold
|
|
226
228
|
[format, parts[:offset]]
|
227
229
|
end
|
228
230
|
|
231
|
+
def local_time_from_hash(value, conversion = :to_time)
|
232
|
+
time = Time.zone.local(*%i[year month day hour minute second].collect { |part| value[part].to_i })
|
233
|
+
time.send(conversion)
|
234
|
+
rescue StandardError => e
|
235
|
+
message = "Error creating time from #{value.inspect}:"
|
236
|
+
Rails.logger.warn "#{message}\n#{e.message}\n#{e.backtrace.join("\n")}"
|
237
|
+
nil
|
238
|
+
end
|
239
|
+
|
240
|
+
def parse_date_with_format(value, format_name)
|
241
|
+
format = I18n.t("date.formats.#{format_name || :default}")
|
242
|
+
format.gsub!(/%-d|%-m|%_m/) { |s| s.gsub(/[-_]/, '') } # strptime fails with %-d, %-m, %_m
|
243
|
+
en_value = I18n.locale == :en ? value : translate_days_and_months(value, format)
|
244
|
+
Date.strptime(en_value, format)
|
245
|
+
rescue StandardError => e
|
246
|
+
message = "Error parsing date from #{en_value}"
|
247
|
+
message << " (#{value})" if en_value != value
|
248
|
+
message << ", with format #{format}" if format
|
249
|
+
Rails.logger.warn "#{message}:\n#{e.message}\n#{e.backtrace.join("\n")}"
|
250
|
+
nil
|
251
|
+
end
|
252
|
+
|
253
|
+
def parse_time_with_format(value, format, offset)
|
254
|
+
format.gsub!(/%-d|%-m|%_m/) { |s| s.gsub(/[-_]/, '') } # strptime fails with %-d, %-m, %_m
|
255
|
+
en_value = I18n.locale == :en ? value : translate_days_and_months(value, format)
|
256
|
+
time = Time.strptime(en_value, format)
|
257
|
+
offset ? time : Time.zone.local_to_utc(time).in_time_zone
|
258
|
+
rescue StandardError => e
|
259
|
+
message = "Error parsing time from #{en_value}"
|
260
|
+
message << " (#{value})" if en_value != value
|
261
|
+
message << ", with format #{format}" if format
|
262
|
+
Rails.logger.warn "#{message}:\n#{e.message}\n#{e.backtrace.join("\n")}"
|
263
|
+
nil
|
264
|
+
end
|
265
|
+
|
229
266
|
def condition_value_for_datetime(column, value, conversion = :to_time)
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
-
|
235
|
-
|
236
|
-
|
237
|
-
|
238
|
-
|
239
|
-
|
240
|
-
value.send(conversion)
|
241
|
-
end
|
242
|
-
elsif conversion == :to_date
|
243
|
-
format = I18n.t("date.formats.#{column.options[:format] || :default}")
|
244
|
-
format.gsub!(/%-d|%-m|%_m/) { |s| s.gsub(/[-_]/, '') } # strptime fails with %-d, %-m, %_m
|
245
|
-
value = translate_days_and_months(value, format) if I18n.locale != :en
|
246
|
-
Date.strptime(value, format) rescue nil
|
247
|
-
elsif value.include?('T')
|
248
|
-
Time.zone.parse(value)
|
249
|
-
else # datetime
|
250
|
-
format, offset = format_for_datetime(column, value)
|
251
|
-
format.gsub!(/%-d|%-m|%_m/) { |s| s.gsub(/[-_]/, '') } # strptime fails with %-d, %-m, %_m
|
252
|
-
value = translate_days_and_months(value, format) if I18n.locale != :en
|
253
|
-
time = Time.strptime(value, format) rescue nil
|
254
|
-
if time
|
255
|
-
time = Time.zone.local_to_utc(time).in_time_zone unless offset
|
256
|
-
time = time.send(conversion) unless conversion == :to_time
|
257
|
-
end
|
258
|
-
time
|
267
|
+
return if value.nil? || value.blank?
|
268
|
+
if value.is_a? Hash
|
269
|
+
local_time_from_hash(value, conversion)
|
270
|
+
elsif value.respond_to?(:strftime)
|
271
|
+
if conversion == :to_time
|
272
|
+
# Explicitly get the current zone, because TimeWithZone#to_time in rails 3.2.3 returns UTC.
|
273
|
+
# https://github.com/rails/rails/pull/2453
|
274
|
+
value.to_time.in_time_zone
|
275
|
+
else
|
276
|
+
value.send(conversion)
|
259
277
|
end
|
278
|
+
elsif conversion == :to_date
|
279
|
+
parse_date_with_format(value, column.options[:format])
|
280
|
+
elsif value.include?('T')
|
281
|
+
Time.zone.parse(value)
|
282
|
+
else # datetime
|
283
|
+
time = parse_time_with_format(value, *format_for_datetime(column, value))
|
284
|
+
conversion == :to_time ? time : time.send(conversion)
|
260
285
|
end
|
261
286
|
end
|
262
287
|
|
@@ -264,7 +289,12 @@ module ActiveScaffold
|
|
264
289
|
return value if value.nil?
|
265
290
|
value = column.number_to_native(value) if column.options[:format] && column.search_ui != :number
|
266
291
|
case (column.search_ui || column.column.type)
|
267
|
-
when :integer then
|
292
|
+
when :integer then
|
293
|
+
if value.is_a?(TrueClass) || value.is_a?(FalseClass)
|
294
|
+
value ? 1 : 0
|
295
|
+
else
|
296
|
+
value.to_i
|
297
|
+
end
|
268
298
|
when :float then value.to_f
|
269
299
|
when :decimal
|
270
300
|
::ActiveRecord::Type::Decimal.new.type_cast_from_user(value)
|
@@ -362,10 +392,12 @@ module ActiveScaffold
|
|
362
392
|
@active_scaffold_references ||= []
|
363
393
|
end
|
364
394
|
|
365
|
-
# Override this method on your controller to define conditions to be used when querying a recordset (e.g. for List).
|
395
|
+
# Override this method on your controller to define conditions to be used when querying a recordset (e.g. for List).
|
396
|
+
# The return of this method should be any format compatible with the :conditions clause of ActiveRecord::Base's find.
|
366
397
|
def conditions_for_collection; end
|
367
398
|
|
368
|
-
# Override this method on your controller to define joins to be used when querying a recordset (e.g. for List).
|
399
|
+
# Override this method on your controller to define joins to be used when querying a recordset (e.g. for List).
|
400
|
+
# The return of this method should be any format compatible with the :joins clause of ActiveRecord::Base's find.
|
369
401
|
def joins_for_collection; end
|
370
402
|
|
371
403
|
# Override this method on your controller to provide custom finder options to the find() call. The return of this method should be a hash.
|
@@ -403,7 +435,10 @@ module ActiveScaffold
|
|
403
435
|
end
|
404
436
|
|
405
437
|
# valid options may include:
|
406
|
-
# * :sorting - a Sorting DataStructure (basically an array of hashes of field => direction,
|
438
|
+
# * :sorting - a Sorting DataStructure (basically an array of hashes of field => direction,
|
439
|
+
# e.g. [{:field1 => 'asc'}, {:field2 => 'desc'}]).
|
440
|
+
# please note that multi-column sorting has some limitations: if any column in a multi-field
|
441
|
+
# sort uses method-based sorting, it will be ignored. method sorting only works for single-column sorting.
|
407
442
|
# * :per_page
|
408
443
|
# * :page
|
409
444
|
def finder_options(options = {})
|
@@ -411,7 +446,7 @@ module ActiveScaffold
|
|
411
446
|
|
412
447
|
# create a general-use options array that's compatible with Rails finders
|
413
448
|
finder_options = {
|
414
|
-
:reorder => options[:sorting]&.clause((grouped_columns_calculations if grouped_search?)),
|
449
|
+
:reorder => options[:sorting]&.clause((grouped_columns_calculations if grouped_search?)).map(&Arel.method(:sql)),
|
415
450
|
:conditions => search_conditions
|
416
451
|
}
|
417
452
|
if active_scaffold_config.mongoid?
|
@@ -480,7 +515,7 @@ module ActiveScaffold
|
|
480
515
|
end
|
481
516
|
|
482
517
|
def calculate_last_modified(query)
|
483
|
-
return unless conditional_get_support? && query.klass
|
518
|
+
return unless conditional_get_support? && ActiveScaffold::OrmChecks.columns_hash(query.klass)['updated_at']
|
484
519
|
@last_modified = query.maximum(:updated_at)
|
485
520
|
end
|
486
521
|
|
@@ -497,13 +532,13 @@ module ActiveScaffold
|
|
497
532
|
end
|
498
533
|
|
499
534
|
def append_to_query(relation, options)
|
500
|
-
options.assert_valid_keys :where, :select, :having, :group, :reorder, :order, :limit, :offset,
|
535
|
+
options.assert_valid_keys :where, :select, :having, :group, :reorder, :order, :limit, :offset,
|
536
|
+
:joins, :left_joins, :left_outer_joins, :includes, :lock, :readonly,
|
537
|
+
:from, :conditions, :preload, :references
|
501
538
|
relation = options.reject { |_, v| v.blank? }.inject(relation) do |rel, (k, v)|
|
502
539
|
k == :conditions ? apply_conditions(rel, *v) : rel.send(k, v)
|
503
540
|
end
|
504
|
-
if options[:left_outer_joins].present? || options[:left_joins].present?
|
505
|
-
relation.distinct_value = true
|
506
|
-
end
|
541
|
+
relation.distinct_value = true if options[:left_outer_joins].present? || options[:left_joins].present?
|
507
542
|
relation
|
508
543
|
end
|
509
544
|
|
@@ -24,9 +24,9 @@ module ActiveScaffold
|
|
24
24
|
ul_options = record_or_ul_options if ul_options.nil? && record_or_ul_options.is_a?(Hash)
|
25
25
|
record = record_or_ul_options unless record_or_ul_options.is_a?(Hash)
|
26
26
|
html = content_tag :ul, ul_options do
|
27
|
-
safe_join
|
27
|
+
safe_join(links.map { |link| content_tag :li, link })
|
28
28
|
end
|
29
|
-
raw "ActiveScaffold.display_dynamic_action_group('#{get_action_link_id action_link, record}', '#{escape_javascript html}');"
|
29
|
+
raw "ActiveScaffold.display_dynamic_action_group('#{get_action_link_id action_link, record}', '#{escape_javascript html}');" # rubocop:disable Rails/OutputSafety
|
30
30
|
end
|
31
31
|
|
32
32
|
def display_action_links(action_links, record, options, &block)
|
@@ -67,7 +67,7 @@ module ActiveScaffold
|
|
67
67
|
html_classes << 'top' if options[:first_action]
|
68
68
|
group_tag = :li
|
69
69
|
end
|
70
|
-
content = content_tag(group_tag, :class =>
|
70
|
+
content = content_tag(group_tag, :class => html_classes.presence, :onclick => ('' if hover_via_click?)) do
|
71
71
|
content_tag(:div, as_(link.label), :class => link.name.to_s.downcase) << content_tag(:ul, content)
|
72
72
|
end
|
73
73
|
else
|
@@ -85,7 +85,9 @@ module ActiveScaffold
|
|
85
85
|
options.delete :link if link.crud_type == :create
|
86
86
|
end
|
87
87
|
if link.action.nil? || (link.type == :member && options.key?(:authorized) && !options[:authorized])
|
88
|
-
|
88
|
+
html_class = "disabled #{link.action}#{" #{link.html_options[:class]}" if link.html_options[:class].present?}"
|
89
|
+
html_options = {:link => action_link_text(link, options), :class => html_class, :title => options[:not_authorized_reason]}
|
90
|
+
action_link_html(link, nil, html_options, record)
|
89
91
|
else
|
90
92
|
url = action_link_url(link, record)
|
91
93
|
html_options = action_link_html_options(link, record, options)
|
@@ -106,12 +108,12 @@ module ActiveScaffold
|
|
106
108
|
end
|
107
109
|
|
108
110
|
def configure_column_link(link, record, associated, actions = nil)
|
109
|
-
actions ||= link.
|
111
|
+
actions ||= link.controller_actions || []
|
110
112
|
if column_empty?(associated) # if association is empty, we only can link to create form
|
111
113
|
if actions.include?(:new)
|
112
114
|
link.action = 'new'
|
113
115
|
link.crud_type = :create
|
114
|
-
link.label ||=
|
116
|
+
link.label ||= :create_new
|
115
117
|
end
|
116
118
|
elsif actions.include?(:edit)
|
117
119
|
link.action = 'edit'
|
@@ -137,7 +139,7 @@ module ActiveScaffold
|
|
137
139
|
def column_link_authorized?(link, column, record, associated)
|
138
140
|
if column.association
|
139
141
|
associated_for_authorized =
|
140
|
-
if column.association.collection? ||
|
142
|
+
if column.association.collection? || associated.nil?
|
141
143
|
column.association.klass
|
142
144
|
else
|
143
145
|
associated
|
@@ -209,6 +211,18 @@ module ActiveScaffold
|
|
209
211
|
url
|
210
212
|
end
|
211
213
|
|
214
|
+
def column_in_params_conditions?(key)
|
215
|
+
if key =~ /!$/
|
216
|
+
conditions_from_params[1..-1].any? { |node| node.left.name.to_s == key[0..-2] }
|
217
|
+
else
|
218
|
+
conditions_from_params[0].include?(key)
|
219
|
+
end
|
220
|
+
end
|
221
|
+
|
222
|
+
def ignore_param_for_nested?(key)
|
223
|
+
NESTED_PARAMS.include?(key) || column_in_params_conditions?(key) || (nested? && nested.param_name == key)
|
224
|
+
end
|
225
|
+
|
212
226
|
def query_string_for_action_links(link)
|
213
227
|
if defined?(@query_string) && link.parameters.none? { |k, _| @query_string_params.include? k }
|
214
228
|
return [@query_string, @non_nested_query_string]
|
@@ -224,12 +238,17 @@ module ActiveScaffold
|
|
224
238
|
keep = false
|
225
239
|
next
|
226
240
|
end
|
227
|
-
if
|
241
|
+
if ignore_param_for_nested?(key)
|
228
242
|
non_nested_query_string_options[key] = value
|
229
243
|
else
|
230
244
|
query_string_options[key] = value
|
231
245
|
end
|
232
246
|
end
|
247
|
+
if nested_singular_association? && action_name == 'index'
|
248
|
+
# pass current path as return_to, for nested listing on singular association, so forms doesn't return to parent listing
|
249
|
+
@query_string_params << :return_to
|
250
|
+
non_nested_query_string_options[:return_to] = request.fullpath
|
251
|
+
end
|
233
252
|
|
234
253
|
query_string = query_string_options.to_query if query_string_options.present?
|
235
254
|
if non_nested_query_string_options.present?
|
@@ -331,7 +350,10 @@ module ActiveScaffold
|
|
331
350
|
html_options[:class] << ' active' if action_link_selected?(link, record)
|
332
351
|
end
|
333
352
|
|
334
|
-
|
353
|
+
if !options[:page] && !options[:inline] && (options[:popup] || link.popup?)
|
354
|
+
html_options[:target] = '_blank'
|
355
|
+
html_options[:rel] = [html_options[:rel], 'noopener noreferrer'].compact.join(' ')
|
356
|
+
end
|
335
357
|
html_options[:id] = link_id
|
336
358
|
if link.dhtml_confirm?
|
337
359
|
unless link.inline?
|
@@ -344,20 +366,23 @@ module ActiveScaffold
|
|
344
366
|
html_options
|
345
367
|
end
|
346
368
|
|
347
|
-
def get_action_link_id(link, record = nil
|
348
|
-
column
|
369
|
+
def get_action_link_id(link, record = nil)
|
370
|
+
column = link.column
|
349
371
|
if column&.association && record
|
350
|
-
|
351
|
-
|
352
|
-
|
353
|
-
|
354
|
-
|
355
|
-
|
356
|
-
|
372
|
+
associated = record.send(column.association.name) unless column.association.collection?
|
373
|
+
id =
|
374
|
+
if associated
|
375
|
+
"#{column.association.name}-#{associated.id}-#{record.id}"
|
376
|
+
else
|
377
|
+
"#{column.association.name}-#{record.id}"
|
378
|
+
end
|
379
|
+
end
|
380
|
+
id ||= record&.id&.to_s || (nested? ? nested_parent_id.to_s : '')
|
381
|
+
action_link_id = ActiveScaffold::Registry.cache :action_link_id, link.name_to_cache do
|
382
|
+
action_id = "#{id_from_controller("#{link.controller}-") if params[:parent_controller] || (link.controller && link.controller != controller.controller_path)}#{link.action}"
|
383
|
+
action_link_id(action_id, '--ID--')
|
357
384
|
end
|
358
|
-
|
359
|
-
action_id = "#{id_from_controller("#{link.controller}-") if params[:parent_controller] || (link.controller && link.controller != controller.controller_path)}#{link.action}"
|
360
|
-
action_link_id(action_id, id)
|
385
|
+
action_link_id.sub('--ID--', id)
|
361
386
|
end
|
362
387
|
|
363
388
|
def action_link_html(link, url, html_options, record)
|
@@ -380,6 +405,7 @@ module ActiveScaffold
|
|
380
405
|
elsif link.parameters&.dig(:named_scope)
|
381
406
|
url_options[:parent_scaffold] = controller_path
|
382
407
|
url_options[active_scaffold_config.model.name.foreign_key.to_sym] = url_options.delete(:id)
|
408
|
+
url_options[:id] = nil
|
383
409
|
end
|
384
410
|
end
|
385
411
|
|