質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.46%
Ruby on Rails

Ruby on Railsは、オープンソースのWebアプリケーションフレームワークです。「同じことを繰り返さない」というRailsの基本理念のもと、他のフレームワークより少ないコードで簡単に開発できるよう設計されています。

API

APIはApplication Programming Interfaceの略です。APIはプログラムにリクエストされるサービスがどのように動作するかを、デベロッパーが定めたものです。

React.js

Reactは、アプリケーションのインターフェースを構築するためのオープンソースJavaScriptライブラリです。

Q&A

0回答

984閲覧

Reactからrails-apiにaxiosで画像データを送するとエラーが出る

kiyomasa

総合スコア40

Ruby on Rails

Ruby on Railsは、オープンソースのWebアプリケーションフレームワークです。「同じことを繰り返さない」というRailsの基本理念のもと、他のフレームワークより少ないコードで簡単に開発できるよう設計されています。

API

APIはApplication Programming Interfaceの略です。APIはプログラムにリクエストされるサービスがどのように動作するかを、デベロッパーが定めたものです。

React.js

Reactは、アプリケーションのインターフェースを構築するためのオープンソースJavaScriptライブラリです。

0グッド

0クリップ

投稿2021/07/16 23:19

編集2021/07/17 23:52

##前提・実現したいこと
現在料理投稿サイトのポートフォリオ を作成中です。
React側(フロントエンド)からrails-apiにaxiosで画像データを送信し、他データ(レシピデータ)とセットでDBに保存したいです

##発生している問題
しかし、現在2点の不明な事象が起きており、それを解決したいです

①axiosでPostすると以下のエラーが出る

##エラー内容 (多分imageデータを文字列にしている?後に引数エラーと表示される)

...大量の文字列 ACCvwAgW5sGc/X6uaVGnIde1/XkadJZk5Nz8l50YiKUQEFFFBAAQUUUEABBXYQ4KIxz5re5+hykHV6H+YdM86HHqoj+cScMf+f5PNhD2MuGm+LfimggAIKKHBSwIvGk4BuV0ABBRRQYGeBbkZpbmcTSj7vuarvHBbJsa/P6xznEamjhuhFI6pGBRRQQAEFFFBAAQUU2EFgXjTmmdPv0PMkkkuk9+l858jfNv2rJ0dMPePUZdxn9DgXjbOes40KKKCAAgp8VsCLxs+KWa+AAgoooMAPEujmshvP1bhfm/XO9Tjr1HSDm5qZz7xrWOc8/0YjEkYFFFBAAQUUUEABBRTYQWD1Nxq5BKT3SWScd2KdMX0Rdffeu/dSN8/u87xoRMmogAIKKHCFgBeNVyh6hgIKKKCAApsKdLP50bhfkdrOZTzzc05NN73kEvmwL9FfNKJiVEABBRRQQAEFFFBAgR0E+EUjF4BEnr3n9EadW9Ult6o5ynMu6/RYyT89PSV9eN5t0S8FFFBAAQUeFPCi8UEoyxRQQAEFFPiJAt1sfjTu91/VZp08tUdzml7iUV3O8ReNaBoVUEABBRRQQAEFFFBgB4H5i8b0Pf3JnF6ImPVV3dzH/N4+zqLPmrVeNKJoVEABBRS4QuAvvMf4TU4yJf4AAAAASUVORK5CYII=", "name"=>"スクリーンショット 2021-07-08 8.33.34.png"}}} ArgumentError (missing keywords: :io, :filename):

②onsubmitで送信できる時とできない時がある
onsubmitを押下すると、以下のようにURLパラメータだけが加わり、apiにリクエストを送らないことがある
/post?image=スクリーンショット+2021-04-14+22.54.13.png

その後、再度入力し送信すると、apiにリクエストを送り、①のエラーが発生する

##関連コード

rails recipes_controller

ruby

