60
57

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

rails4 + bootstrap + summernote(WYSIWYG Editor) とasync画像アップロードで快適なブログ記事編集フォームを実現

Posted at

rails4で記事編集フォームを作ったので、その中でのtipsです。

以下の流れを実現しました。

  1. 記事編集中に画像を選択。
  2. 非同期で画像がサーバー側にアップロードされる。
  3. paperclipでサムネイルが作られてamazon-s3に転送される。
  4. 成功したら280x210サイズのURLを返す。
  5. 記事中に画像が埋め込まれるので、本文の編集を継続する。

bootstrap導入の説明は省きます。
rails側では、aws-sdkとpaperclipを使っています。

Summernote
http://hackerwins.github.io/summernote/

Summernoteについてはサンプルやgithub上で活発なやりとりがされているので、この辺りを見るとほとんどの問題は解決すると思います。

http://hackerwins.github.io/summernote/example.html
https://github.com/HackerWins/summernote/issues

Summernote本体は以下のcssとjsです。

<link href="/stylesheets/summernote.css" rel="stylesheet">
<script src="/javascripts/summernote.js"></script>

画像uploadのダイアログを開くとスクロールバーが消える現象が起こった場合、
masterでは同現象は解決されているので、masterから取得しなおして下さい。

みんな大好きfont-awesomeが必要になります。

 <link rel="stylesheet" href="//netdna.bootstrapcdn.com/font-awesome/4.1.0/css/font-awesome.min.css">

あと日本語対応もしています。以下URLの内容を確認して問題なければそのまま利用するのが良いと思います。

ここまでが導入で、ここからが本題です。

erbのコードはこんな感じです。bodyが記事の本文で、本文中に画像が含まれます。

<%= f.text_field :title %>
<%= f.text_area :body, rows: 15 %>
<%= f.datetime_select :published_datetime, :use_month_numbers => true, :date_separator => '/', minute_step: 30, :include_blank => true, :default => nil %>

javascriptはこんな感じです。routesでresources :blog_imagesしているので、postメソッドを指定するとblog_images#createが呼ばれます。

$(document).ready(function() {

  function sendFile(file, editor,welEditable) {
    data = new FormData();
    data.append("blog_image[image]", file);
    $.ajax({
      url: '/blog_images',
      data: data,
      cache: false,
      contentType: false,
      processData: false,
      type: 'POST',
      success: function(data){
        editor.insertImage(welEditable, data.url);
      }
    });
  }
  
  $('#blog_article_body').summernote({
    height: 300, /*高さを指定*/
    lang: 'ja-JP', /*日本語対応*/
    toolbar: [
      ['style', ['bold', 'italic', 'underline', 'clear']],
      ['fontsize', ['fontsize']],
      ['color', ['color']],
      ['para', ['ul', 'ol', 'paragraph']],
      ['height', ['height']],
      ['insert', ['picture', 'video']],
    ],
    onImageUpload: function(files, editor, welEditable) {
        sendFile(files[0], editor,welEditable);
    }
  });
});

モデルはpaperclipを使ってこんな感じです。


class BlogImage < ActiveRecord::Base

  belongs_to :blog

  has_attached_file :image, Proc.new {
    options = {
      :storage => :s3,
      :s3_credentials => "#{Rails.root.to_s}/config/s3.yml",
      :s3_permissions => "public-read",
      :s3_headers => {'Expires' => 10.year.from_now.httpdate},
      :styles => {
      :"70x52" => ["70x52#", :jpg], # 4:3
      :"280x210" => ["280x210#", :jpg], # 4:3
      },
      #:convert_options => { :thumb => "-quality 85"},
      :default_url => "/images/:style/missing.png",
      :size => { :in => 0..(4.megabytes) }
    }
  }.call

  validates_attachment_content_type :image, :content_type =>/^image\/(.*)/

  def file
    Paperclip.io_adapters.for(image)
  end

  def url(style = "")
    "https://s3-ap-northeast-1.amazonaws.com/webcreation.co.jp.samlet.resources/" + image.path(style)
  end

end

controllerはこんな感じです。成功したらjsonでURLを返します。そのURLがブログ側でそのまま埋め込まれます。

  def create
    @blog_image = BlogImage.new(params.require(:blog_image).permit(:image))
    @blog_image.blog_id = current_user.venue.blog.id
    if @blog_image.save
      render json: {url: @blog_image.url("280x210")}, status: 200
    else
      render nothing: true, status: 500
    end
  end

記事編集中に画像が自然にUPLOADされて、本文に埋め込まれるので快適です。

60
57
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
60
57

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?