active_scaffold 3.3.3 → 3.4.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 (198) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG +39 -0
  3. data/README.md +5 -3
  4. data/app/assets/images/active_scaffold/refresh.png +0 -0
  5. data/app/assets/javascripts/jquery/active_scaffold.js +182 -91
  6. data/app/assets/javascripts/jquery/date_picker_bridge.js.erb +14 -16
  7. data/app/assets/javascripts/jquery/draggable_lists.js +33 -26
  8. data/app/assets/javascripts/jquery/jquery.editinplace.js +3 -3
  9. data/app/assets/javascripts/prototype/active_scaffold.js +61 -19
  10. data/app/assets/stylesheets/active_scaffold_colors.css.scss +4 -0
  11. data/app/assets/stylesheets/active_scaffold_images.css.scss +3 -0
  12. data/app/assets/stylesheets/active_scaffold_layout.css +23 -2
  13. data/app/views/active_scaffold_overrides/_add_existing_form.html.erb +1 -3
  14. data/app/views/active_scaffold_overrides/_base_form.html.erb +7 -5
  15. data/app/views/active_scaffold_overrides/_field_search.html.erb +1 -2
  16. data/app/views/active_scaffold_overrides/_form.html.erb +6 -4
  17. data/app/views/active_scaffold_overrides/_form_association.html.erb +4 -3
  18. data/app/views/active_scaffold_overrides/_form_association_footer.html.erb +5 -5
  19. data/app/views/active_scaffold_overrides/_form_association_record.html.erb +8 -6
  20. data/app/views/active_scaffold_overrides/_horizontal_subform_header.html.erb +3 -2
  21. data/app/views/active_scaffold_overrides/_list.html.erb +8 -6
  22. data/app/views/active_scaffold_overrides/_list_column_headings.html.erb +1 -4
  23. data/app/views/active_scaffold_overrides/_list_pagination.html.erb +4 -4
  24. data/app/views/active_scaffold_overrides/_list_pagination_links.html.erb +1 -1
  25. data/app/views/active_scaffold_overrides/_list_record.html.erb +3 -3
  26. data/app/views/active_scaffold_overrides/_refresh_list.js.erb +8 -1
  27. data/app/views/active_scaffold_overrides/_search.html.erb +7 -13
  28. data/app/views/active_scaffold_overrides/_show_columns.html.erb +1 -1
  29. data/app/views/active_scaffold_overrides/on_create.js.erb +4 -4
  30. data/app/views/active_scaffold_overrides/render_field_inplace.html.erb +1 -1
  31. data/app/views/active_scaffold_overrides/row.js.erb +1 -1
  32. data/config/locales/de.yml +106 -95
  33. data/config/locales/en.yml +108 -97
  34. data/config/locales/es.yml +109 -98
  35. data/config/locales/fr.yml +108 -97
  36. data/config/locales/hu.yml +109 -98
  37. data/config/locales/ja.yml +100 -89
  38. data/config/locales/ru.yml +115 -104
  39. data/lib/active_scaffold.rb +18 -294
  40. data/lib/active_scaffold/actions/common_search.rb +50 -17
  41. data/lib/active_scaffold/actions/core.rb +93 -22
  42. data/lib/active_scaffold/actions/create.rb +15 -6
  43. data/lib/active_scaffold/actions/field_search.rb +68 -60
  44. data/lib/active_scaffold/actions/list.rb +49 -28
  45. data/lib/active_scaffold/actions/nested.rb +14 -6
  46. data/lib/active_scaffold/actions/search.rb +36 -35
  47. data/lib/active_scaffold/actions/show.rb +9 -4
  48. data/lib/active_scaffold/actions/subform.rb +1 -1
  49. data/lib/active_scaffold/actions/update.rb +22 -7
  50. data/lib/active_scaffold/active_record_permissions.rb +125 -118
  51. data/lib/active_scaffold/attribute_params.rb +84 -66
  52. data/lib/active_scaffold/bridges.rb +3 -3
  53. data/lib/active_scaffold/bridges/ancestry/ancestry_bridge.rb +10 -5
  54. data/lib/active_scaffold/bridges/cancan.rb +2 -1
  55. data/lib/active_scaffold/bridges/cancan/cancan_bridge.rb +13 -2
  56. data/lib/active_scaffold/bridges/carrierwave/form_ui.rb +11 -6
  57. data/lib/active_scaffold/bridges/chosen/helpers.rb +2 -2
  58. data/lib/active_scaffold/bridges/country_helper/country_helper_bridge.rb +45 -29
  59. data/lib/active_scaffold/bridges/date_picker/ext.rb +11 -6
  60. data/lib/active_scaffold/bridges/date_picker/helper.rb +5 -1
  61. data/lib/active_scaffold/bridges/dragonfly/form_ui.rb +10 -5
  62. data/lib/active_scaffold/bridges/dragonfly/list_ui.rb +6 -1
  63. data/lib/active_scaffold/bridges/file_column/form_ui.rb +12 -11
  64. data/lib/active_scaffold/bridges/paperclip/form_ui.rb +14 -6
  65. data/lib/active_scaffold/bridges/paperclip/list_ui.rb +1 -1
  66. data/lib/active_scaffold/bridges/record_select/helpers.rb +15 -12
  67. data/lib/active_scaffold/bridges/shared/date_bridge.rb +7 -8
  68. data/lib/active_scaffold/bridges/tiny_mce.rb +5 -3
  69. data/lib/active_scaffold/bridges/tiny_mce/helpers.rb +4 -5
  70. data/lib/active_scaffold/config/base.rb +4 -0
  71. data/lib/active_scaffold/config/core.rb +12 -5
  72. data/lib/active_scaffold/config/delete.rb +0 -2
  73. data/lib/active_scaffold/config/field_search.rb +1 -4
  74. data/lib/active_scaffold/config/form.rb +0 -2
  75. data/lib/active_scaffold/config/list.rb +31 -1
  76. data/lib/active_scaffold/config/search.rb +0 -3
  77. data/lib/active_scaffold/config/show.rb +0 -6
  78. data/lib/active_scaffold/config/subform.rb +1 -0
  79. data/lib/active_scaffold/configurable.rb +2 -2
  80. data/lib/active_scaffold/constraints.rb +11 -14
  81. data/lib/active_scaffold/core.rb +277 -0
  82. data/lib/active_scaffold/data_structures/action_columns.rb +18 -2
  83. data/lib/active_scaffold/data_structures/action_link.rb +25 -6
  84. data/lib/active_scaffold/data_structures/action_links.rb +9 -4
  85. data/lib/active_scaffold/data_structures/actions.rb +1 -1
  86. data/lib/active_scaffold/data_structures/column.rb +6 -6
  87. data/lib/active_scaffold/data_structures/columns.rb +2 -2
  88. data/lib/active_scaffold/data_structures/nested_info.rb +5 -1
  89. data/lib/active_scaffold/data_structures/sorting.rb +15 -5
  90. data/lib/active_scaffold/delayed_setup.rb +30 -0
  91. data/lib/active_scaffold/engine.rb +25 -0
  92. data/lib/active_scaffold/extensions/action_view_rendering.rb +1 -1
  93. data/lib/active_scaffold/extensions/left_outer_joins.rb +61 -21
  94. data/lib/active_scaffold/extensions/localize.rb +1 -1
  95. data/lib/active_scaffold/extensions/name_option_for_datetime.rb +13 -8
  96. data/lib/active_scaffold/extensions/paginator_extensions.rb +5 -1
  97. data/lib/active_scaffold/extensions/reverse_associations.rb +1 -0
  98. data/lib/active_scaffold/extensions/routing_mapper.rb +1 -1
  99. data/lib/active_scaffold/extensions/unsaved_record.rb +4 -6
  100. data/lib/active_scaffold/finder.rb +79 -27
  101. data/lib/active_scaffold/helpers/association_helpers.rb +48 -18
  102. data/lib/active_scaffold/helpers/controller_helpers.rb +19 -10
  103. data/lib/active_scaffold/helpers/form_column_helpers.rb +185 -87
  104. data/lib/active_scaffold/helpers/human_condition_helpers.rb +2 -1
  105. data/lib/active_scaffold/helpers/id_helpers.rb +14 -8
  106. data/lib/active_scaffold/helpers/list_column_helpers.rb +65 -56
  107. data/lib/active_scaffold/helpers/pagination_helpers.rb +5 -1
  108. data/lib/active_scaffold/helpers/search_column_helpers.rb +21 -18
  109. data/lib/active_scaffold/helpers/view_helpers.rb +102 -64
  110. data/lib/active_scaffold/responds_to_parent.rb +39 -64
  111. data/lib/active_scaffold/tableless.rb +129 -10
  112. data/lib/active_scaffold/version.rb +2 -2
  113. data/test/bridges/bridge_test.rb +1 -1
  114. data/test/bridges/date_picker_test.rb +2 -2
  115. data/test/bridges/paperclip_test.rb +10 -8
  116. data/test/bridges/tiny_mce_test.rb +2 -2
  117. data/test/company.rb +22 -10
  118. data/test/config/base_test.rb +1 -1
  119. data/test/config/core_test.rb +8 -6
  120. data/test/config/create_test.rb +6 -6
  121. data/test/config/delete_test.rb +4 -4
  122. data/test/config/field_search_test.rb +6 -6
  123. data/test/config/list_test.rb +7 -7
  124. data/test/config/nested_test.rb +8 -7
  125. data/test/config/search_test.rb +7 -7
  126. data/test/config/show_test.rb +5 -5
  127. data/test/config/subform_test.rb +1 -1
  128. data/test/config/update_test.rb +5 -4
  129. data/test/data_structures/action_columns_test.rb +15 -16
  130. data/test/data_structures/action_link_test.rb +10 -10
  131. data/test/data_structures/action_links_test.rb +6 -6
  132. data/test/data_structures/actions_test.rb +4 -4
  133. data/test/data_structures/association_column_test.rb +4 -4
  134. data/test/data_structures/column_test.rb +9 -9
  135. data/test/data_structures/columns_test.rb +7 -7
  136. data/test/data_structures/error_message_test.rb +2 -4
  137. data/test/data_structures/set_test.rb +13 -13
  138. data/test/data_structures/sorting_test.rb +8 -8
  139. data/test/data_structures/standard_column_test.rb +2 -2
  140. data/test/data_structures/validation_reflection_test.rb +8 -8
  141. data/test/data_structures/virtual_column_test.rb +5 -5
  142. data/test/extensions/active_record_test.rb +1 -1
  143. data/test/helpers/form_column_helpers_test.rb +5 -5
  144. data/test/helpers/list_column_helpers_test.rb +2 -1
  145. data/test/helpers/pagination_helpers_test.rb +1 -1
  146. data/test/misc/active_record_permissions_test.rb +23 -4
  147. data/test/misc/attribute_params_test.rb +304 -136
  148. data/test/misc/calculation_test.rb +55 -0
  149. data/test/misc/configurable_test.rb +22 -21
  150. data/test/misc/constraints_test.rb +10 -7
  151. data/test/misc/convert_numbers_format_test.rb +149 -0
  152. data/test/misc/finder_test.rb +17 -13
  153. data/test/misc/lang_test.rb +1 -1
  154. data/test/misc/tableless_test.rb +18 -0
  155. data/test/mock_app/app/controllers/addresses_controller.rb +4 -0
  156. data/test/mock_app/app/controllers/buildings_controller.rb +4 -0
  157. data/test/mock_app/app/controllers/cars_controller.rb +4 -0
  158. data/test/mock_app/app/controllers/contacts_controller.rb +4 -0
  159. data/test/mock_app/app/controllers/floors_controller.rb +6 -0
  160. data/test/mock_app/app/controllers/people_controller.rb +4 -0
  161. data/test/mock_app/app/models/address.rb +3 -0
  162. data/test/mock_app/app/models/building.rb +8 -0
  163. data/test/mock_app/app/models/car.rb +3 -0
  164. data/test/mock_app/app/models/contact.rb +3 -0
  165. data/test/mock_app/app/models/file_model.rb +19 -0
  166. data/test/mock_app/app/models/floor.rb +8 -0
  167. data/test/mock_app/app/models/person.rb +11 -0
  168. data/test/mock_app/config/application.rb +2 -0
  169. data/test/mock_app/config/environments/test.rb +1 -1
  170. data/test/mock_app/config/initializers/secret_token.rb +5 -1
  171. data/test/mock_app/config/routes.rb +1 -1
  172. data/test/mock_app/db/schema.rb +51 -0
  173. data/test/model_stub.rb +3 -3
  174. data/test/test_helper.rb +15 -12
  175. metadata +51 -50
  176. data/lib/active_scaffold/extensions/array.rb +0 -7
  177. data/lib/active_scaffold/extensions/cache_association.rb +0 -16
  178. data/lib/active_scaffold/extensions/usa_state.rb +0 -46
  179. data/lib/active_scaffold_env.rb +0 -13
  180. data/test/extensions/array_test.rb +0 -12
  181. data/test/mock_app/public/blank.html +0 -33
  182. data/test/mock_app/public/images/active_scaffold/DO_NOT_EDIT +0 -2
  183. data/test/mock_app/public/images/active_scaffold/default/add.gif +0 -0
  184. data/test/mock_app/public/images/active_scaffold/default/arrow_down.gif +0 -0
  185. data/test/mock_app/public/images/active_scaffold/default/arrow_up.gif +0 -0
  186. data/test/mock_app/public/images/active_scaffold/default/close.gif +0 -0
  187. data/test/mock_app/public/images/active_scaffold/default/cross.png +0 -0
  188. data/test/mock_app/public/images/active_scaffold/default/indicator-small.gif +0 -0
  189. data/test/mock_app/public/images/active_scaffold/default/indicator.gif +0 -0
  190. data/test/mock_app/public/images/active_scaffold/default/magnifier.png +0 -0
  191. data/test/mock_app/public/javascripts/active_scaffold/DO_NOT_EDIT +0 -2
  192. data/test/mock_app/public/javascripts/active_scaffold/default/active_scaffold.js +0 -532
  193. data/test/mock_app/public/javascripts/active_scaffold/default/dhtml_history.js +0 -867
  194. data/test/mock_app/public/javascripts/active_scaffold/default/form_enhancements.js +0 -117
  195. data/test/mock_app/public/javascripts/active_scaffold/default/rico_corner.js +0 -370
  196. data/test/mock_app/public/stylesheets/active_scaffold/DO_NOT_EDIT +0 -2
  197. data/test/mock_app/public/stylesheets/active_scaffold/default/stylesheet-ie.css +0 -35
  198. data/test/mock_app/public/stylesheets/active_scaffold/default/stylesheet.css +0 -848
@@ -1,6 +1,6 @@
1
1
  require 'test_helper'
2
2
 
3
- class ActiveRecordTest < Test::Unit::TestCase
3
+ class ActiveRecordTest < MiniTest::Test
4
4
  def setup
5
5
  @record = ModelStub.new
6
6
  end
@@ -10,22 +10,22 @@ class FormColumnHelpersTest < ActionView::TestCase
10
10
 
11
11
  def test_choices_for_select_form_ui_for_simple_column
12
12
  @column.options[:options] = [:value_1, :value_2, :value_3]
13
- assert_dom_equal "<select name=\"record[a]\" id=\"record_a\"><option value=\"value_1\">Value 1</option>\n<option value=\"value_2\">Value 2</option>\n<option value=\"value_3\">Value 3</option></select>", active_scaffold_input_select(@column, {})
13
+ assert_dom_equal "<select name=\"record[a]\" id=\"record_a\"><option value=\"value_1\">Value 1</option>\n<option value=\"value_2\">Value 2</option>\n<option value=\"value_3\">Value 3</option></select>", active_scaffold_input_select(@column, :object => @record)
14
14
 
15
15
  @column.options[:options] = %w(value_1 value_2 value_3)
16
- assert_dom_equal "<select name=\"record[a]\" id=\"record_a\"><option value=\"value_1\">value_1</option>\n<option value=\"value_2\">value_2</option>\n<option value=\"value_3\">value_3</option></select>", active_scaffold_input_select(@column, {})
16
+ assert_dom_equal "<select name=\"record[a]\" id=\"record_a\"><option value=\"value_1\">value_1</option>\n<option value=\"value_2\">value_2</option>\n<option value=\"value_3\">value_3</option></select>", active_scaffold_input_select(@column, :object => @record)
17
17
 
