当我使用来自反应的载波上传文件时,文件变为 NULL
File becomes NULL when I upload the file with carrierwave from react
我的环境在这里:
Environment
Version
Rails
7.0.0
Carrierwave
2.2.2
React
18.0
Next.js
12.1.4
Carrierwave 已在我的应用程序中使用,并且运行良好。
现在,我将客户端替换为 rails 来做出反应。
Carrierwave 的当前配置在这里:
carrierwave.rb
#config/initializers/carrierwave.rb
if Rails.env.production?
CarrierWave.configure do |config|
config.fog_credentials = {
provider: 'AWS',
aws_access_key_id: ENV['S3_ACCESS_KEY'],
aws_secret_access_key: ENV['S3_SECRET_KEY'],
region: ENV['S3_REGION']
}
config.fog_authenticated_url_expiration = 86400
config.fog_directory = 'something'
config.cache_storage = :fog
config.fog_public = false
end
else
CarrierWave.configure do |config|
config.fog_credentials = {
provider: 'AWS',
aws_access_key_id: ENV['S3_ACCESS_KEY'],
aws_secret_access_key: ENV['S3_SECRET_KEY'],
region: ENV['S3_REGION']
}
config.fog_authenticated_url_expiration = 86400
config.fog_directory = 'something'
config.cache_storage = :fog
config.fog_public = false
end
end
cv_uploader.rb
#app/uploaders/cv_uploader.rb
class CvUploader < CarrierWave::Uploader::Base
storage :fog
def store_dir
"uploads/#{model.class.to_s.underscore}/#{mounted_as}/#{model.id}"
end
def filename
original_filename if original_filename
end
end
user.rb
class User < ApplicationRecord
mount_uploader :cv, CvUploader
...
所以我想我只需要将文件作为文件名保存到数据库并从 React 中读取它。
我写了这个:
new.tsx
export default function UsersNewPage() {
const [cv, setCv] = React.useState<string>("");
const handleChangeCv = useMemo(
() => (event: any) => setCv(event.target.value),
[cv]
);
const createUser = async () => {
dispatch(setLoading(true));
await axios
.post(`${process.env.NEXT_PUBLIC_ENDPOINT}/admin/create_user`, {
headers: {
...
},
params: {
...
cv: cv,
...
},
})
.then((response) => {
...
}
})
.catch(() => {
...
});
}
};
return(
<label htmlFor="contained-button-file">
<Input
id="contained-button-file"
type="file"
value={cv}
onChange={handleChangeCv}
/>
<IconButton onClick={handleDeleteCv}>
<DeleteIcon />
</IconButton>
</label>
)
users_controller.rb
def create_user
if User.find_by(email: params[:params][:email])
return render json: { not_exist: true }
end
User.create(str_user)
render json: { not_new: true }
end
private
def str_user
params[:params].permit(
:cv,
)
end
但是如果我发布的文件名是fuga.xls
,响应将是"C:\fakepath\fuga.xls"
。
我不明白C:\fakepath\
从哪里来...
并执行 User.create(str_user)
,cv 将为 NULL
。
似乎没有成功保存文件。
我试图解决这个问题,我写道:
carrierwave.rb
##ADD
elsif Rails.env.development?
CarrierWave.configure do |config|
config.asset_host = 'http://localhost:3000' #Rails port is 3000
config.storage = :file
config.cache_storage = :file
end
cv_uploader.rb
# :fog→:file
storage :file
但是没办法。
有人有解决办法吗?
谢谢。
我解决了这个问题。
错误的原因都是我没有转换文件类型。
所以我改变了视图
<label htmlFor="contained-button-file">
<Input
id="contained-button-file"
type="file"
// value={cv} <-- without value
onChange={(e: React.ChangeEvent<HTMLInputElement>) => {
handleChangeCv(e);
}}
/>
<IconButton onClick={handleDeleteCv}>
<DeleteIcon />
</IconButton>
</label>
正在读取文件
const handleChangeCv = useMemo(
() => (e: any) => {
const file = e.target.files[0];
setCv(file);
},
[cv]
);
转换为FormData
const createFormData = () => {
const formData = new FormData();
formData.append("user[cv]", cv!);
return formData;
};
发送至rails
const data = createFormData(); // <-- here!
dispatch(setLoading(true));
await axios
.post(`${process.env.NEXT_PUBLIC_ENDPOINT}/admin/create_user`, data, {
headers: {
"access-token": access_token!,
client: client!,
uid: uid!,
},
params: {
...
您可以像 params[:user][:cv]
一样阅读 rails 中的文件
就是这样!
我的环境在这里:
Environment | Version |
---|---|
Rails | 7.0.0 |
Carrierwave | 2.2.2 |
React | 18.0 |
Next.js | 12.1.4 |
Carrierwave 已在我的应用程序中使用,并且运行良好。
现在,我将客户端替换为 rails 来做出反应。
Carrierwave 的当前配置在这里:
carrierwave.rb
#config/initializers/carrierwave.rb
if Rails.env.production?
CarrierWave.configure do |config|
config.fog_credentials = {
provider: 'AWS',
aws_access_key_id: ENV['S3_ACCESS_KEY'],
aws_secret_access_key: ENV['S3_SECRET_KEY'],
region: ENV['S3_REGION']
}
config.fog_authenticated_url_expiration = 86400
config.fog_directory = 'something'
config.cache_storage = :fog
config.fog_public = false
end
else
CarrierWave.configure do |config|
config.fog_credentials = {
provider: 'AWS',
aws_access_key_id: ENV['S3_ACCESS_KEY'],
aws_secret_access_key: ENV['S3_SECRET_KEY'],
region: ENV['S3_REGION']
}
config.fog_authenticated_url_expiration = 86400
config.fog_directory = 'something'
config.cache_storage = :fog
config.fog_public = false
end
end
cv_uploader.rb
#app/uploaders/cv_uploader.rb
class CvUploader < CarrierWave::Uploader::Base
storage :fog
def store_dir
"uploads/#{model.class.to_s.underscore}/#{mounted_as}/#{model.id}"
end
def filename
original_filename if original_filename
end
end
user.rb
class User < ApplicationRecord
mount_uploader :cv, CvUploader
...
所以我想我只需要将文件作为文件名保存到数据库并从 React 中读取它。
我写了这个:
new.tsx
export default function UsersNewPage() {
const [cv, setCv] = React.useState<string>("");
const handleChangeCv = useMemo(
() => (event: any) => setCv(event.target.value),
[cv]
);
const createUser = async () => {
dispatch(setLoading(true));
await axios
.post(`${process.env.NEXT_PUBLIC_ENDPOINT}/admin/create_user`, {
headers: {
...
},
params: {
...
cv: cv,
...
},
})
.then((response) => {
...
}
})
.catch(() => {
...
});
}
};
return(
<label htmlFor="contained-button-file">
<Input
id="contained-button-file"
type="file"
value={cv}
onChange={handleChangeCv}
/>
<IconButton onClick={handleDeleteCv}>
<DeleteIcon />
</IconButton>
</label>
)
users_controller.rb
def create_user
if User.find_by(email: params[:params][:email])
return render json: { not_exist: true }
end
User.create(str_user)
render json: { not_new: true }
end
private
def str_user
params[:params].permit(
:cv,
)
end
但是如果我发布的文件名是fuga.xls
,响应将是"C:\fakepath\fuga.xls"
。
我不明白C:\fakepath\
从哪里来...
并执行 User.create(str_user)
,cv 将为 NULL
。
似乎没有成功保存文件。
我试图解决这个问题,我写道:
carrierwave.rb
##ADD
elsif Rails.env.development?
CarrierWave.configure do |config|
config.asset_host = 'http://localhost:3000' #Rails port is 3000
config.storage = :file
config.cache_storage = :file
end
cv_uploader.rb
# :fog→:file
storage :file
但是没办法。
有人有解决办法吗?
谢谢。
我解决了这个问题。
错误的原因都是我没有转换文件类型。
所以我改变了视图
<label htmlFor="contained-button-file">
<Input
id="contained-button-file"
type="file"
// value={cv} <-- without value
onChange={(e: React.ChangeEvent<HTMLInputElement>) => {
handleChangeCv(e);
}}
/>
<IconButton onClick={handleDeleteCv}>
<DeleteIcon />
</IconButton>
</label>
正在读取文件
const handleChangeCv = useMemo(
() => (e: any) => {
const file = e.target.files[0];
setCv(file);
},
[cv]
);
转换为FormData
const createFormData = () => {
const formData = new FormData();
formData.append("user[cv]", cv!);
return formData;
};
发送至rails
const data = createFormData(); // <-- here!
dispatch(setLoading(true));
await axios
.post(`${process.env.NEXT_PUBLIC_ENDPOINT}/admin/create_user`, data, {
headers: {
"access-token": access_token!,
client: client!,
uid: uid!,
},
params: {
...
您可以像 params[:user][:cv]
一样阅读 rails 中的文件
就是这样!