Загрузка файла 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 нажатием "Отправить файл") работает только при полной перезагрузке страницы.
Решения, которые я попробовал:
- Если я не помещаю "authenticity_token: true" во вспомогательную форму для загрузки, я получаю неверную ошибку токена authencity.
- Если я использую контроллер сообщений, который правильно работает с чатом, я получаю пропущенную ошибку шаблона в форме.
- Если я добавлю туда 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