paranitips

Never stop learning! がモットーのゆるふわエンジニアブログ

ckeditor+carrierwaveで画像をS3にアップロードできるようにする

WYSIWYGといえばckeditor!ということで、ckeditorのインストールから画像のS3アップロードの設定までを書いていきます。

必要なgemをインストール

Gemfileに以下を追加し、bundleでインストールします。

# Gemfile
gem 'carrierwave',github: 'carrierwaveuploader/carrierwave'
gem "fog"
gem 'rmagick'
gem 'mini_magick'

今回は画像のアップローダーとしてcarrierwaveを使います。オススメですしおすし。

carrierwaveの場合、なぜかmini_magickがないとエラーになる鬼仕様なので画像処理にrmagickだけ使う場合もmini_magickが必要です。。

CKeditor + Carrierwave + RMagick Error · Issue #527 · galetahub/ckeditor

# ckeditor/lib/ckeditor/backend/carrierwave.rb
require 'mini_magick' # なんでmini_magick固定やねん!

module Ckeditor
  module Backend
    module CarrierWave
...

carrierwaveの設定を編集する

以下のコマンドを打つと、画像アップロードに必要なファイルの生成やルーティングの設定が行われます。

$ rails generate ckeditor:install --orm=active_record --backend=carrierwave

ちなみに、carrierwaveのほかにpaperclipやrefile、dragonfly(はじめて聞いた)にも対応してます。

carrierwaveをカスタマイズ

carrierwaveで画像をS3にアップロードするためにもろもろ設定が必要です。 この記事を参考にcarrierwave.rbを編集すればOKです。

carrierwaveを使ってS3に画像をアップロードする - 49hack

アップローダーをカスタマイズ

uploaderのストレージをS3用のfogに変更します。

# app/uploaders/ckeditor_picture_uploader.rb
class CkeditorPictureUploader < CarrierWave::Uploader::Base
    include Ckeditor::Backend::CarrierWave

    include CarrierWave::RMagick
    # include CarrierWave::MiniMagick
    # include CarrierWave::ImageScience

    storage :fog # ここ

また、url_contentを変更することで、取得する画像のURLを変更することが可能です。 CDNのURLに変更したりするといいのではないでしょうか〜。

# app/models/ckeditor/picture.rb
class Ckeditor::Picture < Ckeditor::Asset
    mount_uploader :data, CkeditorPictureUploader, :mount_on => :data_file_name

    # 画像アップロード時、または選択時にフォームにペーストされるURL
    def url_content
        ENV['CDN_URL'] +"/hoge/fuga/#{filename}"
    end

end

ckeditorの設定を編集する

config.jsを編集することでckeditorをカスタマイズできます。

ツールバーの表示項目が多ければconfig.toolbar = ...と記述すれば項目を限定することができます。詳しくはこちらをご覧ください。

Toolbar Configuration - CKEditor 4 Documentation

画像アップロードのボタン、タブを有効にするためには、config.filebrowserImageBrowseLinkUrlなどの記述が必要です。

設定は下記記事の内容をそのまま使用しました。CSRFトークンのもろもろの設定をしています。

使用 ckeditor gem - your site

// app/assets/javascripts/ckeditor/config.js
CKEDITOR.editorConfig = function (config) {
    // The location of an external file browser, that should be launched when "Browse Server" button is pressed in the Link tab of Image dialog.
    config.filebrowserImageBrowseLinkUrl = "/ckeditor/pictures";

    // The location of an external file browser, that should be launched when "Browse Server" button is pressed in the Image dialog.
    config.filebrowserImageBrowseUrl = "/ckeditor/pictures";

    // The location of a script that handles file uploads in the Image dialog.
    config.filebrowserImageUploadUrl = "/ckeditor/pictures";
    // Rails CSRF token
    config.filebrowserParams = function(){
        var csrf_token, csrf_param, meta,
        metas = document.getElementsByTagName('meta'),
        params = new Object();

        for ( var i = 0 ; i < metas.length ; i++ ){
            meta = metas[i];

            switch(meta.name) {
                case "csrf-token":
                    csrf_token = meta.content;
                    break;
                case "csrf-param":
                    csrf_param = meta.content;
                    break;
                default:
                    continue;
            }
        }

        if (csrf_param !== undefined && csrf_token !== undefined) {
            params[csrf_param] = csrf_token;
        }

        return params;
    };

    config.addQueryString = function( url, params ){
        var queryString = [];

        if ( !params ) {
            return url;
        } else {
            for ( var i in params )
                queryString.push( i + "=" + encodeURIComponent( params[ i ] ) );
        }

        return url + ( ( url.indexOf( "?" ) != -1 ) ? "&" : "?" ) + queryString.join( "&" );
    };

    // Integrate Rails CSRF token into file upload dialogs (link, image, attachment and flash)
    CKEDITOR.on( 'dialogDefinition', function( ev ){
        // Take the dialog name and its definition from the event data.
        var dialogName = ev.data.name;
        var dialogDefinition = ev.data.definition;
        var content, upload;

        if (CKEDITOR.tools.indexOf(['link', 'image', 'attachment', 'flash'], dialogName) > -1) {
            content = (dialogDefinition.getContents('Upload') || dialogDefinition.getContents('upload'));
            upload = (content == null ? null : content.get('upload'));

            if (upload && upload.filebrowser && upload.filebrowser['params'] === undefined) {
                upload.filebrowser['params'] = config.filebrowserParams();
                upload.action = config.addQueryString(upload.action, upload.filebrowser['params']);
            }
        }
    });
}

I18nの設定も忘れずに

これがないとファイルブラウザでtranslation missingになってデザインが崩れちゃうのでご注意ください。

ja:
  ckeditor:
    page_title: 'CKEditorファイルマネージャー'
    confirm_delete: 'ファイルを削除しますか?'
    buttons:
      cancel: 'キャンセル'
      upload: 'アップロード'
      delete: '削除'
      next: '次へ'

まとめ

ckeditorの設定まわりで結構ハマりましたが(なんせドキュメントが見にくい。。)、これでいい感じにアップローダーも連携できたのでもうやりたい放題です。

やっぱCarrierwave使いやすいな〜。

参考