18
18
  @column.options[:options] = [%w(text_1 value_1), %w(text_2 value_2), %w(text_3 value_3)]
19
- assert_dom_equal "<select name=\"record[a]\" id=\"record_a\"><option value=\"value_1\">text_1</option>\n<option value=\"value_2\">text_2</option>\n<option value=\"value_3\">text_3</option></select>", active_scaffold_input_select(@column, {})
19
+ assert_dom_equal "<select name=\"record[a]\" id=\"record_a\"><option value=\"value_1\">text_1</option>\n<option value=\"value_2\">text_2</option>\n<option value=\"value_3\">text_3</option></select>", active_scaffold_input_select(@column, :object => @record)
20
20
 
21
21
  @column.options[:options] = [[:text_1, :value_1], [:text_2, :value_2], [:text_3, :value_3]]
22
- assert_dom_equal "<select name=\"record[a]\" id=\"record_a\"><option value=\"value_1\">Text 1</option>\n<option value=\"value_2\">Text 2</option>\n<option value=\"value_3\">Text 3</option></select>", active_scaffold_input_select(@column, {})
22
+ assert_dom_equal "<select name=\"record[a]\" id=\"record_a\"><option value=\"value_1\">Text 1</option>\n<option value=\"value_2\">Text 2</option>\n<option value=\"value_3\">Text 3</option></select>", active_scaffold_input_select(@column, :object => @record)
23
23
  end
