active_scaffold 3.4.43 → 3.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (216) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG +39 -0
  3. data/{LICENSE → LICENSE.md} +1 -1
  4. data/README.md +27 -19
  5. data/app/assets/javascripts/active_scaffold.js.erb +1 -1
  6. data/app/assets/javascripts/jquery/active_scaffold.js +95 -43
  7. data/app/assets/javascripts/jquery/tiny_mce_bridge.js +30 -6
  8. data/app/assets/javascripts/prototype/tiny_mce_bridge.js +11 -1
  9. data/app/assets/stylesheets/active_scaffold_colors.scss +2 -2
  10. data/app/assets/stylesheets/active_scaffold_layout.css +36 -28
  11. data/app/views/active_scaffold_overrides/_base_form.html.erb +2 -3
  12. data/app/views/active_scaffold_overrides/_field_search.html.erb +8 -7
  13. data/app/views/active_scaffold_overrides/_form_association.html.erb +9 -9
  14. data/app/views/active_scaffold_overrides/_form_association_footer.html.erb +6 -6
  15. data/app/views/active_scaffold_overrides/_form_association_record.html.erb +52 -50
  16. data/app/views/active_scaffold_overrides/_horizontal_subform.html.erb +1 -1
  17. data/app/views/active_scaffold_overrides/_horizontal_subform_header.html.erb +1 -1
  18. data/app/views/active_scaffold_overrides/_human_conditions.html.erb +3 -1
  19. data/app/views/active_scaffold_overrides/_list_calculations.html.erb +1 -1
  20. data/app/views/active_scaffold_overrides/_list_column_headings.html.erb +2 -0
  21. data/app/views/active_scaffold_overrides/_list_messages.html.erb +5 -3
  22. data/app/views/active_scaffold_overrides/_list_record.html.erb +3 -1
  23. data/app/views/active_scaffold_overrides/_list_with_header.html.erb +9 -9
  24. data/app/views/active_scaffold_overrides/_messages.html.erb +1 -1
  25. data/app/views/active_scaffold_overrides/_refresh_list.js.erb +18 -10
  26. data/app/views/active_scaffold_overrides/_render_field.js.erb +3 -3
  27. data/app/views/active_scaffold_overrides/_search.html.erb +7 -6
  28. data/app/views/active_scaffold_overrides/_show_actions.html.erb +14 -0
  29. data/app/views/active_scaffold_overrides/_show_association.html.erb +1 -1
  30. data/app/views/active_scaffold_overrides/_update_actions.html.erb +6 -2
  31. data/app/views/active_scaffold_overrides/_update_column.js.erb +1 -1
  32. data/app/views/active_scaffold_overrides/_update_form.html.erb +1 -1
  33. data/app/views/active_scaffold_overrides/destroy.js.erb +2 -3
  34. data/app/views/active_scaffold_overrides/edit_associated.js.erb +4 -3
  35. data/app/views/active_scaffold_overrides/on_action_update.js.erb +5 -3
  36. data/app/views/active_scaffold_overrides/on_create.js.erb +4 -4
  37. data/app/views/active_scaffold_overrides/on_update.js.erb +6 -6
  38. data/app/views/active_scaffold_overrides/show.html.erb +6 -0
  39. data/app/views/active_scaffold_overrides/update.html.erb +1 -1
  40. data/app/views/active_scaffold_overrides/update_column.js.erb +1 -1
  41. data/config/brakeman.ignore +26 -0
  42. data/config/brakeman.yml +3 -0
  43. data/config/i18n-tasks.yml +121 -0
  44. data/config/locales/de.yml +81 -70
  45. data/config/locales/en.yml +83 -74
  46. data/config/locales/es.yml +82 -73
  47. data/config/locales/fr.yml +86 -75
  48. data/config/locales/hu.yml +81 -70
  49. data/config/locales/ja.yml +71 -60
  50. data/config/locales/ru.yml +85 -74
  51. data/lib/active_scaffold.rb +3 -0
  52. data/lib/active_scaffold/actions/common_search.rb +11 -7
  53. data/lib/active_scaffold/actions/core.rb +119 -47
  54. data/lib/active_scaffold/actions/create.rb +1 -1
  55. data/lib/active_scaffold/actions/delete.rb +11 -8
  56. data/lib/active_scaffold/actions/field_search.rb +104 -6
  57. data/lib/active_scaffold/actions/list.rb +25 -21
  58. data/lib/active_scaffold/actions/mark.rb +12 -4
  59. data/lib/active_scaffold/actions/nested.rb +26 -26
  60. data/lib/active_scaffold/actions/search.rb +2 -2
  61. data/lib/active_scaffold/actions/show.rb +4 -5
  62. data/lib/active_scaffold/actions/subform.rb +9 -7
  63. data/lib/active_scaffold/actions/update.rb +20 -13
  64. data/lib/active_scaffold/active_record_permissions.rb +24 -5
  65. data/lib/active_scaffold/attribute_params.rb +68 -49
  66. data/lib/active_scaffold/bridges.rb +1 -1
  67. data/lib/active_scaffold/bridges/ancestry/ancestry_bridge.rb +15 -19
  68. data/lib/active_scaffold/bridges/bitfields.rb +1 -1
  69. data/lib/active_scaffold/bridges/bitfields/bitfields_bridge.rb +10 -14
  70. data/lib/active_scaffold/bridges/calendar_date_select.rb +0 -7
  71. data/lib/active_scaffold/bridges/calendar_date_select/as_cds_bridge.rb +19 -22
  72. data/lib/active_scaffold/bridges/cancan.rb +4 -3
  73. data/lib/active_scaffold/bridges/cancan/cancan_bridge.rb +11 -21
  74. data/lib/active_scaffold/bridges/carrierwave.rb +2 -1
  75. data/lib/active_scaffold/bridges/carrierwave/carrierwave_bridge.rb +2 -6
  76. data/lib/active_scaffold/bridges/carrierwave/form_ui.rb +6 -39
  77. data/lib/active_scaffold/bridges/carrierwave/list_ui.rb +1 -1
  78. data/lib/active_scaffold/bridges/chosen.rb +4 -1
  79. data/lib/active_scaffold/bridges/chosen/helpers.rb +3 -2
  80. data/lib/active_scaffold/bridges/country_select/country_select_bridge_helper.rb +2 -2
  81. data/lib/active_scaffold/bridges/date_picker.rb +3 -0
  82. data/lib/active_scaffold/bridges/date_picker/ext.rb +43 -38
  83. data/lib/active_scaffold/bridges/date_picker/helper.rb +24 -23
  84. data/lib/active_scaffold/bridges/dragonfly.rb +1 -1
  85. data/lib/active_scaffold/bridges/dragonfly/dragonfly_bridge.rb +3 -7
  86. data/lib/active_scaffold/bridges/dragonfly/form_ui.rb +3 -25
  87. data/lib/active_scaffold/bridges/dragonfly/list_ui.rb +2 -2
  88. data/lib/active_scaffold/bridges/file_column/as_file_column_bridge.rb +6 -8
  89. data/lib/active_scaffold/bridges/file_column/file_column_helpers.rb +1 -1
  90. data/lib/active_scaffold/bridges/file_column/form_ui.rb +0 -2
  91. data/lib/active_scaffold/bridges/file_column/list_ui.rb +2 -1
  92. data/lib/active_scaffold/bridges/file_column/test/test_helper.rb +1 -1
  93. data/lib/active_scaffold/bridges/paper_trail/actions.rb +1 -1
  94. data/lib/active_scaffold/bridges/paper_trail/helper.rb +1 -2
  95. data/lib/active_scaffold/bridges/paper_trail/paper_trail_bridge.rb +3 -7
  96. data/lib/active_scaffold/bridges/paperclip.rb +1 -1
  97. data/lib/active_scaffold/bridges/paperclip/form_ui.rb +3 -28
  98. data/lib/active_scaffold/bridges/paperclip/list_ui.rb +1 -1
  99. data/lib/active_scaffold/bridges/paperclip/paperclip_bridge.rb +3 -7
  100. data/lib/active_scaffold/bridges/record_select.rb +2 -0
  101. data/lib/active_scaffold/bridges/record_select/helpers.rb +14 -18
  102. data/lib/active_scaffold/bridges/semantic_attributes/column.rb +4 -8
  103. data/lib/active_scaffold/bridges/shared/date_bridge.rb +20 -20
  104. data/lib/active_scaffold/bridges/tiny_mce/helpers.rb +7 -22
  105. data/lib/active_scaffold/bridges/usa_state_select/usa_state_select_helper.rb +14 -14
  106. data/lib/active_scaffold/config/base.rb +9 -6
  107. data/lib/active_scaffold/config/core.rb +30 -21
  108. data/lib/active_scaffold/config/create.rb +2 -1
  109. data/lib/active_scaffold/config/delete.rb +2 -2
  110. data/lib/active_scaffold/config/field_search.rb +9 -3
  111. data/lib/active_scaffold/config/form.rb +4 -4
  112. data/lib/active_scaffold/config/list.rb +27 -23
  113. data/lib/active_scaffold/config/nested.rb +4 -4
  114. data/lib/active_scaffold/config/search.rb +6 -6
  115. data/lib/active_scaffold/config/show.rb +11 -1
  116. data/lib/active_scaffold/config/subform.rb +1 -1
  117. data/lib/active_scaffold/config/update.rb +4 -2
  118. data/lib/active_scaffold/constraints.rb +39 -36
  119. data/lib/active_scaffold/core.rb +36 -15
  120. data/lib/active_scaffold/data_structures/action_columns.rb +14 -9
  121. data/lib/active_scaffold/data_structures/action_link.rb +4 -5
  122. data/lib/active_scaffold/data_structures/action_links.rb +5 -4
  123. data/lib/active_scaffold/data_structures/actions.rb +2 -2
  124. data/lib/active_scaffold/data_structures/association.rb +8 -0
  125. data/lib/active_scaffold/data_structures/association/abstract.rb +147 -0
  126. data/lib/active_scaffold/data_structures/association/active_mongoid.rb +42 -0
  127. data/lib/active_scaffold/data_structures/association/active_record.rb +94 -0
  128. data/lib/active_scaffold/data_structures/association/mongoid.rb +45 -0
  129. data/lib/active_scaffold/data_structures/bridge.rb +3 -6
  130. data/lib/active_scaffold/data_structures/column.rb +100 -82
  131. data/lib/active_scaffold/data_structures/columns.rb +21 -3
  132. data/lib/active_scaffold/data_structures/nested_info.rb +22 -37
  133. data/lib/active_scaffold/data_structures/set.rb +4 -4
  134. data/lib/active_scaffold/data_structures/sorting.rb +29 -15
  135. data/lib/active_scaffold/engine.rb +3 -1
  136. data/lib/active_scaffold/extensions/action_controller_rendering.rb +10 -5
  137. data/lib/active_scaffold/extensions/action_view_rendering.rb +65 -59
  138. data/lib/active_scaffold/extensions/left_outer_joins.rb +48 -53
  139. data/lib/active_scaffold/extensions/localize.rb +3 -4
  140. data/lib/active_scaffold/extensions/name_option_for_datetime.rb +7 -11
  141. data/lib/active_scaffold/extensions/paginator_extensions.rb +20 -18
  142. data/lib/active_scaffold/extensions/routing_mapper.rb +104 -40
  143. data/lib/active_scaffold/extensions/to_label.rb +1 -1
  144. data/lib/active_scaffold/extensions/unsaved_associated.rb +4 -13
  145. data/lib/active_scaffold/extensions/unsaved_record.rb +12 -1
  146. data/lib/active_scaffold/finder.rb +200 -134
  147. data/lib/active_scaffold/helpers/action_link_helpers.rb +398 -0
  148. data/lib/active_scaffold/helpers/association_helpers.rb +12 -30
  149. data/lib/active_scaffold/helpers/controller_helpers.rb +74 -24
  150. data/lib/active_scaffold/helpers/form_column_helpers.rb +205 -112
  151. data/lib/active_scaffold/helpers/human_condition_helpers.rb +21 -11
  152. data/lib/active_scaffold/helpers/id_helpers.rb +1 -1
  153. data/lib/active_scaffold/helpers/list_column_helpers.rb +117 -39
  154. data/lib/active_scaffold/helpers/pagination_helpers.rb +11 -14
  155. data/lib/active_scaffold/helpers/search_column_helpers.rb +69 -32
  156. data/lib/active_scaffold/helpers/show_column_helpers.rb +9 -3
  157. data/lib/active_scaffold/helpers/view_helpers.rb +41 -426
  158. data/lib/active_scaffold/orm_checks.rb +109 -0
  159. data/lib/active_scaffold/paginator.rb +1 -1
  160. data/lib/active_scaffold/responds_to_parent.rb +12 -10
  161. data/lib/active_scaffold/tableless.rb +81 -43
  162. data/lib/active_scaffold/version.rb +2 -2
  163. data/lib/generators/active_scaffold/controller_generator.rb +49 -0
  164. data/lib/generators/active_scaffold/install_generator.rb +45 -0
  165. data/lib/generators/active_scaffold/resource_generator.rb +56 -0
  166. data/lib/generators/{active_scaffold_controller/templates → templates}/controller.rb +0 -0
  167. data/lib/generators/{active_scaffold_controller/templates → templates}/helper.rb +0 -0
  168. data/shoulda_macros/macros.rb +3 -3
  169. data/test/active_scaffold_config_mock.rb +33 -0
  170. data/test/bridges/bridge_test.rb +9 -9
  171. data/test/bridges/date_picker_test.rb +3 -1
  172. data/test/bridges/paper_trail_test.rb +2 -3
  173. data/test/bridges/paperclip_test.rb +21 -10
  174. data/test/bridges/tiny_mce_test.rb +20 -21
  175. data/test/class_with_finder.rb +42 -0
  176. data/test/company.rb +6 -4
  177. data/test/config/core_test.rb +1 -1
  178. data/test/config/create_test.rb +1 -1
  179. data/test/config/list_test.rb +3 -3
  180. data/test/config/update_test.rb +3 -3
  181. data/test/data_structures/action_columns_test.rb +3 -3
  182. data/test/data_structures/association_column_test.rb +5 -5
  183. data/test/data_structures/column_test.rb +14 -14
  184. data/test/data_structures/columns_test.rb +2 -2
  185. data/test/data_structures/set_test.rb +2 -2
  186. data/test/data_structures/sorting_test.rb +6 -4
  187. data/test/extensions/active_record_test.rb +1 -1
  188. data/test/extensions/routing_mapper_test.rb +64 -13
  189. data/test/helpers/form_column_helpers_test.rb +6 -6
  190. data/test/helpers/list_column_helpers_test.rb +9 -5
  191. data/test/helpers/pagination_helpers_test.rb +1 -0
  192. data/test/misc/active_record_permissions_test.rb +18 -1
  193. data/test/misc/attribute_params_test.rb +26 -17
  194. data/test/misc/calculation_test.rb +8 -31
  195. data/test/misc/configurable_test.rb +3 -2
  196. data/test/misc/constraints_test.rb +33 -22
  197. data/test/misc/convert_numbers_format_test.rb +28 -10
  198. data/test/misc/finder_test.rb +6 -29
  199. data/test/misc/parse_datetime_test.rb +160 -0
  200. data/test/misc/render_test.rb +1 -1
  201. data/test/misc/tableless_test.rb +24 -0
  202. data/test/mock_app/app/models/building.rb +2 -1
  203. data/test/mock_app/config.ru +1 -1
  204. data/test/mock_app/config/environments/test.rb +1 -1
  205. data/test/mock_app/config/routes.rb +11 -3
  206. data/test/model_stub.rb +11 -6
  207. data/test/run_all.rb +1 -1
  208. data/test/test_helper.rb +19 -4
  209. metadata +42 -23
  210. data/lib/active_scaffold/data_structures/error_message.rb +0 -22
  211. data/lib/active_scaffold/extensions/reverse_associations.rb +0 -119
  212. data/lib/generators/active_scaffold/USAGE +0 -29
  213. data/lib/generators/active_scaffold/active_scaffold_generator.rb +0 -21
  214. data/lib/generators/active_scaffold_controller/USAGE +0 -19
  215. data/lib/generators/active_scaffold_controller/active_scaffold_controller_generator.rb +0 -29
  216. data/test/data_structures/error_message_test.rb +0 -25
