ruby-on-rails - 如何使用 React 的回形针向 Rails API 发出带有图像的 API 发布请求
问题描述
我正在开发一个应用程序,它分别具有客户端 React 和服务器端 Ruby on Rails(这意味着我没有使用“react_on_rails”或“react-rails”gem)。我正在使用paperclip
gem 来处理 Rails 中的图像。
我有模型帖子,它有一个图像和如下属性
# schema.rb
create_table "posts", force: :cascade do |t|
t.string "title"
t.string "image"
t.text "content"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.integer "user_id"
t.string "image_file_name"
t.string "image_content_type"
t.bigint "image_file_size"
t.datetime "image_updated_at"
t.boolean "published", default: false
t.datetime "published_at"
t.index ["user_id"], name: "index_posts_on_user_id"
end
这是post.rb
class Post < ApplicationRecord
has_attached_file :image
validates_attachment_content_type :image, content_type: /\Aimage\/.*\z/
belongs_to :user
validates :title, :image, :content, presence: true
has_many :users_posts, through: :bookmarks
has_many :users_posts, through: :user_like_posts
has_many :users_posts, through: :try_and_likes
has_many :comments
default_scope {order(published_at: :desc)}
end
以下是 React 组件中的新帖子表单
import React, { Component } from 'react';
import { Form } from 'semantic-ui-react';
import CKEditor from "react-ckeditor-component";
import axios from 'axios';
import history from '../../history';
import { AuthWrapper } from '../../utils/auth_helpers';
import { getErrorMessages } from '../../utils/error_message_helpers';
import ErrorMessages from '../shared/ErrorMessages';
class NewPostForm extends Component {
constructor(props) {
super(props);
this.state = {
title: "", image: "", content: "", error_messages: [], client_image_url: ""
}
this.updateContent = this.updateContent.bind(this);
this.handleSubmit = this.handleSubmit.bind(this);
this.handleImageChange = this.handleImageChange.bind(this);
this.handleChange = this.handleChange.bind(this);
this.onChange = this.onChange.bind(this);
this.onBlur = this.onBlur.bind(this);
}
handleChange(event) {
this.setState({ [event.target.name]: event.target.value });
}
handleImageChange(event) {
event.preventDefault();
let image_url = window.URL.createObjectURL(event.target.files[0]);
this.setState({image: image_url});
}
handleSubmit(event) {
event.preventDefault();
const user = this.props.user;
if (event.target.name === "save") {
axios.post("/api/v1/users/" + user.id + "/posts?published=false",
{
post: {
title: this.state.title, image: this.state.image, content: this.state.content,
user_id: user.id
}
})
.then((result) => {
history.replace("/community");
}).catch((err) => {
let errors = getErrorMessages(err);
this.setState({error_messages: errors});
});
} else if (event.target.name === "post") {
axios.post("/api/v1/users/" + user.id + "/posts?published=true",
{
post: {
title: this.state.title, image: this.state.image, content: this.state.content,
user_id: user.id
}
})
.then(() => {
history.replace("/community");
}).catch((err) => {
let errors = getErrorMessages(err);
this.setState({error_messages: errors});
});
}
}
updateContent(newContent) {
this.setState({
content: newContent
})
}
onChange(evt) {
var newContent = evt.editor.getData();
this.setState({
content: newContent
})
}
onBlur(evt) {}
afterPaste(evt) {}
render() {
let image_field = null;
if (this.state.image === "") {
image_field = <div className="customized-file-input-container"><input id="image-file" type="file" name="image" onChange={this.handleImageChange} className="customized-file-input" accept="image/*" required></input><label for="image-file"><i className="fa fa-upload"></i> Choose a file</label></div>
} else {
image_field = <img className="uploaded-post-image" src={this.state.image} alt=""></img>
}
return (
<div>
<Form id="new-post-container">
<h1>New Post</h1>
<ErrorMessages error_messages={this.state.error_messages} />
<p>Title</p>
<input className="form-control" type="text" name="title" onChange={this.handleChange} required></input>
<CKEditor
activeClass="p10"
content={this.state.content}
events={{
"blur": this.onBlur,
"afterPaste": this.afterPaste,
"change": this.onChange
}}
/>
<div className="new-post-bottom-container">
{image_field}
<div>
<input className="btn color-reverse-button contact-submit-button" type="submit" name="save" value="Save" onClick={this.handleSubmit}></input>
<input className="btn color-reverse-button contact-submit-button" type="submit" name="post" value="Post" onClick={this.handleSubmit}></input>
</div>
</div>
</Form>
</div>
)
}
}
const WrappedNewPostForm = AuthWrapper(NewPostForm);
export default WrappedNewPostForm;
我正在使用createObjectURL()
在客户端显示上传的图像。我尝试使用为图像生成的“blob:....”URL,但是这个给出了以下错误。
Paperclip::AdapterRegistry::NoHandlerError (No handler found for "blob:http://localhost:3000/4c001255-53ad-45c0-8261-d706c5132383"):
这样做的问题是因为 URL 需要以“http”开头,但这以“blob”开头,就像我删除了“blob”部分一样,它不会显示此错误,但另一个错误说它找不到图像。有谁知道如何使用图像正确地向 Rails API 发出发布请求paperclip
?
让我知道是否缺少某些重要信息。
解决方案
弃用通知
由于安全和支持等原因,现在强烈建议在 Rails 中使用ActiveStorage来处理服务器端的文件。为了鼓励开发人员追求 ActiveStorage,现在不推荐使用 Paperclip。阅读更多关于为什么在这里。
感谢 Thoughtbot 和 Rails。
推荐阅读
- javascript - 从 MediaRecorder blob 部分创建新的 Blob 会导致空 Blob
- python - 带有熊猫样式格式的表格和链接格式
- c# - 识别 XDocument 中的 HTML 节点以替换并转换为 Json
- java - 在 Java 中评估 XPath 表达式时出现异常
- java - 尝试计算相同的值两次时,HashMap 的循环不正确且超出范围
- c++ - Direct X 9 -“对 Direct3DCreate9@4 的未定义引用”
- android - 即使在交换属性后,Android 资源编译也会失败
- javascript - 将 HTML/JavaScript 形式的答案保存到用户指定的 .txt 文件时遇到问题
- java - 休眠Spring Data JPA如何保存带有id的对象
- r - 未找到 Python 安装,未加载 Python 绑定