简体   繁体   中英

Ruby on Rails file uploading using a form with remote: true

I am trying to upload files using a Rails form where the remote is set to true. I'm using Rails 4.1.1. Let's say that my model is a Message, and it is using JavaScript so that the user could easily send multiple messages without reloading the page. The form is set like this:

<%= form_for @message, url: {action: "create"}, html: {:class => "message-form", multipart: true}, remote: true do |f| %>

The user can upload images with the Message, if they wish to do so. MessageImage acts as a nested attribute in the form, and is declared like this ( http://railscasts.com/episodes/196-nested-model-form-revised way):

<%= f.fields_for :message_images do |builder| %>
   <%= render 'message_image_fields', f: builder %>
   <%= link_to_add_fields "Add an image", f, :message_images %>
<% end %>

On my controller the action is roughly like this:

if @message.save
   flash.now[:success] = "Message sent"
else
   flash.now[:alert] = "Error sending the message"
end
respond_to do |format|
   format.html { render 'new' }
   format.js { render 'new' }
end

Now, this works perfectly as long as the user doesn't send any images, but if they do, it uses format.html instead of format.js. Removing the format.html gives ActionController::UnknownFormat-exception.

Now, this obviously has to do with the fact that you can't submit files with remote set to true. I tried searching a bit, and found this gem https://github.com/JangoSteve/remotipart , which seems to be exactly what I'm looking for. I installed it following the instructions, but for some reason it still doesn't work and gives ActionController::UnknownFormat-exception if I remove the format.html. However, I couldn't find any example of it involving nested attributes. Are there any alternatives for this gem or any other way to fix this, or should I just set that it renders HTML if the user submits files?

JQuery

I don't know how to get the nested model aspect of this, but we've done file uploading with JQuery / asynchronicity before here (register for account, log into profile):

在此处输入图片说明

We used the jquery-file-upload gem - basically allowing you to pass the files through Ajax to your controller backend. To give you a clear idea of how we did this:

--

Code

#app/assets/javascripts/application.js
$('#avatar').fileupload({

    url: '/profile/' + $(this).attr('data_id'),
    dataType: 'json',
    type: 'post',

    add: function (e, data) {
        $(this).avatar_loading('avatar_loading');
        data.submit();
    },
    success: function (data, status) {;
        $("#avatar_img").fadeOut('fast', function() {
            $(this).attr("src", data.avatar_url).fadeIn('fast', function(){
                $(this).avatar_loading('avatar_loading');
            });
        });
    }

});


#app/views/users/index.html.erb
<%= form_for :upload, :html => {:multipart => true, :id => "avatar"}, :method => :put, url: profile_path(current_user.id), "data_id" => current_user.id do |f| %>
    <div class="btn btn-success fileinput-button avatar" id="avatar_container">
            <%= f.file_field :avatar, :title => "Upload New" %>
            <%= image_tag(@user.profile.avatar.url, :width=> '100%', :id => "avatar_img", :alt => name?(@user)) %>
    </div>
<% end %>


#app/controllers/profile_controller.rb
Class ProfileController < ApplicationController
   def update
       def update
        @profile = User.find(current_user.id)
        @profile.profile.update(upload_params)

        respond_to do |format|
            format.html { render :nothing => true }
            format.js   { render :partial => 'profiles/update.js' }
            format.json { 
                render :json => @profile.profile.as_json(:only => [:id, :avatar], :methods => [:avatar_url])
            }
        end

        def upload_params
            params.require(:upload).permit(:avatar, :public, :description)
        end
   end
end

--

Implementation

For your implementation, I would recommend firstly creating the message, and then getting the user to append some images to it in another action

After you've got that working, you could get it to work as one form

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM