Загрузка файла rails через AJAX с включением refile и remotipart + private_pub

У меня есть приложение rails с чатом в реальном времени (1 на 1). Я хотел бы реализовать функцию загрузки файлов через AJAX, где при отправке формы загрузки файлов имя файла будет отображаться в чате без полной перезагрузки страницы.

Я пытаюсь использовать remotipart gem, чтобы иметь возможность отправить форму загрузки файла с помощью AJAX. Файлы загружаются прямо на S3, поэтому они вообще не попадают в мое приложение (мне не нужно их отображать), я просто отправляю имя файла /URL через чат другому пользователю.

В верхней части этих загрузок начинается, когда я выбираю файл благодаря refile gem. Поэтому, когда я отправляю (кнопка "отправить файл") форму, она просто сохраняет атрибуты файла (message.message_attachment / id, url, size и т. Д.) И message_id в базу данных.

введите описание изображения здесь введите описание изображения здесь введите описание изображения здесь

На картинке вы можете увидеть, что я хочу реализовать. Существует отдельная форма для ввода текста чата (message.body) и другая форма для загрузки файла (message.message_attachment). Пока что чат отлично работает с гемом private_pub. Выбор файла также происходит правильно (включая загрузку файла в S3 и 204 ответа о состоянии), но отправка формы (сохранение сообщения в db нажатием "Отправить файл") работает только при полной перезагрузке страницы.

Решения, которые я попробовал:

  1. Если я не помещаю "authenticity_token: true" во вспомогательную форму для загрузки, я получаю неверную ошибку токена authencity.
  2. Если я использую контроллер сообщений, который правильно работает с чатом, я получаю пропущенную ошибку шаблона в форме.
  3. Если я добавлю туда response_to js (с рендерингом или без него: 'create.js.erb'), я получу неизвестную ошибку формата.

Для обмена сообщениями в чате я использую тот же create.js.erb, но мне не нужно использовать response_to js благодаря гему private_pub. Я просто должен подписаться и опубликовать в / с разговор_путь (@path).

Я чувствую, что довольно близок к решению, так как оно работает с полной перезагрузкой страницы. Я не знаю, может ли проблема быть вызвана совместимостью между решением private_pub (нет необходимости в response_to js) и remotipart с / refile (response_to js необходимо).

модель сообщения:

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 %>

сообщение /_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) %>

Контроллер сообщений для чата перед загрузкой файлов:

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

Контроллер сообщений, который отлично работает с полной перезагрузкой страницы для загрузки:

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

ОБНОВИТЬ:

Неполадка решена: опечатка в app.js //= требуется jquery.remotipart...... - response_to js не требуется благодаря gem private_pub - authencity_token: true для помощника по форме также не требуется благодаря remotipart gem - remotipart необходимо быть в состоянии отправить форму файла через AJAX

0 ответов

Другие вопросы по тегам