Sean Magyar
Sean Magyar

Reputation: 2380

rails file uploading via AJAX with refile and remotipart + private_pub involved

I have a rails app with a real time chat (1v1). I'd like to implement a file upload function via AJAX where on submitting the file upload form the filename will show up in the chat without full page reload.

I'm trying to use remotipart gem to be able to submit the refile file upload form via AJAX. Files are uploaded directly to S3 so those never hit my app at all (I don't need to display them), I just send the filename/URL via the chat to the other user.

On the top of these uploading starts when I choose the file thanks to refile gem. So when I submit('send file' button) the form it just saves the file attributes(message.message_attachment/id,url,size, etc.) and message_id into the db.

enter image description hereenter image description hereenter image description here

On the pic you can see what I wanna implement. There is a separate form for chat input text (message.body) and an other form for file uploading (message.message_attachment). So far chat is working perfectly with private_pub gem. Choosing file happens properly as well (including uploading the file to S3 and 204 status response) but submitting the form (saving the message to db by clicking on 'send file') only works with full page reload.

The solutions I tried:

  1. If I don't put the 'authenticity_token: true' into the form helper for uploading then I get invalid authencity token error.
  2. If I'm using the messagescontroller that works properly with the chat then I get missing template error in the form.
  3. If I put there respond_to js (with or without render: 'create.js.erb') I get unknown format error.

For the chat messaging I use the same create.js.erb but I don't have to use respond_to js thanks to the private_pub gem. I just have to subscribe and publish to/with the conversation_path(@path).

I feel I'm pretty close to the solution since it works with full page reload. I don't know if the compatibility between private_pub solution (no need for respond_to js) and remotipart w/ refile (respond_to js needed) can cause the problem.

message model:

create_table "messages", force: :cascade do |t|
    t.text     "body"
    t.integer  "conversation_id"
    t.integer  "user_id"
    t.string   "message_attachment"
    t.string   "message_attachment_id"
    t.string   "message_attachment_filename"
    t.integer  "message_attachment_size"
    t.string   "message_attachment_content_type"
    ......
end

create.js.erb

<% publish_to @path do %>
    var id = "<%= @conversation.id %>";
    var chatbox = $(".chatboxcontent");

    chatbox.append("<%= j render(partial: @message ) %>");
    chatbox.scrollTop(chatbox[0].scrollHeight);
    $(".chatboxtextarea").val("");

    var filechosen = $('.choosefile').val();
    if (filechosen != "") {
        $(".refile_form").find("input[type=submit]").hide();
        $('.choosefile').val("");
        $('#progresspercent').hide();
    }
<% end %>

message/_show.html.erb

<div class="chatboxcontent">
  <% if @messages.any? %>
      <%= render @messages %>
  <% end %>
</div>
<div class="chatboxinput">
  <%= form_for([@conversation, @message], :remote => true, :html => {id: "conversation_form_#{@conversation.id}"}) do |f| %>
      <%= f.text_area :body, class: "chatboxtextarea", "data-cid" => @conversation.id %>
  <% end %>
  <%= form_for([@conversation, @message], html: {class: "refile_form"}, remote: true, authenticity_token: true) do |form| %>
      <span class="btn btn-success btn-sm btn-file">Choose file
      <%= form.attachment_field :message_attachment, direct: true, presigned: true, class: "choosefile" %></span>
      <%= form.submit "Send File", class: "btn btn-primary btn-sm btn-submit-refile" %>
  <% end %>
</div>

<%= subscribe_to conversation_path(@conversation) %>

messages controller for chat before implementing file uploading:

def create
    @conversation = Conversation.find(params[:conversation_id])
    @message = @conversation.messages.build(message_params)
    @message.user_id = current_user.id
    @message.save!
    @path = conversation_path(@conversation)
end

messages controller that works fine w/ full page reload for uploading:

def create
    @conversation = Conversation.find(params[:conversation_id])
    @message = @conversation.messages.build(message_params)
    @message.user_id = current_user.id
    @message.save!
    @path = conversation_path(@conversation)
    if @message.message_attachment_id
      respond_to do |format|
        format.html { redirect_to :back }
        # I've tried w/ and with no format.js as well.
        #format.js { render: 'create.js.erb }
      end
    end
  end

UPDATE:

Problem solved: Typo in the app.js //=require jquery.remotipart...... - respond_to js is not necessary thanks to private_pub gem - authencity_token: true for form helper also not necessary thanks to remotipart gem - remotipart needed to be able to submit file form via AJAX

Upvotes: 1

Views: 735

Answers (0)

Related Questions