@@ -80,7 +80,9 @@ def dummy_model_params
80
80
params . require ( :dummy_model ) . permit (
81
81
:title ,
82
82
:description ,
83
- dummy_child_models_attributes : [ :id , :_destroy , :title , :description ]
83
+ :file ,
84
+ files : [ ] ,
85
+ dummy_child_models_attributes : [ :id , :_destroy , :title , :description , :file , files : [ ] ]
84
86
)
85
87
end
86
88
end
@@ -97,8 +99,9 @@ def dummy_model_params
97
99
end
98
100
99
101
before :each do
100
- DummyModel . destroy_all
102
+ ActiveStorage :: Attachment . all . each { | attachment | attachment . purge }
101
103
DummyChildModel . destroy_all
104
+ DummyModel . destroy_all
102
105
allow_any_instance_of ( NestedFormTestController ) . to receive ( :expect_params )
103
106
end
104
107
@@ -1248,6 +1251,149 @@ def response
1248
1251
1249
1252
end
1250
1253
1254
+ describe "supports multipart form submit alongside file upload within parent model" do
1255
+
1256
+ before do
1257
+ @dummy_model = DummyModel . create ( title : "existing-dummy-model-title" )
1258
+ @dummy_model . dummy_child_models . create ( title : "existing-dummy-child-model-title-1" )
1259
+ @dummy_model . dummy_child_models . create ( title : "existing-dummy-child-model-title-2" )
1260
+
1261
+ class ExamplePage < Matestack ::Ui ::Page
1262
+
1263
+ def prepare
1264
+ @dummy_model = DummyModel . last
1265
+ end
1266
+
1267
+ def response
1268
+ matestack_form form_config do
1269
+ form_input key : :title , type : :text , label : "dummy_model_title_input" , id : "dummy_model_title_input"
1270
+
1271
+ form_input key : :file , type : :file , label : "dummy_model_file_input" , id : "dummy_model_file_input"
1272
+ form_input key : :files , type : :file , label : "dummy_model_files_input" , id : "dummy_model_files_input" , multiple : true
1273
+
1274
+ @dummy_model . dummy_child_models . each do |dummy_child_model |
1275
+ dummy_child_model_form dummy_child_model
1276
+ end
1277
+
1278
+ form_fields_for_add_item key : :dummy_child_models_attributes , prototype : method ( :dummy_child_model_form ) do
1279
+ button "add" , type : :button # type: :button is important! otherwise remove on first item is triggered on enter
1280
+ end
1281
+
1282
+ button "Submit me!"
1283
+
1284
+ toggle show_on : "success" , hide_after : 1000 do
1285
+ plain "success!"
1286
+ end
1287
+ toggle show_on : "failure" , hide_after : 1000 do
1288
+ plain "failure!"
1289
+ end
1290
+ end
1291
+ end
1292
+
1293
+ def dummy_child_model_form dummy_child_model = DummyChildModel . new
1294
+ form_fields_for dummy_child_model , key : :dummy_child_models_attributes do
1295
+ form_input key : :title , type : :text , label : "dummy-child-model-title-input"
1296
+ form_input key : :file , type : :file , label : "dummy-child-model-file-input"
1297
+ form_input key : :files , type : :file , label : "dummy-child-model-files-input" , multiple : true
1298
+
1299
+ form_fields_for_remove_item do
1300
+ button "remove" , ":id" : "'remove'+nestedFormRuntimeId" , type : :button # id is just required in this spec, but type: :button is important! otherwise remove on first item is triggered on enter
1301
+ end
1302
+ end
1303
+ end
1304
+
1305
+ def form_config
1306
+ {
1307
+ for : @dummy_model ,
1308
+ method : :put ,
1309
+ multipart : true ,
1310
+ path : nested_forms_spec_submit_update_path ( id : @dummy_model . id ) ,
1311
+ success : { emit : "success" } ,
1312
+ failure : { emit : "failure" }
1313
+ }
1314
+ end
1315
+ end
1316
+ end
1317
+
1318
+ it "and properly sends dynamically added child data as multipart format" do
1319
+ id_of_parent = DummyModel . last . id
1320
+ id_of_child_1 = DummyChildModel . last . id
1321
+ id_of_child_0 = id_of_child_1 -1
1322
+
1323
+ visit "/example"
1324
+
1325
+ expect ( page ) . to have_selector ( '#dummy_model_title_input' )
1326
+ expect ( page ) . to have_selector ( '#title_dummy_child_models_attributes_child_0' )
1327
+ expect ( page ) . to have_selector ( '#title_dummy_child_models_attributes_child_1' )
1328
+ expect ( page ) . not_to have_selector ( '#title_dummy_child_models_attributes_child_2' )
1329
+ expect ( page ) . not_to have_selector ( '#title_dummy_child_models_attributes_child_3' )
1330
+
1331
+ click_on "add"
1332
+ expect ( page ) . to have_selector ( '#title_dummy_child_models_attributes_child_2' )
1333
+ click_on "add"
1334
+ expect ( page ) . to have_selector ( '#title_dummy_child_models_attributes_child_3' )
1335
+
1336
+
1337
+ fill_in "title_dummy_child_models_attributes_child_2" , with : "new-dummy-child-model-title-3-value"
1338
+ fill_in "title_dummy_child_models_attributes_child_3" , with : "new-dummy-child-model-title-4-value"
1339
+
1340
+ attach_file ( 'dummy_model_file_input' , "#{ File . dirname ( __FILE__ ) } /input/test_files/matestack-logo.png" )
1341
+ attach_file "dummy_model_files_input" , [ "#{ File . dirname ( __FILE__ ) } /input/test_files/matestack-logo.png" , "#{ File . dirname ( __FILE__ ) } /input/test_files/corgi.mp4" ]
1342
+
1343
+ attach_file ( 'file_dummy_child_models_attributes_child_0' , "#{ File . dirname ( __FILE__ ) } /input/test_files/matestack-logo.png" )
1344
+ attach_file ( 'file_dummy_child_models_attributes_child_2' , "#{ File . dirname ( __FILE__ ) } /input/test_files/corgi.mp4" )
1345
+ attach_file ( 'file_dummy_child_models_attributes_child_3' , "#{ File . dirname ( __FILE__ ) } /input/test_files/matestack-logo.png" )
1346
+
1347
+ attach_file "files_dummy_child_models_attributes_child_0" , [ "#{ File . dirname ( __FILE__ ) } /input/test_files/matestack-logo.png" , "#{ File . dirname ( __FILE__ ) } /input/test_files/corgi.mp4" ]
1348
+ attach_file "files_dummy_child_models_attributes_child_2" , [ "#{ File . dirname ( __FILE__ ) } /input/test_files/matestack-logo.png" , "#{ File . dirname ( __FILE__ ) } /input/test_files/corgi.mp4" ]
1349
+ attach_file "files_dummy_child_models_attributes_child_3" , [ "#{ File . dirname ( __FILE__ ) } /input/test_files/matestack-logo.png" , "#{ File . dirname ( __FILE__ ) } /input/test_files/corgi.mp4" ]
1350
+
1351
+ expect {
1352
+ click_button "Submit me!"
1353
+ expect ( page ) . to have_content ( "success!" ) # required to work properly!
1354
+ # expect proper form reset (added items are kept, but value is resetted)
1355
+ expect ( page ) . to have_selector ( '#dummy_model_title_input' )
1356
+ expect ( page ) . to have_selector ( '#title_dummy_child_models_attributes_child_0' )
1357
+ expect ( page ) . to have_selector ( '#title_dummy_child_models_attributes_child_1' )
1358
+ expect ( page ) . to have_selector ( '#title_dummy_child_models_attributes_child_2' )
1359
+ expect ( page ) . to have_selector ( '#title_dummy_child_models_attributes_child_3' )
1360
+ expect ( page . find ( "#dummy_model_title_input" ) . value ) . to eq ( "existing-dummy-model-title" )
1361
+ expect ( page . find ( "#title_dummy_child_models_attributes_child_0" ) . value ) . to eq ( "existing-dummy-child-model-title-1" )
1362
+ expect ( page . find ( "#title_dummy_child_models_attributes_child_1" ) . value ) . to eq ( "existing-dummy-child-model-title-2" )
1363
+ expect ( page . find ( "#title_dummy_child_models_attributes_child_2" ) . value ) . to eq ( "new-dummy-child-model-title-3-value" )
1364
+ expect ( page . find ( "#title_dummy_child_models_attributes_child_3" ) . value ) . to eq ( "new-dummy-child-model-title-4-value" )
1365
+ }
1366
+ . to change { DummyModel . count } . by ( 0 )
1367
+ . and change { DummyChildModel . count } . by ( 2 )
1368
+
1369
+ id_of_child_3 = DummyChildModel . last . id
1370
+ id_of_child_2 = id_of_child_3 -1
1371
+
1372
+ expect ( DummyChildModel . find ( id_of_child_3 ) . title ) . to eq ( "new-dummy-child-model-title-4-value" )
1373
+ expect ( DummyChildModel . find ( id_of_child_2 ) . title ) . to eq ( "new-dummy-child-model-title-3-value" )
1374
+
1375
+ expect ( DummyModel . find ( id_of_parent ) . file . blob . filename ) . to eq ( "matestack-logo.png" )
1376
+ expect ( DummyModel . find ( id_of_parent ) . files [ 0 ] . blob . filename ) . to eq ( "matestack-logo.png" )
1377
+ expect ( DummyModel . find ( id_of_parent ) . files [ 1 ] . blob . filename ) . to eq ( "corgi.mp4" )
1378
+
1379
+ expect ( DummyChildModel . find ( id_of_child_0 ) . file . blob . filename ) . to eq ( "matestack-logo.png" )
1380
+ expect ( DummyChildModel . find ( id_of_child_0 ) . files [ 0 ] . blob . filename ) . to eq ( "matestack-logo.png" )
1381
+ expect ( DummyChildModel . find ( id_of_child_0 ) . files [ 1 ] . blob . filename ) . to eq ( "corgi.mp4" )
1382
+
1383
+ expect ( DummyChildModel . find ( id_of_child_1 ) . file . blob . nil? ) . to be true
1384
+ expect ( DummyChildModel . find ( id_of_child_1 ) . files . empty? ) . to be true
1385
+
1386
+ expect ( DummyChildModel . find ( id_of_child_2 ) . file . blob . filename ) . to eq ( "corgi.mp4" )
1387
+ expect ( DummyChildModel . find ( id_of_child_2 ) . files [ 0 ] . blob . filename ) . to eq ( "matestack-logo.png" )
1388
+ expect ( DummyChildModel . find ( id_of_child_2 ) . files [ 1 ] . blob . filename ) . to eq ( "corgi.mp4" )
1389
+
1390
+ expect ( DummyChildModel . find ( id_of_child_3 ) . file . blob . filename ) . to eq ( "matestack-logo.png" )
1391
+ expect ( DummyChildModel . find ( id_of_child_3 ) . files [ 0 ] . blob . filename ) . to eq ( "matestack-logo.png" )
1392
+ expect ( DummyChildModel . find ( id_of_child_3 ) . files [ 1 ] . blob . filename ) . to eq ( "corgi.mp4" )
1393
+ end
1394
+
1395
+ end
1396
+
1251
1397
end
1252
1398
1253
1399
end
0 commit comments