Мне не удалось выяснить, как заставить мой JavaScript отправлять запрос в формате, который будет принимать Rails, когда я пытаюсь редактировать игру с параметром File и параметром массива в той же полезной нагрузке.
Контроллер Rails выглядит следующим образом (очевидно, упрощенно):
class GamesController < ApplicationController
def update
@game = Game.find(params[:id])
authorize @game
respond_to do |format|
if @game.update(game_params)
format.html { render html: @game, success: "#{@game.name} was successfully updated." }
format.json { render json: @game, status: :success, location: @game }
else
format.html do
flash.now[:error] = "Unable to update game."
render :edit
end
format.json { render json: @game.errors, status: :unprocessable_entity }
end
end
end
private
def game_params
params.require(:game).permit(
:name,
:cover,
genre_ids: [],
engine_ids: []
)
end
end
Итак, у меня есть JavaScript примерно так:
// this.game.genres and this.game.engines come from
// elsewhere, they're both arrays of objects. These two
// lines turn them into an array of integers representing
// their IDs.
let genre_ids = Array.from(this.game.genres, genre => genre.id);
let engine_ids = Array.from(this.game.engines, engine => engine.id);
let submittableData = new FormData();
submittableData.append('game[name]', this.game.name);
submittableData.append('game[genre_ids]', genre_ids);
submittableData.append('game[engine_ids]', engine_ids);
if (this.game.cover) {
// this.game.cover is a File object
submittableData.append('game[cover]', this.game.cover, this.game.cover.name);
}
fetch("/games/4", {
method: 'PUT',
body: submittableData,
headers: {
'X-CSRF-Token': Rails.csrfToken()
},
credentials: 'same-origin'
}).then(
// success/error handling here
)
JavaScript запускается, когда я нажимаю кнопку подтверждения.в форме, и предполагается преобразовать данные в формат, который примет бэкэнд Rails.К сожалению, у меня возникают проблемы с тем, чтобы заставить его работать.
Я могу использовать JSON.stringify()
вместо FormData
для отправки данных в случае, когда нет файла изображения для отправки, например:
fetch("/games/4", {
method: 'PUT',
body: JSON.stringify({ game: {
name: this.game.name,
genre_ids: genre_ids,
engine_ids: engine_ids
}}),
headers: {
'Content-Type': 'application/json',
'X-CSRF-Token': Rails.csrfToken()
},
credentials: 'same-origin'
})
Это отлично работает.Но я не смог понять, как использовать JSON.stringify
при отправке объекта File.В качестве альтернативы я могу использовать объект FormData
, который работает для простых значений, например, name
, а также для объектов File, но не для значений массива, таких как массив идентификаторов.
Успешная отправка формы столько массивы идентификаторов (с использованием JSON.stringify
) выглядят так в консоли Rails:
Parameters: {"game"=>{"name"=>"Pokémon Ruby", "engine_ids"=>[], "genre_ids"=>[13]}, "id"=>"4"}
Однако мой текущий код заканчивается примерно так:
Parameters: {"game"=>{"name"=>"Pokémon Ruby", "genre_ids"=>"18,2,15", "engine_ids"=>"4,2,10"}, "id"=>"4"}
Unpermitted parameters: :genre_ids, :engine_ids
Или, если вы также загружаете файл в процессе:
Parameters: {"game"=>{"name"=>"Pokémon Ruby", "genre_ids"=>"13,3", "engine_ids"=>"5", "cover"=>#<ActionDispatch::Http::UploadedFile:0x00007f9a45d11f78 @tempfile=#<Tempfile:/var/folders/2n/6l8d3x457wq9m5fpry0dltb40000gn/T/RackMultipart20190217-31684-1qmtpx2.png>, @original_filename="Screen Shot 2019-01-27 at 5.26.23 PM.png", @content_type="image/png", @headers="Content-Disposition: form-data; name=\"game[cover]\"; filename=\"Screen Shot 2019-01-27 at 5.26.23 PM.png\"\r\nContent-Type: image/png\r\n">}, "id"=>"4"}
Unpermitted parameters: :genre_ids, :engine_ids
TL; DR : У меня вопрос, как я могу отправить эту полезную нагрузку (строку имени, массив идентификаторов,а также изображение обложки игры) на Rails с использованием JavaScript?Какой формат на самом деле будет принят и как мне это сделать?
Приложение Rails с открытым исходным кодом, если это вообще поможет, репозиторий можно посмотреть здесь .Упомянутые конкретные файлы: app/controllers/games_controller.rb
и app/javascript/src/components/game-form.vue
, хотя я значительно упростил оба этих вопроса.