ruby on rails爬坑圖片上傳及顯示的執行個體

來源:互聯網
上載者:User

一,問題及思路

最近在用 rails + react + mysql 基本架構寫一個cms + client的項目,裡面涉及到了圖片的上傳及顯示,下面簡單說說思路,至於這個項目的配置部署,應該會在寒假結束總結分享一下。

rails中圖片上傳及顯示要解決主要問題是:

圖片存在哪?
圖片格式大小?
用戶端怎麼顯示圖片?
因為這是個小項目,估計最多1000張圖片,最多佔用空間1G,所以採取相對簡便的方法: 圖片儲存在rails的public檔案夾裡(也就是儲存在部署該項目的主機中) ,如果圖片比較多的話,還是推薦用亞馬遜雲提供的服務 AWS S3 (理解為一個硬碟,S3提供了介面給你存取東西,安全,管理方便)。

大概的思路是,前端通過 <input type="file"/> 選擇檔案,發送ajax請求到後端的controller,controller將請求的圖片資料進行大小裁剪、類型轉換後儲存到本地指定的檔案夾,同時將路徑返回,用於顯示圖片。

二,實踐

思路比較簡單,所以話不多說,直接上代碼:

前端代碼整合在react寫的一個圖片上傳組件裡,image_uploader.js.jsx代碼如下

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>
    );
  }
});

上面的重點在於upload函數,源碼是最好的文檔,如果看源碼需要太多注釋的話,那肯定是我寫的代碼品質還不夠高,請批評指出。

寫這個的時候遇到兩個問題:

一,這個組件是用在_form.html.slim裡的,這個表單是用於資訊的錄入的,大家對錶單應該比較熟悉,既然要用在表單裡,就是給這個組件作標識,標明name和id,程式碼片段如下(從上面的代碼中截取):
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}/>
二,使用 <input type="file"/> 有一個普遍的問題,內建的UI不美觀。


Google/百度“input file btn”會有許多解決方案,家裡網速差就沒細看。我的做法是把這個btn設為透明,相關的代碼及css如下:

<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;
    }
  }
10
11
12
13
接下來看看後端的代碼:

def upload_image
    # => will 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
代碼同樣簡單,構建檔案路徑,儲存檔案,返迴路徑。因為開發進度的原因這裡並沒有對圖片的大小和類型進行修改(為了減少資料轉送量,在前端進行大小的修改比較合理),後面review這部分代碼的時候會再更新這篇部落格。

值得說說的是:

圖片命名的問題,採用了時間戳記,命名不會重複,為了方便管理,將不同類型的圖片存於不同的檔案夾,但是只以時間戳記命名可擷取的資訊太少,不利於運營人員管理,後期會再仔細考慮這個問題。
存放路徑問題,在後端代碼裡,rails能將圖片存在rails專案檔夾的任何位置,但是用戶端顯示圖片的時候,只能訪問public檔案夾裡的內容,於是決定將圖片存在public檔案夾下。
三,總結及思考

完成這個功能不需要太久,但代碼外的思考不少。圖片小,甚至能用Git備份圖片,也許不是長久之計,開始想念aws的好了,容災交給aws處理最好不過了,後面試了一下AWS S3

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.