Ruby on Rails 예제

주의

서버 보안을 위해 파일 업로드 및 문서 임포트 처리를 구현할 때 아래 가이드를 참고합니다.

소프트웨어 보안 취약점 진단 가이드

아래 예제는 Ruby 2.5.1 및 Rails 5.2.3을 기준으로 작성되었습니다.

carrierwave gem은 파일 업로드를 위한 업로더로 사용됩니다. 설정 방법은 carrierwave 설치 가이드를 참고합니다.

이 예제에서는 /upload를 이미지, video, 파일 업로드를 위한 API로 사용하고, /import를 문서 임포트를 위한 API로 사용합니다.

// synapeditor.config.js
{
  'editor.import.api':       '/import',
  'editor.upload.image.api': '/upload',
  'editor.upload.video.api': '/upload',
  'editor.upload.file.api':  '/upload'
}

1. 파일 업로더 만들기

주의

아래 샘플 코드의 파일 업로드 부분은 의도적으로 최소화되어 있으며, 적절한 보안 처리가 적용되어 있지 않습니다.

파일 업로드는 프로젝트에 이미 구현된 기능을 사용하고, 아래 코드는 에디터 연동 부분만 참고합니다.

rails generate uploader File
# ./app/uploaders/file_uploader.rb
class FileUploader < CarrierWave::Uploader::Base
  storage :file

  def store_dir
    'uploads/'
  end

  def filename
    "#{secure_token}.#{file.extension}" if original_filename.present?
  end

  protected

  def secure_token
    var = :"@#{mounted_as}_secure_token"
    model.instance_variable_get(var) || model.instance_variable_set(var, SecureRandom.uuid)
  end
end

2. 모델 생성

rails generate model UploadFile
# ./app/models/upload_file.rb
class UploadFile < ApplicationRecord
  mount_uploader :file, FileUploader
end

3. 컨트롤러 생성

rails generate controller UploadFile
# ./app/controllers/upload_file_controller.rb
class UploadFileController < ApplicationController
  skip_before_action :verify_authenticity_token   # csrf_token

  def upload
    uploaded = UploadFile.create(file: params[:file])
    render json: { 'uploadPath': uploaded.file.url }
  end

  def import
    root_path = Rails.root
    uploaded  = UploadFile.create(file: params[:file])

    # 1. Document conversion
    input_file_path = uploaded.file.path
    input_file_name = File.basename(input_file_path)
    output_dir_name = File.basename(input_file_name, File.extname(input_file_name))

    converter_path  = "%s/sedocConverter/sedocConverter_exe" % [root_path]
    font_dir_path   = "%s/fonts" % [root_path]
    output_dir_path = "%s/public/output/%s" % [root_path, output_dir_name]
    tmp_dir_path    = "%s/tmp" % [root_path]

    system("%s -pz -f %s %s %s %s" % [converter_path, font_dir_path, input_file_path, output_dir_path, tmp_dir_path])

    # 2. Serialize .pb
    pb_file_path = "%s/document.pb" % [output_dir_path]
    a_file       = File.open(pb_file_path, 'r')
    a_serialized = []
    if a_file
      a_file.sysread(16)
      a_file.each_byte do |byte|
        a_serialized.push(byte & 0xFF)
      end
    end

    # 3. Clean up
    File.delete(input_file_path) if File.exist?(input_file_path)
    File.delete(pb_file_path)    if File.exist?(pb_file_path)

    render json: {
      'importPath':     "/output/%s" % [File.basename(output_dir_path)],
      'serializedData': a_serialized
    }
  end
end

4. 데이터베이스 마이그레이션

# Add a 'file' column on UploadFile
rails generate migration AddFileToUploadFile file:string
rake db:migrate

5. 라우트

# ./config/routes.rb
Rails.application.routes.draw do
  post 'import' => 'upload_file#import'
  post 'upload' => 'upload_file#upload'
end

관련 정보