ruby-on-rails - 使用 React、Ruby on rails 5 和 CarrierWave 多次上传文件
问题描述
我被一个问题困扰了大约 2 天。我可能正在寻找,但我找不到关于它的帖子......
因此,我将 Ruby on Rails 框架与 gem react on rails 一起使用,并尝试使用 CarrierWave gem 进行多次上传。
因此,当只有一个文件时,上传效果很好。但我采用了另一种策略,结果我最终不得不为单个模型上传多个文件。所以我创建了一个多态模型(如果我在其他地方需要它,它更通用)。
所以问题是我将数据从反应发送到我的控制器的那一刻。确实 JSON.stringify 不适用于对象文件,我不明白我该怎么做......
我的控制器
# POST /band_musics
# POST /band_musics.json
def create
@band_music = BandMusic.new({
:name => band_music_params[:name],
:phone => band_music_params[:phone],
:mail => band_music_params[:mail],
:style => band_music_params[:style],
:comment => band_music_params[:comment],
:status => band_music_params[:status],
:musics_attributes => JSON.parse(band_music_params[:musics_attributes]),
:youtubes_attributes => JSON.parse(band_music_params[:youtubes_attributes])
})
respond_to do |format|
if @band_music.save
format.html { redirect_to root_path, notice: 'Le groupe a bien été enregisté' }
format.json { render :show, status: :created, location: @band_music }
else
format.html { render :new }
format.json { render json: @band_music.errors, status: :unprocessable_entity }
end
end
end
我的band_music_params
def band_music_params
params.require(:band_music).permit(:name, :mail, :phone, :style, :comment, :status, :youtubes_attributes, :musics_attributes)
end
我的反应组件
import PropTypes from 'prop-types';
import React from 'react';
import ReactDropzone from 'react-dropzone'
export default class GroupForm extends React.Component {
static propTypes = {
};
/**
* @param props - Comes from your rails view.
*/
constructor(props) {
super(props);
this.state = {
files: {},
loading: false,
disabled: true,
};
}
submitGroupForm = (event) => {
event.preventDefault();
let response_files = {}
Object.keys(this.state.files).map((file, index) => {
response_files[index] = {
'lastMod' : this.state.files[file].sound.lastModified,
'lastModDate': this.state.files[file].sound.lastModifiedDate,
'name' : this.state.files[file].sound.name,
'size' : this.state.files[file].sound.size,
'type' : this.state.files[file].sound.type,
}
});
const file_array = JSON.stringify(response_files);
this.setState({ loading: true });
let formPayLoad = new FormData();
formPayLoad.append('band_music[musics_attributes]', file_array);
fetch(this.props.url, {
method: 'POST',
headers: {
'Accept': 'application/json',
'X-CSRF-Token': ReactOnRails.authenticityToken(),
},
body: formPayLoad,
}).then((response) => {
console.log(response)
});
}
onDrop = (files) => {
if (Object.keys(this.state.files).length === 3) return
var countFile = Object.keys(this.state.files).length
console.log(countFile)
files.forEach(file => {
let hash = this.state.files
hash[`${countFile}`] = { sound: file }
this.setState({
files: hash
});
});
}
render() {
console.log(this.state)
return (
<div>
<form onSubmit={this.submitGroupForm}>
<div className="form-group">
<label htmlFor="sound" className="color-primary">
Fichier(s) Audio(s)
</label>
<ReactDropzone
accept="audio/*"
onDrop={this.onDrop}
className="react-drop-zone-css"
>
{ Object.keys(this.state.files).length > 0 &&
<div className="fileContainer">
{Object.keys(this.state.files).map((file) => (
<p className="file">
<i className="fa fa-music fa-2x mb-2"></i>
{this.state.files[file].sound.name}
</p>
))}
{ Object.keys(this.state.files).length < 1 &&
<p className="plus">
<i className="fa fa-plus fa-3x mb-2"></i>
</p>
}
</div>
}
{ Object.keys(this.state.files).length === 0 &&
<div className="d-flex justify-content-center align-items-center w-100 h-100">
<p className="mb-0">Cliquez pour importer un fichier audio ! (3 fichiers max)</p>
</div>
}
</ReactDropzone>
</div>
<div className="row justify-content-center">
{
!!this.state.loading ? (
<input className="btn btn-lg bg-button color-white mt-3" type="submit" value="Chargement... Cette action peut prendre quelques minutes" />
) : (
<input className={"btn btn-lg bg-button color-white mt-3 " + (!!this.state.disabled ? 'disabled' : '')} disabled={!!this.state.disabled} type="submit" value="S'inscrire au tremplin" />
)
}
</div>
</form>
</div>
);
}
}
为简单起见,如何在参数中传递文件。在这里,我尝试将文件转换为 stringify 的经典对象,它不会出错,但不会将文件保存在多态模型中......
如果您需要我发布另一个文件以获得更多理解,请在评论中说明,提前谢谢您:)
解决方案
让我们从修复控制器方法开始:
# POST /band_musics
# POST /band_musics.json
def create
@band_music = BandMusic.new(band_music_params)
respond_to do |format|
if @band_music.save
format.html { redirect_to root_path, notice: 'Le groupe a bien été enregisté' }
format.json { render :show, status: :created, location: @band_music }
else
format.html { render :new }
format.json { render json: @band_music.errors, status: :unprocessable_entity }
end
end
end
没有实际意义:
- 像人类编译器一样复制哈希键。
Hash#slice
RoR 有很多类似的哈希方法Hash#except
。 - 手动 JSON 转换嵌套属性。
相反,您可以通过将哈希传递给#permit
.
def band_music_params
params.require(:band_music)
.permit(
:name, :mail, :phone, :style, :comment, :status,
youtubes_attributes: [:foo, :bar],
musics_attributes: [:lastMod, :lastModDate, :name, :size, :type]
)
end
这允许具有属性的哈希数组[:lastMod, :lastModDate, :name, :size, :type]
。当然,您还应该删除反应代码中将对象转换为 JSON 字符串的行:
// Don't do this.
const file_array = JSON.stringify(response_files);
推荐阅读
- python - Is there an easier way(pythonic) to write the following code?
- regex - How to use regular expression(/^ $/i) of MongoDB in go?
- reactjs - Next.js 配置文件中的 next/image 配置
- flutter - Flutter - Input TextField gets cleared by TextEditingController but the entered message appears to be 'still alive' (not empty)
- c++ - AWS 使用 QT 5 执行 API 请求
- pdf - Forge 查看器,PDF 镜像
- c# - 将托管 asp 核心记录为 Windows 服务时出错
- sql - SQL 上的平均时间
- php - 在订单电子邮件 woocommerce 中添加新添加的帐单地址和送货地址字段
- pandas - 将附加信息(数据)附加到数据框列值