---

こんにちは〜

【Rails】テキストエリアにドロップした画像をアップロードする

f:id:motty72:20190209143728g:plain

画像をドロップしたら、画像がアップロードされてテキストエリア内にタグが追加されるようにする。

動き

  • 画像をテキストエリアにドラックアンドドロップ(jQueryでイベントハンドル)
  • 画像をサーバーにアップロード(ajax)
  • レスポンスで画像のパスとファイル名を返す(Rails)
  • テキストエリア内のカーソル位置にタグを追加する(js)

実装

必要なgemを追加

  • Gemfileに追加
gem 'redcarpet', '~> 2.3.0'
gem 'carrierwave', '~> 1.0'
gem "jquery-rails"
  • bundle installを実行する
$ docker-compose run --rm web bundle install

#Docker+docker-composeを使わない場合は↓
$ bundle install

scaffoldする

$ rails g articles title:string body:text
$ rails g uploader Image
$ rails g images image:string

carrierwaveの設定

app/models/image.rbに以下を追加

class Image < ApplicationRecord
  mount_uploader :image, ImageUploader #追加
end

jquery読み込み

app/assets/javascripts/application.jsに以下を追加

//= require jquery

view(js周り)

app/assets/javascripts/articles.coffeapp/assets/javascripts/articles.jsにrenameする

$(document).ready(function() {
  $('#article_body').on('drop', function(e) { //dropのイベントをハンドル
    e.preventDefault(); //元の動きを止める処理
    f = e.originalEvent.dataTransfer.files[0]; //ドロップされた画像の1件目を取得
    var formData = new FormData();
    formData.append('image', f); // FormDataに画像を追加

    // ajaxで画像をアップロード
    $.ajax({
      url  : "/images",
      type : "POST",
      data : formData,
      dataType    : "json",
      contentType: false,
      processData: false
    })
    .done(function(data, textStatus, jqXHR){
      setImage(data['name'], data['url'])
    })
    .fail(function(jqXHR, textStatus, errorThrown){
      alert("fail");
    });
  });

  // テキストエリアに画像タグを追加する関数
  function setImage(name, url) {
    var textarea = document.querySelector('textarea');
    var sentence = textarea.value;
    var len      = sentence.length;
    var pos      = textarea.selectionStart;
    var before   = sentence.substr(0, pos);
    var word     = '![' + name + '](' + url + ')';
    var after    = sentence.substr(pos, len);

    sentence = before + word + after;

    textarea.value = sentence;
  }
});

controller

app/controllers/images_controller.rbのcreateアクションを以下に書き換える

  # POST /images
  # POST /images.json
  def create
    @image = Image.new({image: params[:image]})  //パラメーターから画像を取得

    respond_to do |format|
      if @image.save
        format.html { render json: { name: @image.image.identifier, url: @image.image.url } }
        format.json { render json: { name: @image.image.identifier, url: @image.image.url } }
      end
    end
  end

サンプル

雑に作ったサンプル
Docker+docker-composeで作ってある。

github.com

参考