24
24
 
25
25
  def test_options_for_select_form_ui_for_simple_column
26
26
  @column.options = {:include_blank => 'None', :selected => 'value_2', :disabled => %w(value_1 value_3)}
27
27
  @column.options[:options] = %w(value_1 value_2 value_3)
28
28
  @column.options[:html_options] = {:class => 'big'}
29
- assert_dom_equal "<select name=\"record[a]\" class=\"big\" id=\"record_a\"><option value=\"\">None</option>\n<option disabled=\"disabled\" value=\"value_1\">value_1</option>\n<option selected=\"selected\" value=\"value_2\">value_2</option>\n<option disabled=\"disabled\" value=\"value_3\">value_3</option></select>", active_scaffold_input_select(@column, {})
29
+ assert_dom_equal "<select name=\"record[a]\" class=\"big\" id=\"record_a\"><option value=\"\">None</option>\n<option disabled=\"disabled\" value=\"value_1\">value_1</option>\n<option selected=\"selected\" value=\"value_2\">value_2</option>\n<option disabled=\"disabled\" value=\"value_3\">value_3</option></select>", active_scaffold_input_select(@column, :object => @record)
30
30
  end
31
31
  end
@@ -1,3 +1,4 @@
1
+ #encoding: utf-8
1
2
  require 'test_helper'
2
3
 
3
4
  class ListColumnHelpersTest < ActionView::TestCase
@@ -11,7 +12,7 @@ class ListColumnHelpersTest < ActionView::TestCase
11
12
  @record = stub(:a => 'value_2')
12
13
  @config = stub(:list => stub(:empty_field_text => '-', :association_join_text => ', '))
13
14
  @association_column = ActiveScaffold::DataStructures::Column.new(:b, ModelStub)
14
- @association_column.stubs(:association).returns(stub(:macro => :has_many))
15
+ @association_column.stubs(:association).returns(stub(:collection? => true))
15
16
  end
16
17
 
17
18
  def test_options_for_select_list_ui_for_simple_column
@@ -1,6 +1,6 @@
1
1
  require 'test_helper'
2
2
 
3
- class PaginationHelpersTest < Test::Unit::TestCase
3
+ class PaginationHelpersTest < MiniTest::Test
4
4
  include ActiveScaffold::Helpers::PaginationHelpers
5
5
 
6
6
  def active_scaffold_config
@@ -1,7 +1,10 @@
1
1
  require 'test_helper'
2
2
 
3
3
  class PermissionModel < ActiveRecord::Base
4
+ include ActiveScaffold::ActiveRecordPermissions::ModelUserAccess::Model
4
5
  def self.columns; [] end
6
+ def self.column_types; [] end
7
+ def self.columns_hash; {} end
5
8
 
6
9
  def authorized_for_read?; true; end
7
10
  def authorized_for_update?; false; end
@@ -50,7 +53,7 @@ class PermissionModel < ActiveRecord::Base
50
53
  #def c1_authorized_for_update?; end
51
54
  end
52
55
 
53
- class ActiveRecordPermissionsTest < Test::Unit::TestCase
56
+ class ActiveRecordPermissionsTest < MiniTest::Test
54
57
  def setup
55
58
  @model = PermissionModel.new
56
59
  end
@@ -59,7 +62,11 @@ class ActiveRecordPermissionsTest < Test::Unit::TestCase
59
62
  # columns are: crud_type method, column method, crud_type/column method
60
63
  # symbols are: is (a)bsent, returns (f)alse, returns (t)rue, or n/a (_)
61
64
  def test_method_combinations_with_default_true
62
- ActiveRecordPermissions.default_permission = true
65
+ old_permission = nil
66
+ ActiveScaffold.set_defaults do |config|
67
+ old_permission = config.security.default_permission
68
+ config.security.default_permission = true
69
+ end
63
70
 
64
71
  pass(@model.authorized_for?(:column => :a3), '_a_')
65
72
  fail(@model.authorized_for?(:column => :a2), '_f_')
@@ -98,10 +105,18 @@ class ActiveRecordPermissionsTest < Test::Unit::TestCase
98
105
  pass(@model.authorized_for?(:crud_type => :read, :column => :c1), 'tta')
99
106
  fail(@model.authorized_for?(:crud_type => :read, :column => :b1), 'ttf')
100
107
  pass(@model.authorized_for?(:crud_type => :read, :column => :a1), 'ttt')
108
+
109
+ ActiveScaffold.set_defaults do |config|
110
+ config.security.default_permission = old_permission
111
+ end
101
112
  end
102
113
 
103
114
  def test_method_combinations_with_default_false
104
- ActiveRecordPermissions.default_permission = false
115
+ old_permission = nil
116
+ ActiveScaffold.set_defaults do |config|
117
+ old_permission = config.security.default_permission
118
+ config.security.default_permission = false
119
+ end
105
120
 
106
121
  fail(@model.authorized_for?(:column => :a3), '_a_')
107
122
  fail(@model.authorized_for?(:column => :a2), '_f_')
@@ -140,6 +155,10 @@ class ActiveRecordPermissionsTest < Test::Unit::TestCase
140
155
  pass(@model.authorized_for?(:crud_type => :read, :column => :c1), 'tta')
141
156
  fail(@model.authorized_for?(:crud_type => :read, :column => :b1), 'ttf')
142
157
  pass(@model.authorized_for?(:crud_type => :read, :column => :a1), 'ttt')
