Search code examples
ruby-on-railsajaxactiverecordassociationsjquery-file-upload

Creating associated records inside parent's new view/form. Associated records are done through Ajax/jquery-file-upload


So i have a "Style" model, which has_many "Images". In the new style page, i want to be able to add images all in the same page. However, since we did not create the style record yet, it does not have an ID. So how would i go about collecting all the images that are built/uploaded by ajax, and updating their style_id attributes after saving the new Style?

I am using jquery-file-upload to add images to the Image table, and upload my files to Rackspace cloud files. All of this is working, i just am not able to set style_id other than just manually setting it.

Is there a best practices/proper way to go about this, since jquery-file-upload uses Ajax, i am not sure the best approach to saving my parent. I am thinking the best approach would be to use ajax to submit the parent form as well, rather than use the dom, like adding hidden inputs/elements to the parent form?

thank you

Style: form partial

<%= form_for @style, :html => {:multipart => true} do |f| %>
    //NORMAL RAILS FORM CODE HERE
<% end %>

<%= form_for Image.new, :html => { :multipart => true, :id => "fileupload"  } do |f| %>
  <%= f.file_field :file, :multiple => true %>
<% end %>

<script>
$(function () {
  $('#fileupload').fileupload({
    dataType: 'json',
    url: '<%= style_images_path(1) %>',
    add: function (e, data) {
        data.context = $('<div class="img uploading"/>').text('Uploading...').appendTo(document.body);
        data.submit();
    },
    done: function (e, data) {
        $.each(data.result.files, function (index, file) {
            $('<img src="'+file.thumbnail_url+'">').appendTo(data.context);
        });
        console.log(data);
        data.context.append("<span>done</span>");
    },
    option: {
            autoUpload: true,
    }
  });
});
</script>

In the above code you can see I set the style_id manually... style_images_path(1)

-

MY PROPOSED SOLUTION:

My idea is to pass an array of the id's of all children (images) to the create/update method of style. and in the controller, update all the style_id attributes of the matching id's to the newly created style's id... I think this is possible?


Solution

  • That's tricky.

    You can instantiate the @style from within the new method of your controller. Instead than:

    @style = Style.new
    

    put

    @style = Style.create
    

    If validation complains, than use the following workaround:

    @style = Style.new
    @style.save :validate => false
    

    Now in your view you have a fully qualified @style with an ID you can pass over to js:

        url: '<%= style_images_path(@style) %>',
    

    At this point when (if ever) the user clicks on the form button, the control reaches the update method, not the create (this is because the _form.html.erb automatically changes the HTTP verb from POST (create) to PUT (update). So make sure your controller is ready for this).

    You should also consider some sort of "garbage collection" in case Style objects get created and never saved. This might not be straight forward because the user can always close the window and you are left with an incomplete Style in the db. Maybe some js function that triggers at window close and calls a garbage_collect_if_not_saved(@style) method? Still not perfect (what if the browser hangs?) but better than nothig. Otherwise a good-old cron based script that cleans the db up.

    Cheers,