@@ -24,7 +24,7 @@ module ActiveScaffold::DataStructures
24
24
  @_inheritable = []
25
25
  @set = []
26
26
 
27
- add *args
27
+ add(*args)
28
28
  end
29
29
 
30
30
  # the way to add columns to the set. this is primarily useful for virtual columns.
@@ -38,7 +38,25 @@ module ActiveScaffold::DataStructures
38
38
  # then add columns to @set (unless they already exist)
39
39
  args.each { |a| @set << ActiveScaffold::DataStructures::Column.new(a.to_sym, @active_record_class) unless find_by_name(a) }
40
40
  end
41
- alias_method :<<, :add
41
+ alias << add
42
+
43
+ # add columns from association (belongs_to or has_one)
44
+ # these columns will use label translation from association model
45
+ # they will be excluded, so won't be included in action columns
46
+ # association columns will work for read actions only, not in form actions (create, update, subform)
47
+ def add_association_columns(association, *columns)
48
+ column = self[association]
49
+ raise ArgumentError, "unknown column #{association}" if column.nil?
50
+ raise ArgumentError, "column #{association} is not an association" if column.association.nil?
51
+ raise ArugmentError, "column #{association} is not singular association" unless column.association.singular?
52
+ raise ArugmentError, "column #{association} is polymorphic association" if column.association.polymorphic?
53
+
54
+ klass = column.association.klass
55
+ columns.each do |col|
56
+ next if find_by_name col
57
+ @set << ActiveScaffold::DataStructures::Column.new(col, klass, column.association)
58
+ end
59
+ end
42
60
 
