我尝试了各种解决方案,为什么会出现此错误?完全无法理解
我试图从网站删除cloudinary上传部分。
这意味着用户可以在我的博客张贴没有上传图像。
图像是必要的,所以我试图改变源代码,但这个错误不会消失在任何代价
this.$__.validationError = new ValidationError(this);
[0] ^
[0]
[0] ValidationError: Post validation failed: body: Cast to string failed for value "{
[0] _immutable: {
[0] allowUndo: true,
[0] currentContent: {
[0] entityMap: {},
[0] blockMap: [Object],
[0] selectionBefore: [Object],
[0] selectionAfter: [Object]
[0] },
[0] decorator: { _decorators: [Array] },
[0] directionMap: { idih: 'LTR' },
[0] forceSelection: false,
[0] inCompositionMode: false,
[0] inlineStyleOverride: null,
[0] lastChangeType: 'insert-characters',
[0] nativelyRenderedContent: null,
[0] redoStack: [],
[0] selection: {
[0] anchorKey: 'idih',
[0] anchorOffset: 5,
[0] focusKey: 'idih',
[0] focusOffset: 5,
[0] isBackward: false,
[0] hasFocus: false
[0] },
[0] treeMap: { idih: [Array] },
[0] undoStack: [ [Object] ]
[0] }
[0] }" (type Object) at path "body", image.publicId: Path `image.publicId` is required., image.url: Path `image.url` is required.
这是我的postmodel.js,我删除必需的:真。但错误是相同的
const mongoose = require('mongoose');
const Schema = mongoose.Schema;
const PostSchema = new Schema(
{
title: { type: String, required: true },
image: { url: { type: String, required: true }, publicId: { type: String, required: true } },
body: { type: String, required: true },
likes: [{ type: mongoose.Types.ObjectId, ref: 'User' }],
unicorns: [{ type: mongoose.Types.ObjectId, ref: 'User' }],
bookmarks: [{ type: mongoose.Types.ObjectId, ref: 'User' }],
tags: [{ type: mongoose.Types.ObjectId, required: true, ref: 'Tag' }],
comments: [{ type: mongoose.Types.ObjectId, required: true, ref: 'Comment' }],
author: { type: mongoose.Types.ObjectId, required: true, ref: 'User' },
},
{
timestamps: true,
}
);
module.exports = mongoose.model('Post', PostSchema);
这是我的后控制器,我试图改变和删除上传部分从网站,但我不能后3天。
后控制器.js
const Post = require('../model/Post');
const User = require('../model/User');
const Tag = require('../model/Tag');
const Comment = require('../model/Comment');
const cloudinary = require('../config/cloudinary');
const { uploadToCloudinary } = require('../utils/cloudinary');
const { getPostParams, unCapitalizeFirstLetter } = require('../helpers/string');
const { createTags, updateTags, deleteTags } = require('./tagsController');
const {
likeNotification,
removeLikeNotification,
postNotification,
removePostNotification,
} = require('./notificationsController');
const createPost = async (req, res) => {
const { title, file, body, tags, authorUsername } = req.body;
const { url, public_id: publicId } = await uploadToCloudinary(file, 'Posts');
const author = await User.findOne({ username: authorUsername }).exec();
const formattedTags = tags
.trim()
.split(',')
.map(w => w.trim().replace(/ /g, '-'));
const createdPost = await Post.create({
title,
image: { url, publicId },
body,
author: author._id,
});
author.followers.map(followerId => {
(async () => {
await postNotification(author._id, createdPost._id, followerId);
})();
});
await createTags(formattedTags, createdPost);
author.posts.push(createdPost._id);
await author.save();
res.status(200).json(createdPost.toObject({ getters: true }));
};
const getPost = async (req, res) => {
const author = await User.findOne({ username: req.params.username }).exec();
const authorId = await author?.toObject({ getters: true }).id;
const { postTitle, postId } = getPostParams(req.params.postUrl);
const foundPost = await Post.findOne({
author: authorId,
title: postTitle,
_id: postId,
})
.populate('author')
.populate('comments')
.populate('tags')
.exec();
res.status(200).json(foundPost.toObject({ getters: true }));
};
const getPosts = async (req, res) => {
const { userId } = req.params;
const posts = await Post.find(userId ? { bookmarks: userId } : {})
.sort({ createdAt: -1 })
.populate('author')
.populate('tags');
if (!posts) res.status(204).json('No posts found');
res.status(200).json(posts.map(post => post.toObject({ getters: true })));
};
const updatePost = async (req, res) => {
const authorId = await User.findOne({ username: req.params.username }).exec();
const { postTitle, postId } = getPostParams(req.params.postUrl);
const { url, public_id: publicId } = await uploadToCloudinary(req.body.image.url, 'Posts');
await cloudinary.uploader.destroy(req.body.image.publicId);
req.body.image = { url, publicId };
const formattedTags = req.body.tags
.trim()
.split(',')
.map(w => w.trim().replace(/ /g, '-'));
const post = await Post.findOne({
author: authorId,
title: postTitle,
_id: postId,
})
.populate('author')
.populate('tags');
Object.keys(req.body).map(key => {
if (key !== 'tags') post[key] = req.body[key];
});
await updateTags(formattedTags, post);
await post.save();
res.status(200).json(post.toObject({ getters: true }));
};
const deletePostsByUserId = async user => {
const { _id: userId } = user;
user.comments.forEach(commentId => {
(async () => {
await Post.updateMany({ comments: commentId }, { $pull: { comments: commentId } });
})();
});
const posts = await Post.find({ author: userId }).populate('tags');
['likes', 'unicorns', 'bookmarks'].forEach(k => {
(async () => {
await Post.updateMany({ [k]: userId }, { $pull: { [k]: userId } });
})();
});
posts.forEach(post => {
(async () => {
await deleteTags(
post.tags.map(({ name }) => name),
post,
true
);
await cloudinary.uploader.destroy(post.image.publicId);
await Post.deleteOne({ _id: post._id });
})();
});
await Comment.deleteMany({ author: userId });
};
const deletePost = async (req, res) => {
const author = await User.findOne({ username: req.params.username }).exec();
const { postTitle, postId } = getPostParams(req.params.postUrl);
await cloudinary.uploader.destroy(req.body.publicId);
const foundPost = await Post.findOne({
author: author._id,
title: postTitle,
_id: postId,
})
.populate('tags')
.exec();
if (!foundPost) return res.sendStatus(204);
const comments = await Comment.find({ parentPost: postId }).populate({
path: 'author',
populate: 'followers',
});
comments.forEach(({ author }) =>
(async () => {
author.comments.forEach(comment => author.comments.pull(comment));
})()
);
author.posts.pull(postId);
await author.save();
await Comment.deleteMany({ parentPost: postId });
await deleteTags(
foundPost.tags.map(({ name }) => name),
foundPost,
true
);
removePostNotification(author._id, foundPost._id, author.followers);
await Post.deleteOne({ _id: foundPost._id });
res.status(200).json(foundPost.toObject({ getters: true }));
};
const postReaction = async (req, res) => {
const { userId } = req.body;
const { action, postUrl } = req.params;
const { postTitle, postId } = getPostParams(postUrl);
const isUndoing = action.includes('remove');
const actionKey = isUndoing
? unCapitalizeFirstLetter(action.replace('remove', '')) + 's'
: action + 's';
const author = await User.findOne({ username: req.params.username }).exec();
const authorId = await author.toObject({ getters: true }).id;
const updatedPost = await Post.findOneAndUpdate(
{ author: authorId, title: postTitle, _id: postId },
isUndoing ? { $pull: { [actionKey]: userId } } : { $addToSet: { [actionKey]: userId } },
{ new: true, timestamps: false }
);
if (isUndoing) await removeLikeNotification(userId, updatedPost._id, authorId);
else await likeNotification(userId, updatedPost._id, authorId);
res.status(200).json(updatedPost.toObject({ getters: true }));
};
module.exports = {
createPost,
getPosts,
getPost,
updatePost,
deletePost,
deletePostsByUserId,
postReaction,
};
这是我的前端部分new-post.jsx
import 'easymde/dist/easymde.min.css';
import { useContext, useEffect, useRef, useState } from 'react';
import { useDispatch, useSelector } from 'react-redux';
import { useNavigate } from 'react-router-dom';
import SimpleMDE from 'react-simplemde-editor';
import tw from 'twin.macro';
import Error from '../../common/Error';
import LoadingSpinner from '../../common/LoadingSpinner';
import RouteWrapper from '../../common/RouteWrapper';
import socketContext from '../../context/SocketContext';
import { selectCurrentUser } from '../../core/features/auth/authSlice';
import { useCreatePostMutation } from '../../core/features/posts/postsApiSlice';
import { useGetUserDashboardQuery } from '../../core/features/users/usersApiSlice';
import useBase64 from '../../hooks/useBase64';
import useRequireAuth from '../../hooks/useRequireAuth';
import { Editor } from "react-draft-wysiwyg";
// import "../../../node_modules/react-draft-wysiwyg/dist/react-draft-wysiwyg.css";
// import React, { Component } from 'react';
import "../NewPost/react-draft-wysiwyg.css"
// import "react-draft-wysiwyg/dist/react-draft-wysiwyg.cs";
// import LiveMarkdown from '../markdowneditor/markdowneditor';
// import EasyMDE from 'easymde';
const NewPost = () => {
const [title, setTitle] = useState('');
const [file, setFile] = useState('');
const [body, setBody] = useState('');
const [tags, setTags] = useState('');
const [isTagsFocused, setIsTagsFocused] = useState(false);
const [inputsFilled, setInputsFilled] = useState(false);
const filePickerRef = useRef();
const titleRef = useRef();
const [createPost, { isLoading, isError }] = useCreatePostMutation();
const navigate = useNavigate();
const currentUser = useSelector(selectCurrentUser);
const dispatch = useDispatch();
const previewURL = useBase64(file);
const { isAuthed, handleAuth } = useRequireAuth();
const { socket } = useContext(socketContext);
const { data: user } = useGetUserDashboardQuery(currentUser.username);
useEffect(() => titleRef.current.focus(), []);
useEffect(() => {
if (title && body && tags) setInputsFilled(true);
else setInputsFilled(false);
}, [title, body, tags]);
const handleSubmit = async () => {
if (inputsFilled) {
if (isAuthed) {
try {
const { id } = await createPost({
title,
file: previewURL,
body,
tags,
authorUsername: currentUser.username,
}).unwrap();
socket.emit('post', {
sender: currentUser,
receivers: user?.followers,
post: { title, id },
});
setTitle('');
setFile('');
setBody('');
setTags('');
navigate('/');
} catch (err) {
console.log(err);
}
} else handleAuth();
}
};
return (
<RouteWrapper>
<Wrapper>
{isLoading && <LoadingSpinner />}
{!isLoading && (
<NewPostWrapper>
<Heading>ایجاد پست جدید</Heading>
<InputWrapper>
<Label dir='rtl' htmlFor='title'>موضوع</Label>
<Input
dir='rtl'
ref={titleRef}
id='title'
value={title}
onBlur={e => setTitle(prev => prev.trim())}
onChange={e => setTitle(e.target.value)}
required
/>
</InputWrapper>
<InputWrapper>
// <Input
type='file'
ref={filePickerRef}
onChange={e => setFile(e.target.files[0])}
style={{ display: 'none' }}
/>
<ImagePreview src={previewURL.toString()} alt='عکس انتخاب کنید' />
<Button onClick={() => filePickerRef.current.click()}>انتخاب آواتار</Button>
</InputWrapper>
<InputWrapper2>
{/* <SimpleMDE value={body} onChange={setBody} required /> */}
<Editor
editorState={body}
toolbarClassName="toolbarClassName"
wrapperClassName="wrapperClassName"
editorClassName="editorClassName"
onEditorStateChange={setBody}
textAlignment="right"
placeholder="اینجا تایپ کنید"
/>;
</InputWrapper2>
<InputWrapper>
<Label htmlFor='tags'>
تگ ها
{isTagsFocused && (
<Span>تگ ها با کاما جدا شده هست</Span>
)}
</Label>
<Input
id='tags'
value={tags}
onFocus={() => setIsTagsFocused(true)}
onBlur={() => setIsTagsFocused(false)}
onChange={e => setTags(e.target.value.replace(/ /g, ''))}
required
/>
</InputWrapper>
<Submit onClick={handleSubmit}>تایید</Submit>
{isError && <Error>خطاا در انجام عملیات . دوباره امتحان کنید</Error>}
{!inputsFilled && <Error>تمام فیلدها اجباری هست</Error>}
</NewPostWrapper>
)}
</Wrapper>
</RouteWrapper>
);
};
const Submit = tw.button`bg-lighter-gray hover:bg-light-gray rounded-md text-center py-2 px-1 w-full text-sm`;
const ImagePreview = tw.img`w-32 h-32 mx-auto border border-gray flex justify-center items-center text-center object-cover`;
const Input = tw.input`py-1 px-2 rounded-md outline-none border-2 border-solid border-gray focus:border-blue`;
const Label = tw.label`font-bold text-dark-gray`;
const Span = tw.p`inline ml-sm`;
const InputWrapper = tw.div`flex flex-col gap-2 `;
const Button = tw.button`bg-lighter-gray hover:bg-light-gray rounded-md text-center py-2 px-1 w-28 text-sm mx-auto`;
const Heading = tw.h1`text-dark-gray text-center`;
const NewPostWrapper = tw.div`bg-white w-3/5 mob:(w-full px-4) mx-auto py-20 px-8 [&>*:not(:last-child)]:mb-md`;
const Wrapper = tw.div`flex items-center`;
const InputWrapper2 = tw.div`border border-gray`;
export default NewPost;
我试图删除文件更改和更改。但这个错误不会消失。请如果有人知道这个答案帮助我
1条答案
按热度按时间kxe2p93d1#
当您尝试创建一个没有值的帖子时,会发生此错误,但在您的架构中,您已根据需要设置了标题、正文等的值,因此出现此错误,请检查您是否正在从前端调用创建帖子,但没有值。
试着检查一下这个useEffect,在这里你设置了你的inputsfilled,我敢打赌,即使值是空的,它也会设置inputsfilled为真。
后端错误是因为您尝试使用所需参数创建Post,但参数值为空。
希望这能有所帮助。这甚至可能不是问题所在。如果我弄错了,我的错。