Bootstrap용 WYSIWYG 웹에디터 Summernote 사용시 서버로 로컬 이미지 업로드후 삽입하기 (1)

Summernote 에디터에서 onImageLoad 콜백 제대로 사용하기

제목이 너무 길다. ㅎㅎㅎ

웹애플리케이션에서 사용자들이 글을 작성할 때 편리하게 사용할 수 있는 웹에디터를 제공하면 서비스의 질을 향상시킬 수 있다. 이 글은 루비온레일스 프렘임워크를 이용하여 웹애플리케이션을 개발할 때, 요즘 Bootstrap 분야에서 급부상하고 있는 WYSIWYG 웹에디터인 Summernote를 사용하는 방법과, 로컬이미지를 글 중에 삽입할 때, Summernote의 기본상태에서 이미지 파일을 Base64로 인코딩하여 DB에 저장하는 방식 외에, 별도로 이미지 파일을 서버로 업로드한 후 해당 링크를 에디터로 삽입하는 방식에 대해서 경험한 내용을 설명한다. 이러한 아이디어는 stackoverflow에서도 찾아 볼 수 있다.

Summernote 공식 홈페이지를 방문하면 AWS S3나 서버에 이미지를 업로드하여 이미지를 에디터에 삽입하는 방법에 대해 설명하고 있지만 실제로 구현하기에는 설명이 부족하다. 위에서 언급한 바와 같이 https://github.com/summernote/summernote/issues/1127를 방문하면 Summernote 깃헙 저장소에 이슈로 동일한 문제가 등록된 것을 알 수 있고, 특히 최근 Summernote 소스 업데이트로 코드 용법이 변경되어 사용시 주의를 요한다. 공식 홈페이지에서도 기본적인 Summernote 에디터를 사용법을 알 수 있지만, 루비온레일스로 개발할 때를 중점적으로 설명하기로 한다. Summernote 에디터 자원을 레일스 assets pipeline으로 쉽게 사용하기 위해서는 summernote-rails 젬을 Gemfile에 추가하여 셋팅하면 된다. 사용법은 깃헙 저장소를 방문하면 잘 설명되어 있다. 그대로 따라하면 문제없이 에디터를 사용할 수 있게 된다. 2015-06-06_07-28-23 로컬이미지를 에디터에 삽입할 경우, summernote에서는 기본으로 이미지 파일을 Base64 dataURL 방식으로 인코딩하여 DB에 저장하도록 한다. 따라서 이미지 크기가 클 경우 해당 글을 저장할 수 없게 되거나 DB에서 많은 용량을 차지하여 서버의 퍼포먼스를 떨어뜨리는 주범이 되기도 한다. summernote에서는 몇가지 콜백 함수를 지원한다. 2015-06-06_07-49-21 app/assets/javascripts/ 디렉토리에 coffeescript 파일을 하나 생성하고 아래와 같이 코드를 작성한다. 여기서는 summernote_upload.coffee 라고 파일명을 정하기로 한다. 이 글에서는 독자들의 이해를 돕기 위해서 최소한의 기능만 구현하도록 코드를 작성했다. 더 세부적인 기능 구현은 독자들의 실력에 따라 멋지게 구현할 수 있을 것이다.

sendFile = (file) ->
  data = new FormData
  data.append 'upload[image]', file
  $.ajax
    data: data
    type: 'POST'
    url: '/uploads'
    cache: false
    contentType: false
    processData: false
    success: (data) ->
      $(".summernote").summernote "insertImage", data.url

$ ->
  $(".summernote").summernote
    lang: 'ko-KR'
    height: 360
    codemirror:
      lineNumbers: true
      tabSize: 2
      theme: "solarized light"
    onImageUpload: (files) ->
      sendFile files[0]

위의 코드가 작동하기 위한 서버 환경을 준비해 보자. 우선, 파일 업로드를 가능하게 하기 위해서 Gemfile에 paperclip 젬을 추가하고 설치한 후 기본 셋팅을 해야 한다. 물론 carrierwave 젬을 사용해도 된다.

gem "paperclip", "~> 4.2"

번들 인스톨 명령을 실행 후(서버에 반영하기 위해서는 반드시 로컬웹서버를 다시 시작해야 함), 아래와 같이 빈 모델을 생성한다. 이름은 upload로 하자.

$ rails g model Upload

