WYSIWYG Editor with Summernote

Episode #27 by David Kimura

Summary

Integrate Summernote WYSIWYG Editor into your application. Learn how to use AJAX callbacks to filestore your images instead of database Base64.
rails wysiwyg view ajax javascript 7:40

Resources

Summary

# Gemfile
gem 'summernote-rails'
gem "refile", require: "refile/rails"
gem "refile-mini_magick"

Generate a new model for your images to be stored. Without Refile (or a similar uploader), the images will be converted to BASE64 and stored within the database.

# bash
rails g model image image_id image_filename image_size:integer image_content_type

# application.js
//= require summernote

# application.css.scss
/*
@import "bootstrap-sprockets";
@import "bootstrap";
*/
@import "summernote";

# _form.html.erb
    <%= f.input :summary, as: :summernote %>
    <%= f.input :content, as: :summernote %>

# articles.coffee
$ ->
  sendFile = (that, file) ->
    data = new FormData
    data.append 'image[image]', file
    $.ajax
      data: data
      type: 'POST'
      url: '/images'
      cache: false
      contentType: false
      processData: false
      success: (data) ->
        img = document.createElement('IMG')
        img.src = data.url
        img.setAttribute('id', data.image_id)
        $(that).summernote 'insertNode', img

  deleteFile = (file_id) ->
    $.ajax
      type: 'DELETE'
      url: "/images/#{file_id}"
      cache: false
      contentType: false
      processData: false

  ready = ->
    $('[data-provider="summernote"]').each ->
      $(this).summernote 
        height: 200
        callbacks: 
          onImageUpload: (files) ->
            img = sendFile(this, files[0])
          onMediaDelete: (target, editor, editable) ->
            image_id = target[0].id
            if !!image_id
              deleteFile image_id
            target.remove()
  $(document).ready(ready)
  $(document).on('page:load', ready)

# images_controller.rb
class ImagesController < ApplicationController
  protect_from_forgery except: :create
 
  def create
    @image = Image.new(image_params)
    @image.save
 
    respond_to do |format|
      format.json { render :json => { url: Refile.attachment_url(@image, :image), image_id: @image.image_id } }
    end
  end
 
  def destroy
    @image = Image.find_by(image_id: params[:id])
    @image.destroy
    respond_to do |format|
      format.json { render :json => { status: :ok } }
    end
  end
  
  private
 
  def image_params
    params.require(:image).permit(:image)
  end
end

# routes.rb
Rails.application.routes.draw do
  resources :articles
  resources :images, only: [:create, :destroy]
  root to: 'articles#index'
end

# image.rb
class Image < ActiveRecord::Base
  attachment :image
  belongs_to :article
end