43
61
  def exclude(*args)
44
62
  # only remove columns from _inheritable. we never want to completely forget about a column.
@@ -56,7 +74,7 @@ module ActiveScaffold::DataStructures
56
74
  column = @set.find { |c| c == name }
57
75
  column
58
76
  end
59
- alias_method :[], :find_by_name
77
+ alias [] find_by_name
60
78
 
61
79
  def each
62
80
  @set.each { |i| yield i }
@@ -63,7 +63,7 @@ module ActiveScaffold::DataStructures
63
63
  false
64
64
  end
65
65
 
66
- def sorted?
66
+ def sorted?(*)
67
67
  false
68
68
  end
69
69
  end
@@ -71,27 +71,15 @@ module ActiveScaffold::DataStructures
71
71
  class NestedInfoAssociation < NestedInfo
72
72
  def initialize(model, params)
73
73
  super
74
- @association = parent_model.reflect_on_association(params[:association].to_sym)
75
- @param_name = @association.active_record.name.foreign_key.to_sym
74
+ column = parent_scaffold.active_scaffold_config.columns[params[:association].to_sym]
75
+ @param_name = column.model.name.foreign_key.to_sym
76
76
  @parent_id = params[@param_name]
77
- iterate_model_associations(model)
77
+ @association = column.try(:association)
78
+ @child_association = association.reverse_association(model) if association
79
+ setup_constrained_fields
78
80
  end
