Загрузка картинок через CKeditor и Ruby on Rails

В этой статье мы рассмотрим, как интегрировать загрузку картинок из редактора CKeditor в приложение на Ruby on Rails

Автор . Дата: 30.10.2014

Чтобы воспользоваться загрузкой картинок через CKeditor нужно указать адрес обработчика в config.js:

    config.filebrowserImageBrowseUrl = '/images';
    config.filebrowserImageUploadUrl = '/images?'+$('meta[name="csrf-param"]').attr('content')+'='+encodeURIComponent($('meta[name="csrf-token"]').attr('content'));

Мы реализуем возможность загружать новые файлы а так же выбирать из списка уже загруженных файлов. Переменная filebrowserImageBrowseUrl содержит адрес страницы для браузера изображений а filebrowserImageUploadUrl адрес страницы, которая будет выполнять загрузку файлов. Теперь перейдем к настройке Rails части. Для начала подключим гем rmagick:

gem 'rmagick', :require => 'RMagick'

Он нужен для того, чтобы выполнять ресайз превьюх для браузера картинок. После чего создадим модель Image:

class Image < ActiveRecord::Base
  belongs_to :user
  
  before_save :upload_image
  attr_accessor :upload

  def get_thumb
    get_image 368, 264
  end
  
  def get_small_thumb
    get_image 240, 190
  end
  
  def get_link
    "/uploads/images/original/#{self.file}"
  end

  def get_image(w, h)
    dir = get_upload_dir "#{w}x#{h}"
    FileUtils.mkdir_p(dir) unless File.directory?(dir)
    path = "#{dir}/#{self.file}"
    unless File.exist?(path)
      img = Magick::Image.read(get_upload_dir('original', self.file)).first
      img.resize_to_fill!(w, h)
      img.write path
    end
    "/uploads/images/#{w}x#{h}/#{self.file}"
  end

  private

    def get_upload_dir *dir
      Rails.root.join('public', 'uploads', 'images', *dir)
    end

    def generate_filename
      file_name = upload.original_filename
      ext_name = File.extname(upload.original_filename).downcase
      rnd = rand(999999)
      time = Time.now.to_i
      "#{user_id}-#{time}-#{file_name}-#{rnd}#{ext_name}"
    end

    def upload_image
      if upload
        dir = get_upload_dir 'original'
        FileUtils.mkdir_p(dir) unless File.directory?(dir)
        
        self.file = generate_filename
        
        path = "#{dir}/#{self.file}"
        
        File.delete(path) if File.exist?(path)
            
        File.open(path, 'wb') do |f|
          f.write(upload.read)
        end
      end
    end
end

и миграцию:

class CreateImages < ActiveRecord::Migration
  def change
    create_table :images do |t|
      t.string, :file, :null => false, :limit => 256
      t.timestamps
    end
  end
end

Создадим контроллер:

class ImagesController < ApplicationController
  def index
    @images = current_user.images
  end

  def create
    @image = current_user.images.build image_create_params
    @image.save
    render :create, :layout => 'clear'
  end

  private
    def image_create_params
      params.permit(:upload)
    end
end

И новый layout под названием clear.html.erb содержащий всего-лишь:

<%= yield %>

Это нужно для того, чтобы выводить ответ скрипта без остального дизайна сайта, ибо при загрузке файла он не нужен и будет лишь зря забивать канал пользователя.

Добавим новый маршрут в routes.rb:

resources :images

и связь в модель User:

has_many :images

Остался последний штрих. Создадим вьюхи create.html.erb и index.html.erb.

create.html.erb:

<script type="text/javascript">window.parent.CKEDITOR.tools.callFunction("<%= params[:CKEditorFuncNum] %>", "<%= @image.get_link %>", "<% if @error %><% error %><% end %>" );</script>

index.html.erb:

<div class="row">
    <div class="col-xs-12 col-md-12">
        <% @images.each do |image| %>
            <img src="<%= image.get_thumb %>" data-src="<%= image.get_link %>" class="thumbnail preview" />
        <% end %>
    </div>
</div>

И добавим в application.js код, который позволит передать по клику на превьюху картинки её адрес в основное окно браузера:

function getUrlParam( paramName ) {
    var reParam = new RegExp( '(?:[\?&]|&)' + paramName + '=([^&]+)', 'i' ) ;
    var match = window.location.search.match(reParam) ;
    return ( match && match.length > 1 ) ? match[ 1 ] : null ;
}

$(document).ready(function() {
    $(".preview").click(function() {
        window.opener.CKEDITOR.tools.callFunction(getUrlParam('CKEditorFuncNum'), $(this).attr('data-src'));
        self.close();
    });
});



 

Вот и все. Не забываем выполнить bundle installrake db:migrate, перезагрузить сервер и радоваться новому функционалу на вашем сайте :-)