1module Api 2 module V1 3 class RecipesController < ApplicationController 4 def create 5 @recipe = Recipe.new(post_params) 6 if @recipe.valid? 7 if params[:recipe][:image] 8 blob = ActiveStorage::Blob.create_after_upload!( 9 io: StringIO.new(decode(params[:recipe][:image][:data]) + "\n"), 10 filename: params[:recipe][:image][:name], 11 ) 12 @recipe.image.attach(blob) 13 end 14 15 @recipe.save 16 render json: { 17 status: :created, 18 methods: [:image_url], 19 } 20 else 21 render json: { 22 status: 500, 23 errors: @recipe.errors.full_messages, 24 # '登録に失敗しました。再度ログインしなおしてからご登録ください' 25 } 26 end 27 end 28 29... 30 31 private 32 33 def post_params 34 params.require(:recipe).permit( 35 :user_id, :title, :time_required, :food, :process, image: 36#ここに問題あり? 37 ) 38 39 end 40 41 def decode(str) 42 Base64.decode64(str.split(",").last) 43 end 44 end 45 end 46end 47

React Post.jsx

javascript

1import React, { memo, useState, useEffect } from 'react'; 2import { 3 Flex, Box, Divider, Heading, Input, Textarea, Stack, Text, Image, 4 NumberInput, 5 NumberInputField, 6 NumberInputStepper, 7 NumberIncrementStepper, 8 NumberDecrementStepper, 9 Slider, 10 SliderTrack, 11 SliderFilledTrack, 12 SliderThumb, 13} from "@chakra-ui/react"; 14import styled from 'styled-components'; 15 16import { useLoginUser } from "../hooks/useLoginUser"; 17 18import axios from "axios"; 19import { useHistory } from "react-router-dom"; 20 21import { useMessage } from "../hooks/useMessege"; 22 23 24 25export const Post = () => { 26 const { loginUser } = useLoginUser(); 27 const history = useHistory(); 28 const { showMessage } = useMessage(); 29 30 //api送信state 31 const [title, setTitle] = useState() 32 const [food, setFood] = useState() 33 const [process, setProcess] = useState() 34 const [time_required, setTime_required] = useState(0) 35 const [image, setImage] = useState({ data: "", name: "" }) 36 37 38 const handleImageSelect = (e) => { 39 const reader = new FileReader() 40 //画像をbase64にエンコード 41 const files = (e.target).files 42 if (files) { 43 reader.onload = () => { 44 setImage({ 45 data: reader.result, 46 name: files[0] ? files[0].name : "unknownfile" 47 }) 48 } 49 reader.readAsDataURL(files[0]) 50 //onsubmitするとURLパラメータになる 51 } 52 } 53 54 const onSubmit = (event) => { 55 console.log("イベント発火") 56 // なぜ送られる時と送られない時がある 57 axios.post("http://localhost:3000/api/v1/recipes", 58 { 59 recipe: { 60 user_id: loginUser.user.id, 61 title: title, 62 time_required: time_required, 63 food: food, 64 process: process, 65 image: 66 { 67 data: image.data, 68 name: image.data 69 } 70 } 71 } 72 , { withCredentials: true } 73 ).then(response => { 74 if (response.data.created) { 75 showMessage({ title: "投稿に成功しました", status: "success" }); 76 history.push("/index"); 77 } 78 else if (response.data.status === 500) { 79 showMessage({ title: `${response.data.errors}`, status: "error" }); 80 } 81 }).catch(e => { 82 showMessage({ title: "投稿できませんでした", status: "error" }); 83 }) 84 }; 85 86 const handleChange = (time_required) => setTime_required(time_required) 87 88 return ( 89 <> 90 <Flex mt="80px" alignItems="center" justifyContent="center" > 91 <Box bg="white" w="sm" p={4} borderRadius="md" shadow="md"> 92 <Heading as="h1" size="lg" textAlign="center"> 93 レシピ投稿 94 </Heading> 95 <Divider my={4} /> 96 <form onSubmit={onSubmit}> 97 <Stack> 98 <Input variant="flushed" radii="1rem" placeholder="タイトル(20文字まで)" value={title} onChange={e => setTitle(e.target.value)} /> 99 </Stack> 100 <Stack> 101 102 <Image src={!image.data ? "gibbresh.png" : image.data} fallbackSrc="https://via.placeholder.com/150" /> 103 104 </Stack> 105 <Stack> 106 <Input type="file" placeholder="画像アップロード" name="image" accept="image/png,image/jpeg" onChange={handleImageSelect} /> 107 </Stack> 108 109 <Stack mt={3}> 110 <Text color="gray.500">材料</Text> 111 <Textarea placeholder="材料" value={food} onChange={e => setFood(e.target.value)} /> 112 </Stack> 113 <Stack mt={3}> 114 <Text color="gray.500">手順</Text> 115 <Textarea placeholder="手順" value={process} onChange={e => setProcess(e.target.value)} /> 116 </Stack> 117 <Text color="gray.500">所要時間</Text> 118 <Flex> 119 <NumberInput maxW="100px" mr="2rem" value={time_required} value={time_required} onChange={handleChange} > 120 <NumberInputField /> 121 <NumberInputStepper> 122 <NumberIncrementStepper /> 123 <NumberDecrementStepper /> 124 </NumberInputStepper> 125 </NumberInput> 126 <Slider flex="1" focusThumbOnChange={false} value={time_required} onChange={handleChange} > 127 <SliderTrack> 128 <SliderFilledTrack /> 129 </SliderTrack> 130 <SliderThumb fontSize="sm" boxSize="32px" children={time_required} /> 131 </Slider> 132 </Flex> 133 <Input type="submit" value="レシピ登録" /> 134 </form> 135 </Box> 136 </Flex> 137 </> 138 ); 139} 140

##試したこと
strong parameterがおかしいのかと疑い、

def post_params params.require(:recipe).permit( :user_id, :title, :time_required, :food, :process, image: )

def post_params params.require(:recipe).permit( :user_id, :title, :time_required, :food, :process, image:[:data,:name] //またはimage:{}と変更  )

と変えてもエラー内容は変わりありませんでした。

##バージョン
ruby 3.0.0p0 (2020-12-25 revision 95aff21468) [x86_64-darwin19]
Rails 6.1.3.1
"react": "17.0.2",

##参考サイト

https://qiita.com/togo_mentor/items/8253315a4d464521b90a

https://qiita.com/mochio/items/45b9172a50a6ebb0bee0

お知恵をいただけるとありがたいです。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

まだ回答がついていません

会員登録して回答してみよう

アカウントをお持ちの方は

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.46%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問