158
+
159
+ ActiveScaffold.set_defaults do |config|
160
+ config.security.default_permission = old_permission
161
+ end
143
162
  end
144
163
 
145
164
  private
@@ -149,6 +168,6 @@ class ActiveRecordPermissionsTest < Test::Unit::TestCase
149
168
  end
150
169
 
151
170
  def fail(value, message = nil)
152
- assert !value, "#{message} should fail"
171
+ refute value, "#{message} should fail"
153
172
  end
154
173
  end
@@ -1,145 +1,313 @@
1
1
  require 'test_helper'
2
2
 
3
- class NumberModel < ActiveRecord::Base
4
- abstract_class = true
5
- def self.columns
6
- @columns ||= [ActiveRecord::ConnectionAdapters::Column.new('number', '', 'double(10,2)')]
3
+ class AttributeParamsTest < MiniTest::Test
4
+ def setup
5
+ @controller = Controller.new
6
+ end
7
+
8
+ def test_saving_simple_record
9
+ model = update_record_from_params(Person.new, :create, :first_name, :last_name, :first_name => 'First', :last_name => '')
10
+ assert_equal 'First', model.first_name
11
+ assert_nil model.last_name
12
+ assert model.buildings.blank?
13
+ assert model.save
14
+
15
+ model.buildings.create(:name => '1st building')
16
+ model = update_record_from_params(model, :update, :first_name, :last_name, :first_name => 'Name', :last_name => 'Last')
17
+ assert_equal 'Name', model.first_name
18
+ assert_equal 'Last', model.last_name
19
+ assert model.buildings.present?, 'buildings should not be cleared'
20
+ assert model.save
21
+ end
22
+
23
+ def test_saving_unexpected_column_is_ignored
24
+ model = Person.new(:first_name => 'First', :last_name => 'Last')
25
+ model.buildings.build(:name => '1st building')
26
+ assert model.save
27
+
28
+ model = update_record_from_params(model, :update, :first_name, :first_name => 'Name', :last_name => 'Surname')
29
+ assert_equal 'Name', model.first_name
30
+ assert_equal 'Last', model.last_name
31
+ assert model.buildings.present?, 'buildings should not be cleared'
32
+ assert model.save
33
+ end
34
+
35
+ def test_saving_multiparameter_attribute
36
+ model = update_record_from_params(Contact.new, :update, :first_name, :birthday, :first_name => 'Christopher', :last_name => 'Columbus', 'birthday(1i)' => '1451', 'birthday(2i)' => '10', 'birthday(3i)' => '31')
37
+ assert_equal 'Christopher', model.first_name
38
+ assert_equal Date.new(1451, 10, 31), model.birthday
39
+ end
40
+
41
+ def test_saving_has_many_select
42
+ buildings = 2.times.map { Building.create }
43
+ model = update_record_from_params(Person.new, :create, :first_name, :last_name, :buildings, :first_name => 'First', :last_name => '', :buildings => ['', *buildings.map{|b| b.id.to_s}]) # checkbox_list always add a hidden tag with empty value
44
+ assert_equal 'First', model.first_name
45
+ assert_nil model.last_name
46
+ assert_equal buildings.map(&:id), model.building_ids
47
+ assert_equal buildings, model.buildings
48
+ assert model.save
49
+
50
+ model = update_record_from_params(model, :update, :first_name, :last_name, :buildings, :first_name => 'Name', :last_name => 'Last', :buildings => ['']) { raise ActiveRecord::Rollback }
51
+ assert_equal 'Name', model.first_name
52
+ assert_equal 'Last', model.last_name
53
+ assert_equal [model.id]*2, buildings.map{|b| b.reload.owner_id}, 'owners should not be saved'
54
+ assert model.building_ids.blank?, 'buildings should be cleared'
55
+ assert model.buildings.blank?, 'buildings should be cleared'
56
+
57
+ model.reload
58
+ model = update_record_from_params(model, :update, :first_name, :last_name, :buildings, :first_name => 'Name', :last_name => 'Last', :buildings => [''])
59
+ assert_equal 'Name', model.first_name
60
+ assert_equal 'Last', model.last_name
61
+ assert model.building_ids.blank?, 'buildings should be cleared'
62
+ assert model.buildings.blank?, 'buildings should be cleared'
63
+ assert_equal [nil]*2, buildings.map{|b| b.reload.owner_id}, 'buildings should be saved'
64
+ assert model.save
65
+ end
66
+
67
+ def test_saving_belongs_to_select
68
+ person = Person.create
69
+ assert person.persisted?
70
+
71
+ model = update_record_from_params(Floor.new, :create, :number, :tenant, :number => '1', :tenant => person.id.to_s)
72
+ assert_equal 1, model.number
73
+ assert_equal person.id, model.tenant_id
74
+ assert_equal person, model.tenant
75
+ assert model.save
76
+
77
+ model = update_record_from_params(model, :update, :number, :tenant, :number => '1', :tenant => '')
78
+ assert_equal 1, model.number
79
+ assert_nil model.tenant_id, 'tenant should be cleared'
80
+ assert_nil model.tenant, 'tenant should be cleared'
81
+ assert_equal person.id, Floor.find(model).tenant_id, 'floor should not be saved yet'
82
+ assert model.save
83
+ assert_nil Floor.find(model).tenant_id, 'floor should not be saved'
84
+ end
85
+
86
+ def test_saving_has_one_select
87
+ floor = Floor.create
88
+ assert floor.persisted?
89
+
90
+ model = update_record_from_params(Person.new, :create, :first_name, :floor, :first_name => 'Name', :floor => floor.id.to_s)
91
+ assert_equal 'Name', model.first_name
92
+ assert model.floor.present?
93
+ assert_equal floor.id, model.floor.id
94
+ assert_nil floor.reload.tenant_id, 'tenant_id should not be saved yet'
95
+ assert model.save
96
+ assert_equal model.id, floor.reload.tenant_id, 'tenant_id should be saved'
97
+
98
+ model = update_record_from_params(model, :update, :first_name, :floor, :first_name => 'First', :floor => '') { raise ActiveRecord::Rollback }
99
+ assert_equal 'First', model.first_name
100
+ assert_equal model.id, floor.reload.tenant_id, 'previous car should not be saved and nullified'
101
+ assert_nil model.floor, 'floor should be cleared'
102
+
103
+ model.reload
104
+ model = update_record_from_params(model, :update, :first_name, :floor, :first_name => 'First', :floor => '')
105
+ assert_equal 'First', model.first_name
106
+ assert_nil floor.reload.tenant_id, 'previous car should be saved and nullified'
107
+ assert_nil model.floor, 'floor should be cleared'
108
+ assert model.save
109
+ end
110
+
111
+ def test_saving_has_one_through_select
112
+ building = Building.create
113
+ assert building.persisted?
114
+ assert building.floors.create(:number => 2)
115
+
116
+ model = update_record_from_params(Person.new, :create, :first_name, :home, :first_name => 'Name', :home => building.id.to_s)
117
+ assert_equal 'Name', model.first_name
118
+ assert model.home.present?
119
+ assert model.floor.present?
120
+ assert_equal [nil], building.floors(true).map(&:tenant_id), 'floor should not be saved yet'
121
+ assert model.save
122
+ assert_equal model.id, model.floor.tenant_id, 'tenant_id should be saved'
123
+ assert_equal [nil, model.id], building.floors(true).map(&:tenant_id)
124
+
125
+ model = update_record_from_params(model, :update, :first_name, :home, :first_name => 'First', :home => '') { raise ActiveRecord::Rollback }
126
+ assert_equal 'First', model.first_name
127
+ assert_equal [nil, model.id], building.floors(true).map(&:tenant_id), 'previous floor should not be deleted'
128
+ assert_nil model.home, 'home should be cleared'
129
+
130
+ model.reload
131
+ model = update_record_from_params(model, :update, :first_name, :home, :first_name => 'First', :home => '')
132
+ assert_equal 'First', model.first_name
133
+ assert_equal [nil], building.floors(true).map(&:tenant_id), 'previous floor should be deleted'
134
+ assert_nil model.home, 'home should be cleared'
135
+ assert model.save
136
+ end
137
+
138
+ def test_saving_has_many_through_select
139
+ people = 2.times.map { Person.create }
140
+ assert people.all?(&:persisted?)
141
+
142
+ model = update_record_from_params(Building.new, :create, :name, :tenants, :name => 'Tower', :tenants => ['', *people.map{|b| b.id.to_s}]) # checkbox_list always add a hidden tag with empty value
143
+ assert_equal 'Tower', model.name
144
+ assert model.tenants.present?
145
+ assert_equal [nil]*2, people.map {|p| p.floor(true)}, 'floor should not be saved yet'
146
+ assert model.save
147
+ assert_equal [model.id]*2, model.floors.map(&:building_id)
148
+ assert_equal [model.id]*2, people.map {|p| p.floor(true).building_id}, 'floor should be saved'
149
+
150
+ model = update_record_from_params(model, :update, :name, :tenants, :name => 'Skyscrapper', :tenants => ['']) { raise ActiveRecord::Rollback }
151
+ assert_equal 'Skyscrapper', model.name
152
+ assert_equal [model.id]*2, people.map {|p| p.floor(true).building_id}, 'previous floor should not be deleted'
153
+ assert model.tenants.empty?, 'tenants should be cleared'
154
+
155
+ model.reload
156
+ model = update_record_from_params(model, :update, :name, :tenants, :name => 'Skyscrapper', :tenants => [''])
157
+ assert_equal 'Skyscrapper', model.name
158
+ assert_equal [nil]*2, people.map {|p| p.floor(true)}, 'previous floor should be deleted'
159
+ assert model.tenants.empty?, 'tenants should be cleared'
160
+ assert model.save
161
+ end
162
+
163
+ def test_saving_has_many_crud_with_error
164
+ building = Building.create(:name => 'First')
165
+ key = Time.now.to_i.to_s
166
+ floors = {'0' => '', key => {:number => '', 'tenant' => '', :number_required => true}}
167
+ model = update_record_from_params(building, :create, :name, :floors, :name => 'First', :floors => floors)
168
+ assert_equal 'First', model.name
169
+ assert_equal 1, model.floors.size
170
+ assert model.floors.first.errors.present?
171
+ refute model.floors.first.persisted?
172
+ end
173
+
174
+ def test_saving_has_many_crud_and_belongs_to_select
175
+ floor = Floor.create
176
+ people = 2.times.map { Person.create }
177
+ key = Time.now.to_i.to_s
178
+ floors = {'0' => '', '1' => {:number => '1', :tenant => '', :id => floor.id.to_s}, key => {:number => '2', 'tenant' => people.first.id.to_s}, key.succ => {:number => '4', 'tenant' => people.last.id.to_s}}
179
+ model = update_record_from_params(Building.new, :create, :name, :floors, :name => 'First', :floors => floors)
180
+ assert_equal 'First', model.name
181
+ assert_equal 3, model.floors.size
182
+ assert_equal floor.id, model.floors.first.id
183
+ assert_equal [nil, *people.map(&:id)], model.floors.map(&:tenant_id)
184
+ assert model.save
185
+
186
+ model = update_record_from_params(model, :update, :name, :floors, :name => 'Tower', :floors => {'0' => ''})
187
+ assert_equal 'Tower', model.name
188
+ assert model.floors.blank?, 'floors should be cleared'
189
+ assert model.save
190
+ end
191
+
192
+ def test_saving_belongs_to_crud
193
+ person = Person.create
194
+ assert person.persisted?
195
+
196
+ model = update_record_from_params(Car.new, :create, :brand, :person, :brand => 'Ford', :person => {:first_name => 'First'})
197
+ assert_equal 'Ford', model.brand
198
+ assert model.person.present?
199
+ assert model.person.new_record?
200
+ assert model.save
201
+ assert model.person.persisted?
202
+
203
+ model = update_record_from_params(model, :update, :brand, :person, :brand => 'Ford', :person => {:first_name => 'First', :id => person.id.to_s})
204
+ assert_equal 'Ford', model.brand
205
+ assert model.person.present?
206
+ assert_equal person.id, model.person.id
207
+ assert model.save
208
+
209
+ model = update_record_from_params(model, :update, :brand, :person, :brand => 'Mercedes', :person => {:first_name => ''})
210
+ assert_equal 'Mercedes', model.brand
211
+ assert model.person.blank?, 'person should be cleared'
212
+ assert model.save
213
+ end
214
+
215
+ def test_saving_has_one_crud
216
+ car = Car.create :brand => 'Renault'
217
+ assert car.persisted?
218
+
219
+ model = update_record_from_params(Person.new, :create, :first_name, :car, :first_name => 'First', :car => {:brand => 'Ford'})
220
+ assert_equal 'First', model.first_name
221
+ assert model.car.present?
222
+ assert model.car.new_record?
223
+ assert model.save
224
+ assert model.car.persisted?
225
+
226
+ model = update_record_from_params(Person.new, :create, :first_name, :car, :first_name => 'First', :car => {:brand => 'Peugeot', :id => car.id.to_s})
227
+ assert_equal 'First', model.first_name
228
+ assert model.car.present?
229
+ assert_equal car.id, model.car.id
230
+ assert_nil car.reload.person_id, 'person_id should not be saved yet'
231
+ assert_equal 'Peugeot', model.car.brand
232
+ assert_equal 'Renault', car.reload.brand, 'brand should not be saved yet'
233
+ assert model.save
234
+ assert_equal model.id, car.reload.person_id, 'person_id should be saved'
235
+
236
+ model = update_record_from_params(model, :update, :first_name, :car, :first_name => 'First', :car => {:brand => 'Mercedes', :id => car.id.to_s})
237
+ assert_equal 'First', model.first_name
238
+ assert model.car.present?
239
+ assert_equal 'Mercedes', model.car.brand
240
+ assert model.save
241
+ assert model.save_associated
242
+ assert_equal 'Mercedes', car.reload.brand, 'brand should be saved'
243
+
244
+ model = update_record_from_params(model, :update, :first_name, :car, :first_name => 'First', :car => {:brand => 'Mercedes'})
245
+ assert_equal 'First', model.first_name
246
+ assert_nil Car.where(:id => car.id).first, 'previous car should be deleted'
247
+ assert model.car.present?
248
+ refute_equal car.id, model.car.id
249
+ assert model.save
250
+
251
+ car = model.car.reload
252
+ model = update_record_from_params(model, :update, :first_name, :car, :first_name => 'Name', :car => {:brand => ''})
253
+ assert_equal 'Name', model.first_name
254
+ assert_nil Car.where(:id => car.id).first, 'previous car should be deleted'
255
+ assert model.car.blank?, 'car should be cleared'
256
+ assert model.save
257
+ end
258
+
259
+ def test_saving_belongs_to_polymorphic_select
260
+ person = Person.create
261
+ assert person.persisted?
262
+
263
+ model = update_record_from_params(Contact.new, :create, :first_name, :contactable_type, :contactable, :first_name => 'First', :contactable_type => person.class.name, :contactable => person.id.to_s)
264
+ assert_equal 'First', model.first_name
265
+ assert_equal person.class.name, model.contactable_type
266
+ assert_equal person.id, model.contactable_id
267
+ assert_equal person, model.contactable
268
+ assert model.save
269
+
270
+ model = update_record_from_params(model, :update, :first_name, :contactable_type, :contactable, :first_name => 'Name', :contactable_type => person.class.name, :contactable => '')
271
+ assert_equal 'Name', model.first_name
272
+ assert_nil model.contactable_type
273
+ assert_nil model.contactable_id, 'contactable should be cleared'
274
+ assert_nil model.contactable, 'contactable should be cleared'
275
+ assert_equal person.id, Contact.find(model).contactable_id, 'contact should not be saved yet'
276
+ assert model.save
277
+ assert_nil Contact.find(model).contactable_id, 'contact should be saved'
278
+ end
279
+
280
+ protected
281
+ MODELS = [Address, Building, Car, Contact, Floor, Person]
282
+ def update_record_from_params(record, action, *columns, &block)
283
+ params = columns.extract_options!.with_indifferent_access
284
+ new_record = nil
285
+ record.class.transaction do
286
+ new_record = @controller.update_record_from_params(record, build_action_columns(record, action, columns), params)
287
+ MODELS.each { |model| model.any_instance.unstub(:save) }
288
+ yield if block_given?
289
+ Thread.current[:constraint_columns] = nil
290
+ end
291
+ new_record
292
+ end
293
+
294
+ def build_action_columns(record, action, *columns)
295
+ controller = ActiveScaffold::Core.active_scaffold_controller_for record.class
296
+ controller.active_scaffold_config.send(action).columns = columns
297
+ controller.active_scaffold_config.send(action).columns
7
298
  end