79
81
 
80
- delegate :name, :to => :association
81
-
82
- def has_many?
83
- association.macro == :has_many
84
- end
85
-
86
- def habtm?
87
- association.macro == :has_and_belongs_to_many
88
- end
89
-
90
- delegate :belongs_to?, :to => :association
91
-
92
- def has_one?
93
- association.macro == :has_one
94
- end
82
+ delegate :name, :belongs_to?, :has_one?, :has_many?, :habtm?, :readonly?, :to => :association
95
83
 
96
84
  # A through association with has_one or has_many as source association
97
85
  # create cannot be called in nested through associations, and not-nested through associations
@@ -101,28 +89,25 @@ module ActiveScaffold::DataStructures
101
89
  def readonly_through_association?(columns)
102
90
  return false unless through_association?
103
91
  return true if association.through_reflection.options[:through]
104
- association.source_reflection.macro != :belongs_to && (
92
+ !association.source_reflection.belongs_to? && (
105
93
  !child_association || !columns.include?(child_association.through_reflection.name)
106
94
  )
107
95
  end
108
96
 
109
97
  def through_association?
110
- association.options[:through]
98
+ association.through?
111
99
  end
112
100
 
113
- def readonly?
114
- association.options[:readonly]
101
+ def sorted?(chain)
102
+ default_sorting(chain).present?
115
103
  end
116
104
 
117
- def sorted?
118
- association.options.key? :order
119
- end
120
-
121
- def default_sorting
122
- if association.options[:order] # TODO: remove when rails 3 compatibility is removed
123
- association.options[:order]
124
- elsif association.respond_to?(:scope) # rails 4
125
- association.klass.class_eval(&association.scope).values[:order] if association.scope.is_a? Proc
105
+ def default_sorting(chain)
106
+ return @default_sorting if defined? @default_sorting
107
+ if association.scope.is_a?(Proc) && chain.respond_to?(:values) && chain.values[:order]
108
+ @default_sorting = chain.values[:order]
109
+ @default_sorting = @default_sorting.map(&:to_sql) if @default_sorting[0].is_a? Arel::Nodes::Node
110
+ @default_sorting = @default_sorting.join(', ')
126
111
  end
127
112
  end
128
113
 
@@ -132,12 +117,12 @@ module ActiveScaffold::DataStructures
132
117
 
133
118
  protected
134
119
 
135
- def iterate_model_associations(model)
120
+ def setup_constrained_fields
136
121
  @constrained_fields = []
137
- constrained_fields << Array(association.foreign_key).map(&:to_sym) unless association.belongs_to?
138
- return if (reverse = association.reverse(model)).nil?
139
- @child_association = model.reflect_on_association(reverse)
140
- constrained_fields << @child_association.name unless @child_association == association
122
+ @constrained_fields << Array(association.foreign_key).map(&:to_sym) unless association.belongs_to?
123
+ if child_association && child_association != association
124
+ @constrained_fields << child_association.name
125
+ end
141
126
  end
142
127
  end
143
128
 
@@ -9,7 +9,7 @@ module ActiveScaffold::DataStructures
9
9
 
10
10
  def set_values(*args)
11
11
  @set = []
12
- add *args
12
+ add(*args)
13
13
  end
14
14
 
15
15
  # the way to add items to the set.
@@ -20,7 +20,7 @@ module ActiveScaffold::DataStructures
20
20
  @set << arg unless @set.include? arg # avoid duplicates
21
21
  end
22
22
  end
23
- alias_method :<<, :add
23
+ alias << add
24
24
 
25
25
  # the way to remove items from the set.
26
26
  def exclude(*args)
@@ -29,7 +29,7 @@ module ActiveScaffold::DataStructures
29
29
  # check respond_to? :to_sym, ActionColumns doesn't respond to to_sym
30
30
  @set.reject! { |c| c.respond_to?(:to_sym) && args.include?(c.to_sym) } # reject all items specified
31
31
  end
32
- alias_method :remove, :exclude
32
+ alias remove exclude
33
33
 
34
34
  # returns an array of items with the provided names
35
35
  def find_by_names(*names)
@@ -42,7 +42,7 @@ module ActiveScaffold::DataStructures
42
42
  item = @set.find { |c| c == name }
43
43
  item
44
44
  end
45
- alias_method :[], :find_by_name
45
+ alias [] find_by_name
46
46
 
47
47
  def each
48
48
  @set.each { |i| yield i }
@@ -2,19 +2,24 @@ module ActiveScaffold::DataStructures
2
2
  # encapsulates the column sorting configuration for the List view
3
3
  class Sorting
4
4
  include Enumerable
5
+ include ActiveScaffold::OrmChecks
5
6
 
6
7
  attr_accessor :constraint_columns
7
8
  attr_accessor :sorting_by_primary_key # enabled by default for postgres
9
+ attr_reader :model
10
+ alias active_record_class model
8
11
 
9
- def initialize(columns)
12
+ def initialize(columns, model)
10
13
  @columns = columns
11
14
  @clauses = []
12
15
  @constraint_columns = []
16
+ @model = model
13
17
  end
14
18
 
15
- def set_default_sorting(model)
19
+ def set_default_sorting
20
+ return unless active_record?
16
21
  # fallback to setting primary key ordering
17
- setup_primary_key_order_clause(model)
22
+ setup_primary_key_order_clause
18
23
  model_scope = model.send(:build_default_scope)
19
24
  order_clause = model_scope.order_values.join(',') if model_scope
20
25
  return unless order_clause
@@ -34,7 +39,7 @@ module ActiveScaffold::DataStructures
34
39
  direction = direction.to_s.upcase
35
40
  column = get_column(column_name)
36
41
  raise ArgumentError, "Could not find column #{column_name}" if column.nil?
37
- raise ArgumentError, 'Sorting direction unknown' unless [:ASC, :DESC].include? direction.to_sym
42
+ raise ArgumentError, 'Sorting direction unknown' unless %i[ASC DESC].include? direction.to_sym
38
43
  @clauses << [column, direction.untaint] if column.sortable?
39
44
  raise ArgumentError, "Can't mix :method- and :sql-based sorting" if mixed_sorting?
40
45
  end
@@ -77,8 +82,8 @@ module ActiveScaffold::DataStructures
77
82
  clause[1]
78
83
  end
79
84
 
80
- SORTING_STAGES = Hash[%w(reset ASC DESC reset).each_cons(2).to_a].freeze
81
- DEFAULT_SORTING_STAGES = Hash[%w(ASC DESC ASC).each_cons(2).to_a].freeze
85
+ SORTING_STAGES = Hash[%w[reset ASC DESC reset].each_cons(2).to_a].freeze
86
+ DEFAULT_SORTING_STAGES = Hash[%w[ASC DESC ASC].each_cons(2).to_a].freeze
82
87
  def next_sorting_of(column, sorted_by_default)
83
88
  stages = sorted_by_default ? DEFAULT_SORTING_STAGES : SORTING_STAGES
84
89
  stages[direction_of(column)] || 'ASC'
@@ -103,21 +108,30 @@ module ActiveScaffold::DataStructures
103
108
  @clauses.first
104
109
  end
105
110
 
111
+ def size
112
+ @clauses.size
113
+ end
114
+
106
115
  # builds an order-by clause
107
- def clause
116
+ def clause(grouped_columns_calculations = nil)
108
117
  return nil if sorts_by_method? || default_sorting?
109
118
 
110
119
  # unless the sorting is by method, create the sql string
111
120
  order = []
112
121
  each do |sort_column, sort_direction|
113
122
  next if constraint_columns.include? sort_column.name
114
- sql = sort_column.sort[:sql]
115
- next if sql.nil? || sql.empty?
123
+ sql = grouped_columns_calculations.try(:dig, sort_column.name) || sort_column.sort[:sql]
124
+ next if sql.blank?
125
+ sql = sql.to_sql if sql.respond_to?(:to_sql)
116
126
 
117
- order << Array(sql).map { |column| "#{column} #{sort_direction}" }.join(', ')
127
+ parts = Array(sql).map do |column|
128
+ mongoid? ? [column, sort_direction] : "#{column} #{sort_direction}"
129
+ end
130
+ order << parts
118
131
  end
119
132
 
120
133
  order << @primary_key_order_clause if @sorting_by_primary_key
134
+ order.flatten!(1)
121
135
  order unless order.empty?
122
136
  end
123
137
 
@@ -149,7 +163,7 @@ module ActiveScaffold::DataStructures
149
163
  def set_sorting_from_order_clause(order_clause, model_table_name = nil)
150
164
  clear
151
165
  order_clause.to_s.split(',').each do |criterion|
152
- unless criterion.blank?
166
+ if criterion.present?
153
167
  order_parts = extract_order_parts(criterion)
154
168
  add(order_parts[:column_name], order_parts[:direction]) unless different_table?(model_table_name, order_parts[:table_name]) || get_column(order_parts[:column_name]).nil?
155
169
  end
@@ -178,22 +192,22 @@ module ActiveScaffold::DataStructures
178
192
  end
179
193
 
180
194
  def extract_direction(direction_part)
181
- if direction_part.to_s.upcase == 'DESC'
195
+ if direction_part.to_s.casecmp('DESC').zero?
182
196
  'DESC'
183
197
  else
184
198
  'ASC'
185
199
  end
186
200
  end
187
201
 
188
- def postgres?(model)
202
+ def postgres?
189
203
  model.connection.try(:adapter_name) == 'PostgreSQL'
190
204
  end
191
205
 
192
- def setup_primary_key_order_clause(model)
206
+ def setup_primary_key_order_clause
193
207
  return unless model.column_names.include?(model.primary_key)
194
208
  set([model.primary_key, 'ASC'])
195
209
  @primary_key_order_clause = clause
196
- @sorting_by_primary_key = postgres?(model) # mandatory for postgres, so enabled by default
210
+ @sorting_by_primary_key = postgres? # mandatory for postgres, so enabled by default
197
211
  end
198
212
  end
199
213
  end
@@ -34,6 +34,8 @@ module ActiveScaffold
34
34
  end
35
35
  end
36
36
 
37
- config.assets.precompile << 'active_scaffold/indicator.gif' if Rails::VERSION::MAJOR >= 4
37
+ initializer 'active_scaffold.assets' do
38
+ config.assets.precompile << 'active_scaffold/indicator.gif'
39
+ end
38
40
  end
39
41
  end
@@ -1,7 +1,7 @@
1
1
  # wrap the action rendering for ActiveScaffold controllers
2
- module ActionController #:nodoc:
3
- class Base
4
- def render_with_active_scaffold(*args, &block)
2
+ module ActiveScaffold
3
+ module ActionController #:nodoc:
4
+ def render(*args, &block)
5
5
  if self.class.uses_active_scaffold? && params[:adapter] && @rendering_adapter.nil? && request.xhr?
6
6
  @rendering_adapter = true # recursion control
7
7
  # if we need an adapter, then we render the actual stuff to a string and insert it into the adapter template
@@ -11,9 +11,14 @@ module ActionController #:nodoc:
11
11
  :use_full_path => true, :layout => false, :content_type => :html
12
12
  @rendering_adapter = nil # recursion control
13
13
  else
14
- render_without_active_scaffold(*args, &block)
14
+ super(*args, &block)
15
15
  end
16
16
  end
17
- alias_method_chain :render, :active_scaffold
17
+ end
18
+ end
19
+
20
+ module ActionController
21
+ class Base
22
+ prepend ActiveScaffold::ActionController
18
23
  end
19
24
  end
@@ -1,16 +1,15 @@
1
- module ActionView
2
- class LookupContext
1
+ module ActiveScaffold
2
+ module LookupContext
3
3
  attr_accessor :last_template
4
4
 
5
- def find_template_with_last_template(name, prefixes = [], partial = false, keys = [], options = {})
6
- self.last_template = find_template_without_last_template(name, prefixes, partial, keys, options)
5
+ def find_template(name, prefixes = [], partial = false, keys = [], options = {})
6
+ self.last_template = super(name, prefixes, partial, keys, options)
7
7
  end
8
- alias_method_chain :find_template, :last_template
9
8
  end
10
9
  end
11
10
 
12
11
  # wrap the action rendering for ActiveScaffold views
13
- module ActionView::Helpers #:nodoc:
12
+ module ActiveScaffold #:nodoc:
14
13
  module RenderingHelper
15
14
  #
16
15
  # Adds two rendering options.
@@ -34,52 +33,11 @@ module ActionView::Helpers #:nodoc:
34
33
  #
35
34
  # Defining options[:label] lets you completely customize the list title for the embedded scaffold.
36
35
  #
37
- def render_with_active_scaffold(*args, &block)
36
+ # options[:xhr] force to load embedded scaffold with AJAX even when render_component gem is installed.
37
+ #
38
+ def render(*args, &block)
38
39
  if args.first.is_a?(Hash) && args.first[:active_scaffold]
39
- require 'digest/md5'
40
- options = args.first
41
-
42
- remote_controller = options[:active_scaffold]
43
- constraints = options[:constraints]
44
- conditions = options[:conditions]
45
- eid = Digest::MD5.hexdigest(params[:controller] + remote_controller.to_s + constraints.to_s + conditions.to_s)
46
- eid_info = session["as:#{eid}"] ||= {}
47
- if constraints
48
- eid_info['constraints'] = constraints
49
- else
50
- eid_info.delete 'constraints'
51
- end
52
- if conditions
53
- eid_info['conditions'] = conditions
54
- else
55
- eid_info.delete 'conditions'
56
- end
57
- if options[:label]
58
- eid_info['list'] = {'label' => options[:label]}
59
- else
60
- eid_info.delete 'list'
61
- end
62
- session.delete "as:#{eid}" if eid_info.empty?
63
- options[:params] ||= {}
64
- options[:params].merge! :eid => eid, :embedded => true
65
-
66
- id = "as_#{eid}-embedded"
67
- url_options = {:controller => remote_controller.to_s, :action => 'index'}.merge(options[:params])
68
-
69
- if controller.respond_to?(:render_component_into_view, true)
70
- controller.send(:render_component_into_view, url_options)
71
- else
72
- url = url_for(url_options)
73
- content_tag(:div, :id => id, :class => 'active-scaffold-component', :data => {:refresh => url}) do
74
- # parse the ActiveRecord model name from the controller path, which
75
- # might be a namespaced controller (e.g., 'admin/admins')
76
- model = remote_controller.to_s.sub(/.*\//, '').singularize
77
- content_tag(:div, :class => 'active-scaffold-header') do
78
- content_tag :h2, link_to(args.first[:label] || active_scaffold_config_for(model).list.label, url, :remote => true, :class => 'load-embedded')
79
- end
80
- end
81
- end
82
-
40
+ render_embedded args.first
83
41
  elsif args.first == :super
84
42
  @_view_paths ||= lookup_context.view_paths.clone
85
43
  @_last_template ||= lookup_context.last_template
@@ -102,30 +60,78 @@ module ActionView::Helpers #:nodoc:
102
60
  last_view_path = File.expand_path(File.dirname(File.dirname(lookup_context.last_template.inspect)), Rails.root)
103
61
  lookup_context.view_paths = view_paths.drop(view_paths.find_index { |path| path.to_s == last_view_path } + 1)
104
62
  end
105
- result = render_without_active_scaffold options
63
+ result = super options
106
64
  lookup_context.view_paths = @_view_paths if @_view_paths
107
65
  lookup_context.last_template = @_last_template if @_last_template
108
66
  result
109
67
  else
110
68
  @_view_paths ||= lookup_context.view_paths.clone
111
69
  last_template = lookup_context.last_template
112
- if args[0].is_a?(Hash)
113
- current_view = {:locals => args[0][:locals], :object => args[0][:object]}
114
- else # call is render 'partial', locals_hash
115
- current_view = {:locals => args[1]}
116
- end
70
+ current_view = if args[0].is_a?(Hash)
71
+ {:locals => args[0][:locals], :object => args[0][:object]}
72
+ else # call is render 'partial', locals_hash
73
+ {:locals => args[1]}
74
+ end
117
75
  view_stack << current_view if current_view
118
76
  lookup_context.view_paths = @_view_paths # reset view_paths in case a view render :super, and then render :partial
119
- result = render_without_active_scaffold(*args, &block)
77
+ result = super
120
78
  view_stack.pop if current_view.present?
121
79
  lookup_context.last_template = last_template
122
80
  result
123
81
  end
124
82
  end
125
- alias_method_chain :render, :active_scaffold
126
83
 
127
84
  def view_stack
128
85
  @_view_stack ||= []
129
86
  end
87
+
88
+ private
89
+
90
+ def render_embedded(options)
91
+ require 'digest/md5'
92
+
93
+ remote_controller = options[:active_scaffold]
94
+ # It is important that the EID hash remains short as to not contribute
95
+ # to a large session size and thus a possible cookie overflow exception
96
+ # when using rails CookieStore or EncryptedCookieStore. For example,
97
+ # when rendering many embedded scaffolds with constraints or conditions
98
+ # on a single page.
99
+ eid = Digest::MD5.hexdigest(params[:controller] + options.to_s)
100
+ eid_info = {loading: true}
101
+ eid_info[:constraints] = options[:constraints] if options[:constraints]
102
+ eid_info[:conditions] = options[:conditions] if options[:conditions]
103
+ eid_info[:label] = options[:label] if options[:label]
104
+ options[:params] ||= {}
105
+ options[:params].merge! :eid => eid, :embedded => eid_info
106
+
107
+ id = "as_#{eid}-embedded"
108
+ url_options = {controller: remote_controller.to_s, action: 'index', id: nil}.merge(options[:params])
109
+
110
+ if controller.respond_to?(:render_component_into_view, true) && !options[:xhr]
111
+ controller.send(:render_component_into_view, url_options)
112
+ else
113
+ url = url_for(url_options)
114
+ content_tag(:div, :id => id, :class => 'active-scaffold-component', :data => {:refresh => url}) do
115
+ # parse the ActiveRecord model name from the controller path, which
116
+ # might be a namespaced controller (e.g., 'admin/admins')
117
+ model = remote_controller.to_s.sub(/.*\//, '').singularize
118
+ content_tag(:div, :class => 'active-scaffold-header') do
119
+ content_tag :h2, link_to(options[:label] || active_scaffold_config_for(model).list.label, url, :remote => true, :class => 'load-embedded')
120
+ end
121
+ end
122
+ end
123
+ end
124
+ end
125
+ end
126
+
127
+ module ActionView
128
+ LookupContext.class_eval do
129
+ prepend ActiveScaffold::LookupContext
130
+ end
131
+
132
+ module Helpers
133
+ Base.class_eval do
134
+ include ActiveScaffold::RenderingHelper
135
+ end
130
136
  end
131
137
  end