Я работаю над приложением, которое имеет клиентскую сторону React и серверную часть Ruby on Rails по отдельности (то есть я не использую гем «response_on_rails» или «Reaction-rails»).Я использую paperclip
gem для обработки изображений в Rails.
У меня есть модель Post, которая имеет одно изображение и атрибуты, такие как следующие
# 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()
для отображения загруженного изображения на стороне клиента.Я попытался использовать URL-адрес blob: ...., сгенерированный для изображения, но этот выдал следующую ошибку:
Paperclip::AdapterRegistry::NoHandlerError (No handler found for "blob:http://localhost:3000/4c001255-53ad-45c0-8261-d706c5132383"):
Проблема в том, что URL-адрес должен начинаться с«http», но это начинается с «blob», как будто я удаляю часть «blob», она не будет отображать эту ошибку, но другая ошибка говорит, что она не может найти изображение.Кто-нибудь знает, как правильно сделать пост-запрос к Rails API с изображением, используя paperclip
?
Дайте мне знать, если какая-то важная информация отсутствует.