Reputation: 3556
I have a file upload component in React that makes a POST to my Rails API:
class uploadFormState {
@observable file;
constructor() {
this.file = '';
}
@action.bound setFile(file){
this.file = file[0];
this.fileName = file[0].name;
}
@action.bound uploadFile() {
$.ajax({
url: AppConstants.APIEndpoints.USERLOCATIONS + '/1/photos/1/upload',
headers: { "Authorization": localStorage.getItem('authToken') },
data: this.file,
processData: false,
contentType: false,
type: 'POST',
success: function (data) {
alert(this.data.name + " uploaded successfully!");
}
});
}
}
export default new uploadFormState();
As you can see in the data field, I'm trying to pass in the original file name to the rails backend. The problem is, I don't know how to get these data params.
My upload method looks like this:
def upload
@photo.upload_model(request.body)
end
And the class method `upload_model' looks like this:
def upload_model(model_file)
model = StorageBucket.files.new(
key: "models/#{id}",
body: model_file.read,
public: true
)
model.save
update_columns model_url: model.public_url
end
I've tried changing the data
field in the ajax call to data: {file: this.file, fileName: this.file.name}
but I'm not sure how to access these two params from the rails side. It results it uploading a text of object Object
if I change the data params this way. request.body
is a StringIO
ruby type. The method itself works when the data field is this.file
(i.e. it uploads the file to google storage), however, the filename loses the extension, which isn't ideal.
So to sum up, how do I access the uploaded filename in the Rails backend?
Upvotes: 0
Views: 1055
Reputation: 3556
Big thanks to @kasperite for suggesting the use of FormData, which was a big part of this answer. I changed the ajax call to look like this:
@action.bound uploadFile() {
let form = new FormData();
form.append("file", this.file);
$.ajax({
url: AppConstants.APIEndpoints.USERLOCATIONS + '/1/photos/1/upload',
headers: { "Authorization": localStorage.getItem('authToken') },
data: form,
processData: false,
contentType: false,
type: 'POST',
success: function (data) {
alert(this.data.name + " uploaded successfully!");
}
});
}
And then changed my controller to look like this:
def upload
@photo.upload_model(params[:file].original_filename, params[:file].tempfile)
end
params[:file].original_filename
is the filename while params[:file].tempfile
is the actual file.
And my class method now looks like this:
def upload_model(original_filename, model_file)
model = StorageBucket.files.new(
key: "models/#{id}-#{original_filename}",
body: model_file.read,
public: true
)
model.save
update_columns model_url: model.public_url
end
Upvotes: 0
Reputation: 2478
Have you tried using FormData?In your case, it will be:
JS:
// Use FormData to build params
let form = new FormData();
form.append("file_name", file[0].name);
// Send form as part of ajax post
$.ajax({
...
data: form,
...
})
Then on the Rails side, you can get file_name
through params[:file_name]
(in controller)
That's a quick suggestion, hopefully it will help you.
Cheers
Upvotes: 1