8
299
  end
9
300
 
10
- class AttributeParamsTest < Test::Unit::TestCase
301
+ class Controller
302
+ def self.helper_method(*args); end
303
+ def self.before_filter(*args); end
304
+
305
+ include ActiveScaffold::Core
306
+ include ActiveScaffold::Helpers::ControllerHelpers
11
307
  include ActiveScaffold::AttributeParams
12
- include ActiveScaffold::Finder
308
+ public :update_record_from_params
13
309
 
14
- def setup
15
- I18n.backend.store_translations :en, :number => {:format => {
16
- :delimiter => ',',
17
- :separator => '.'
18
- }}
19
- I18n.backend.store_translations :es, :number => {:format => {
20
- :delimiter => '.',
21
- :separator => ','
22
- }}
23
- I18n.backend.store_translations :ru, :number => {:currency => {
24
- :format => {
25
- :separator => ',',
26
- :delimiter => ''
27
- }
28
- }}
29
-
30
- @config = config_for('number_model')
31
- @config.columns[:number].form_ui = nil
32
- @config.list.columns.set_columns @config.columns
33
- end
34
-
35
- def teardown
36
- I18n.locale = :en
37
- end
38
-
39
- def test_english_format_with_decimal_separator_using_english_language
40
- I18n.locale = :en
41
- assert_equal 0.1, convert_number('.1')
42
- assert_equal 0.1, convert_number('.100')
43
- assert_equal 0.1, convert_number('0.1')
44
- assert_equal 0.345, convert_number('0.345')
45
- assert_equal 0.345, convert_number('+0.345')
46
- assert_equal -0.345, convert_number('-0.345')
47
- assert_equal 9.345, convert_number('9.345')
48
- assert_equal 9.1, convert_number('9.1')
49
- assert_equal 90.1, convert_number('90.1')
50
- end
51
-
52
- def test_english_format_with_thousand_delimiter_using_english_language
53
- I18n.locale = :en
54
- assert_equal 1000, convert_number('1,000')
55
- assert_equal 1000, convert_number('+1,000')
56
- assert_equal -1000, convert_number('-1,000')
57
- assert_equal 1000000, convert_number('1,000,000')
58
- end
59
-
60
- def test_english_format_with_separator_and_delimiter_using_english_language
61
- I18n.locale = :en
62
- assert_equal 1234.1, convert_number('1,234.1')
63
- assert_equal 1234.1, convert_number('1,234.100')
64
- assert_equal 1234.345, convert_number('+1,234.345')
65
- assert_equal -1234.345, convert_number('-1,234.345')
66
- assert_equal 1234000.1, convert_number('1,234,000.100')
67
- end
68
-
69
- def test_english_format_with_decimal_separator_using_spanish_language
70
- I18n.locale = :es
71
- assert_equal 0.1, convert_number('.1')
72
- assert_equal 0.1, convert_number('0.1')
73
- assert_equal 0.12, convert_number('+0.12')
74
- assert_equal -0.12, convert_number('-0.12')
75
- assert_equal 9.1, convert_number('9.1')
76
- assert_equal 90.1, convert_number('90.1')
77
- end
78
-
79
- def test_spanish_format_with_decimal_separator_using_spanish_language
80
- I18n.locale = :es
81
- assert_equal 0.1, convert_number(',1')
82
- assert_equal 0.1, convert_number(',100')
83
- assert_equal 0.1, convert_number('0,1')
84
- assert_equal 0.345, convert_number('0,345')
85
- assert_equal 0.345, convert_number('+0,345')
86
- assert_equal -0.345, convert_number('-0,345')
87
- assert_equal 9.1, convert_number('9,1')
88
- assert_equal 90.1, convert_number('90,1')
89
- assert_equal 9.1, convert_number('9,100')
90
- end
91
-
92
- def test_spanish_format_with_thousand_delimiter_using_spanish_language
93
- I18n.locale = :es
94
- assert_equal 1000, convert_number('1.000')
95
- assert_equal 1000, convert_number('+1.000')
96
- assert_equal -1000, convert_number('-1.000')
97
- assert_equal 1000000, convert_number('1.000.000')
98
- end
99
-
100
- def test_spanish_format_with_separator_and_decimal_using_spanish_language
101
- I18n.locale = :es
102
- assert_equal 1230.1, convert_number('1.230,1')
103
- assert_equal 1230.1, convert_number('1.230,100')
104
- assert_equal 1234.345, convert_number('+1.234,345')
105
- assert_equal -1234.345, convert_number('-1.234,345')
106
- assert_equal 1234000.1, convert_number('1.234.000,100')
107
- end
108
-
109
- def test_english_currency_format_with_decimal_separator_using_russian_language
110
- I18n.locale = :ru
111
- assert_equal 0.1, convert_number('.1', :currency)
112
- assert_equal 0.1, convert_number('0.1', :currency)
113
- assert_equal 0.12, convert_number('+0.12', :currency)
114
- assert_equal -0.12, convert_number('-0.12', :currency)
115
- assert_equal 9.1, convert_number('9.1', :currency)
116
- assert_equal 90.1, convert_number('90.1', :currency)
117
- end
118
-
119
- def test_russian_currency_format_with_decimal_separator_using_russian_language
120
- I18n.locale = :ru
121
- assert_equal 0.1, convert_number(',1', :currency)
122
- assert_equal 0.1, convert_number(',100', :currency)
123
- assert_equal 0.1, convert_number('0,1', :currency)
124
- assert_equal 0.345, convert_number('0,345', :currency)
125
- assert_equal 0.345, convert_number('+0,345', :currency)
126
- assert_equal -0.345, convert_number('-0,345', :currency)
127
- assert_equal 9.1, convert_number('9,1', :currency)
128
- assert_equal 90.1, convert_number('90,1', :currency)
129
- assert_equal 9.1, convert_number('9,100', :currency)
130
- end
131
-
132
- def test_english_format_with_decimal_separator_with_no_localized_format
133
- I18n.locale = :ru
134
- assert_equal 0.1, convert_number('.1')
135
- assert_equal 0.1, convert_number('0.1')
136
- end
137
-
138
- private
139
- def convert_number(value, format = nil)
140
- record = NumberModel.new
141
- @config.columns[:number].options[:format] = format unless format.nil?
142
- update_record_from_params(record, @config.list.columns, HashWithIndifferentAccess.new({:number => value}))
143
- record.number
310
+ def logger
311
+ @logger ||= Logger.new(STDOUT)
144
312
  end
145
313
  end