paperclip 젬이 설치되면 paperclip이라는 제너레이터를 사용할 수 있게 된다. 따라서 아래와 같이 명령을 실행하여 Upload 모델에 paperclip젬에서 사용하게 될 속성을 생성하기 위해서 마이그레이션 파일을 생성하도록 한다. 이 때 이미지를 업로드할 속성을 지정해야 하는데 여기서는 편의상 image로 정하도록 한다.

$ rails g paperclip Upload image

이제 마이그레이션 명령을 실행하여 실제 데이터베이스 테이블(uploads)를 생성한다. 이제 schema.rb  파일에서 uploads 테이블 코드 부분을 보면 아래와 같게 된다.

create_table "uploads", force: :cascade do |t|
  t.datetime "created_at",                     null: false
  t.datetime "updated_at",                     null: false
  t.string   "image_file_name",    limit: 255
  t.string   "image_content_type", limit: 255
  t.integer  "image_file_size",    limit: 4
  t.datetime "image_updated_at"
end

이제 방금 생성한 Upload 모델 클래스 파일을 열고 아래와 같이 작성한다.

class Upload < ActiveRecord::Base
  has_attached_file :image
  validates_attachment_content_type :image, :content_type => ["image/jpg", "image/jpeg", "image/png", "image/gif"]
end

다음은 Upload 모델에 대한 컨트롤러(uploads_controller.rb)를 아래와 같이 생성한다. 여기서는 우선 create 액션 하나만 생성하도록 한다.

$ rails g controller uploads create

그리고 방금 생성한 컨트롤러 파일을 열고 아래와 같이 작성한다.

class UploadsController < ApplicationController
  protect_from_forgery except: :create

  def create
    @upload = Upload.new(upload_params)
    @upload.save

    respond_to do |format|
      format.json { render :json => { url: @upload.image.url } }
    end
  end

  private

  def upload_params
    params.require(:upload).permit(:image, :image_file_name, :image_content_type, :image_file_size, :image_updated_at)
  end
end

uploads#create 액션이 제대로 라우팅되도록 config/routes.rb 파일을 열어 아래와 같이 추가해 준다.

post 'uploads' => 'uploads#create'

이로써 이 글의 시작 부분에서 작성했던 coffeescript 파일이 작동할 수 있도록 서버측 환경 셋팅이 완료되었다. 이제 실제로 브라우저에서 확인해 보자. summernote 에디터를 열고 로컬 PC에 저장되어 있는 이미지를 마우스로 드래그하여 summernote 에디터로 드롭해 보자. 지금까지 코딩 작업이 제대로 동작한다면 public/system/uploads/images/ 디렉토리에 해당 이미지가 존재하게 되고 summernote 에디터에는 해당 이미지가 삽입되어 보이게 된다. 2015-06-06_10-59-30 2015-06-06_10-58-16 지금까지 설명한 로직은 아마도 wordpress에서 글을 작성해 본 경험이 있는 독자의 경우 일견에 이해할 수 있을 것으로 생각된다. 현재까지 구현한 로직에서는 일단 이미지를 에디터에 삽입하는 동작을 취하게 되면 서버에 이미지가 업로드되어 에디터 상에서 해당 이미지를 삭제하더라도 서버상에는 그대로 존재한다는 것이다. 그래서 다음 글에서는 wordpress와 같이 미디어 라이브러 페이지를 만들어 현재까지 업로드한 모든 이미지를 썸네일로 볼 수 있도록 하고 불필요한 파일은 삭제할 수 있도록 구현해 보기로 하고 여기서 글을 마치도록 한다.

글쓴이: 최효성

외과전문의,웹프로그래밍,컴퓨터 일러스트레이션 / Surgeon, Medical Illustration, Web Programmer

2 thoughts on “Bootstrap용 WYSIWYG 웹에디터 Summernote 사용시 서버로 로컬 이미지 업로드후 삽입하기 (1)”

  1. Hello!
    I implemmented your code, and it works everything but it is just not inserting the image in the editor. Can you help me around?
    Thanks!

답글 남기기

아래 항목을 채우거나 오른쪽 아이콘 중 하나를 클릭하여 로그 인 하세요:

WordPress.com 로고

WordPress.com의 계정을 사용하여 댓글을 남깁니다. 로그아웃 / 변경 )

Twitter 사진

Twitter의 계정을 사용하여 댓글을 남깁니다. 로그아웃 / 변경 )

Facebook 사진

Facebook의 계정을 사용하여 댓글을 남깁니다. 로그아웃 / 변경 )

Google+ photo

Google+의 계정을 사용하여 댓글을 남깁니다. 로그아웃 / 변경 )

%s에 연결하는 중