One, problems and ideas
Recently in the rails + react + MySQL basic framework to write a CMS + client project, which involves the image upload and display, the following simple ideas, as for the deployment of the project, should be in the end of the winter break to share.
The main problem with uploading and displaying pictures in rails is:
Where does the picture exist?
Picture format size?
How does the client display the picture?
Because it's a small project, estimate up to 1000 pictures, up to 1G of space, so take a relatively simple approach: The picture is saved in the Rails public folder (that is, in the host where the project is deployed), and if the picture is more, it is recommended to use the services provided by Amazon Cloud S3 (understood as a hard drive, S3 provides an interface for you to access things, secure, and manage conveniently).
The general idea is that the front end through the <input type= "file"/> Select files, send AJAX requests to the back-end of the Controller,controller the requested picture data to size, type conversion after saving to the local designated folder, Returns the path at the same time to display the picture.
Second, the practice
The idea is relatively simple, so the words do not say more directly on the code:
The front-end code is integrated in a picture upload component written by react, and the IMAGE_UPLOADER.JS.JSX code is as follows
var Imageuploader = React.createclass ({
Getinitialstate:function () {
return {
Url:this.props.url
};
},
Onfileselect:function (e) {
var that = this;
var files = e.target.files;
if (files.length <= 0) {
Alertmodal.showwithprops ("No file selected");
Return
}
var data = new FormData ();
$.each (Files, function (key, value) {
Data.append (' file ', value);
Data.append (' type ', That.props.type)
});
This.upload (data);
},
Upload:function (data) {
var that = this;
if (!data) {
Return
} else {
This.refs.filebtn.disabled = true;
$ ("#loading-modal"). Modal (' show ');
$.ajax ({
URL: '/missions/upload_image ',
Type: ' Post ',
Data:data,
Processdata:false,
Contenttype:false
). Done (function (res) {
Console.log (RES);
That.setstate ({url:res.url});
}). Fail (function (ERR) {
Console.log (ERR);
Alertmodal.showwithprops ("Upload Failed");
}). Always (function () {
$ ("#loading-modal"). Modal (' hide ');
that.refs.filebtn.disabled = false;
});
}
},
Handleurlchange:function (e) {
This.setstate ({url:e.target.value});
},
Render:function () {
var form_input_name = This.props.model + "[Thumb]";
var form_input_id = this.props.model+ "_thumb";
Return (
<div classname= "Image-uploader-inputs row" >
<div classname= "Col-sm-8 image-input" >
<input classname= "Form-control" Name={form_input_name} id={form_input_id} ref= "Urlinput" Value={this.state.url | | ""} onchange={this.handleurlchange}/>
</div>
<div classname= "btn btn-primary btn-file image-input-btn" >
<input type= "File" Onchange={this.onfileselect} ref= "Filebtn"/>
</div>
</div>
);
}
});
The above focus on the upload function, the source code is the best document, if you want to see the source code needs too many comments, it must be I write the quality of the coding is not high enough, please criticize.
Two questions were encountered when writing this:
One, this component is used in the _form.html.slim, this form is used for the input of the information, we should be more familiar with the form, since to use in the form, that is to identify the component, indicate the name and ID, the code fragment as follows (from the above code interception):
var form_input_name = This.props.model + "[Thumb]";
var form_input_id = this.props.model+ "_thumb";
<input classname= "Form-control" Name={form_input_name} id={form_input_id} ref= "Urlinput" Value={this.state.url | | ""} onchange={this.handleurlchange}/>
Second, the use of <input type= "file"/> has a common problem with the UI is not beautiful.
Google/Baidu "input file btn" There will be many solutions, home network speed is not close. My approach is to set this btn to be transparent, the relevant code and CSS as follows:
<div classname= "btn btn-primary btn-file image-input-btn"
<input type= "file" onchange={ This.onfileselect} ref= "Filebtn"/>
</div>
. image-input-btn {
float:left;
width:15%;
background-image:image-url ("Upload.png");
background-size:30px;
Background-position:center;
background-repeat:no-repeat;
Input {
//hide file input button
Width:inherit;
opacity:0;
}
}
Ten
One
Take a look at the back-end code:
def upload_image
# => 'll resize later
Image_relative_path = "/assets/images/#{params[:type]}/#{time.now.to_i}.png"
Image_path = File.expand_path (File.dirname (__file__) + '/. /..') + "/public" + Image_relative_path
data = File.read (Params[:file].path)
img = file.new (image_path, "w+")
If img
Img.syswrite (data)
End
Img.close
Render json: {Url:image_relative_path}
End
10
11
12
13
The code is just as simple, building the file path, saving the file, and returning the path. Because the development progress reason here does not have the picture size and the type to make the revision (in order to reduce the data transmission quantity, in the front the size modification is more reasonable), later review this part of code will update this blog again.
It is worth saying that:
Picture naming problem, the use of timestamp, the name will not repeat, in order to facilitate management, the different types of pictures in different folders, but only the time stamp to name the available information is too small, not conducive to the management of operators, later will carefully consider this issue.
A problem with the path, in the back-end code, rails can place the picture anywhere in the Rails project folder, but when the client displays the picture, it can only access the contents of the public folder, and then decides to have the picture under the public folder.
Third, summing up and thinking
It doesn't take long to complete this function, but there's a lot of thinking outside the code. Small picture, even can use Git to back up the picture, perhaps not long-term, began to miss AWS good, disaster-tolerant to AWS processing best, and then interviewed a bit AWS S3