バックエンドをrails,フロントをReactで開発を行っています。
Rails API CarrierWave
React
実現したいこと
フロント側であるReactからアップロードした画像をバックエンド側で保存?api通信できるようにしたい。
Rails 側でGemのCarrierWaveを使用しています。
CarrierWaveの設定などは下記リンクを参考に行なっています。
https://note.com/matsushoooo12/n/n6398a6600d20
発生している問題・エラーメッセージ
PUT http://localhost:3001/api/v1/users/9
500 (Internal Server Error) とエラーが出てしまいます。
users_controller
class Api::V1::UsersController < ApplicationController before_action :set_user, only: %i[show update] def index # 都道府県が同じで性別の異なるユーザーを取得(自分以外) users = User.all.order("created_at DESC") render json: { status: 200, users: users } end def show render json: { status: 200, user: @user } end def update @user.name = user_params[:name] @user.profile = user_params[:profile] @user.image = user_params[:image] if user_params[:image] != "" if @user.save render json: { status: 200, user: @user } else render json: { status: 500, message: "更新に失敗しました" } end end private def set_user @user = User.find(params[:id]) end def user_params params.permit(:name, :profile, :image) end end
Routes.rb
Rails.application.routes.draw do namespace :api do namespace :v1 do resources :test, only: %i[index] resources :englishlists resources :my_lists, only: %i[create] resources :users, only: %i[index show update] mount_devise_token_auth_for 'User', at: 'auth', controllers: { registrations: 'api/v1/auth/registrations' } namespace :auth do resources :sessions, only: %i[index] end end end end
api関係
import applyCaseMiddleware from "axios-case-converter" import axios from "axios" const options = { ignoreHeaders: true } const client = applyCaseMiddleware( axios.create({ baseURL:"http://localhost:3001/api/v1" }), options) export default client import client from "./client" import Cookies from "js-cookie" export const getUser = (id) => { return client.get(`users/${id}`) } export const updateUser = (id , data) => { return client.put(`users/${id}`, data) }
const Home = () => { const { isSignedIn, setIsSignedIn, currentUser, setCurrentUser } = useContext(AuthContext) const classes = useStyles() const histroy = useNavigate() const [editFormOpen, setEditFormOpen] = useState(false) const [name, setName] = useState(currentUser) const [prefecture, setPrefecture] = useState(currentUser?.prefecture || 0) const [profile, setProfile] = useState(currentUser?.profile) const [image, setImage] = useState("") const [preview, setPreview] = useState("") // アップロードした画像の情報を取得 const uploadImage = useCallback((e) => { const file = e.target.files[0] setImage(file) }, []) // 画像プレビュー const previewImage = useCallback((e) => { const file = e.target.files[0] setPreview(window.URL.createObjectURL(file)) }, []) const createFormData = () => { const formData = new FormData() formData.append("name", name || "") formData.append("profile", profile || "") formData.append("image", image) return formData } const handleSubmit = async (e) => { e.preventDefault() const data = { name: name, profile: profile, image: image } // const data = await createFormData() console.log(data) try { const res = await updateUser(currentUser?.id, data) console.log(res) if (res.status === 200) { setEditFormOpen(false) setCurrentUser(res.data.user) console.log("Update user successfully!") } else { console.log(res.data.message) } } catch (err) { console.log(err) console.log("Failed in updating user!") } } // サインアウト用の処理 const handleSignOut = async (e) => { try { const res = await signOut() if (res.data.success === true) { // Cookieから各情報を削除 Cookies.remove("_access_token") Cookies.remove("_client") Cookies.remove("_uid") setIsSignedIn(false) histroy.push("/signin") console.log("Succeeded in sign out") } else { console.log("Failed in sign out") } } catch (err) { console.log(err) } } return ( <> { isSignedIn && currentUser ? ( <> <Card className={classes.card}> <CardContent> <Grid container justify="flex-end"> <Grid item> <IconButton onClick={() => setEditFormOpen(true)} > <SettingsIcon color="action" fontSize="small" /> </IconButton> </Grid> </Grid> <Grid container justify="center"> <Grid item> <Avatar alt="avatar" src={currentUser?.image.url} className={classes.avatar} /> </Grid> </Grid> <Grid container justify="center"> <Grid item style={{ marginTop: "1.5rem"}}> <Typography variant="body1" component="p" gutterBottom> {currentUser?.name} </Typography> <Divider style={{ marginTop: "0.5rem"}}/> <Typography variant="body2" component="p" gutterBottom style={{ marginTop: "0.5rem", fontWeight: "bold" }} > 自己紹介 </Typography> { currentUser.profile ? ( <Typography variant="body2" component="p" color="textSecondary"> {currentUser.profile} </Typography> ): ( <Typography variant="body2" component="p" color="textSecondary"> よろしくお願いいたします。 </Typography> ) } <Button variant="outlined" onClick={handleSignOut} color="primary" fullWidth startIcon={<ExitToAppIcon />} style={{ marginTop: "1rem"}} > サインアウト </Button> </Grid> </Grid> </CardContent> </Card> <form noValidate autoComplete="off"> <Dialog open={editFormOpen} keepMounted onClose={() => setEditFormOpen(false)} > <DialogTitle style={{ textAlign: "center"}}> プロフィールの変更 </DialogTitle> <DialogContent> <TextField variant="outlined" required fullWidth label="名前" value={name} margin="dense" onChange={(e) => setName(e.target.value)} /> <TextField placeholder="1000文字以内で書いてください。" variant="outlined" multiline fullWidth label="自己紹介" rows="8" value={profile} margin="dense" onChange={(e) => { setProfile(e.target.value) }} /> <div className={classes.imageUploadBtn}> <input accept="image/*" className={classes.input} id="icon-button-file" type="file" onChange={(e) => { uploadImage(e) previewImage(e) }} /> <label htmlFor="icon-button-file"> <IconButton color="primary" aria-label="upload picture" component="span" > <PhotoCamera /> </IconButton> </label> </div> { preview ? ( <Box className={classes.box} > <IconButton color="inherit" onClick={() => setPreview("")} > <CancelIcon /> </IconButton> <img src={preview} alt="preview img" className={classes.preview} /> </Box> ) : null } </DialogContent> <DialogActions> <Button onClick={handleSubmit} color="primary" disabled={!name || !profile ? true : false} > 送信 </Button> </DialogActions> </Dialog> </form> </> ) : ( <></> ) } <Link to="/list">List</Link> </> ) } export default Home
まだ回答がついていません
会員登録して回答してみよう