2

I don't need a concret solution, but someone that gives me a closer hint to solve my problem. I have an ruby on rails 4 intranet application, that is login protected. In this application I have an editing page, where I also use TinyMCE. It has the ability to give it an URL where to send the picture to for uploading it (see here). I implemented the upload routine with CarrierWave and it works great outside of TinyMCE. If it's possible I would also keep that plugin. But as I said CarrierWave is currently not working with TinyMCE and an asynchronous upload.

So do you have an idea how I can upload an image, but with correct session token (asynchronously). And the picture URL that not saving the database, but in the text shown in TinyMCE. Is there a plugin that can help me or anything else? If you need closer information please tell me.

Best regards Marco

Mainz007
  • 533
  • 5
  • 16

1 Answers1

3

You have to use the image plugin for TinyMCE and set file_picker properties and callbacks, so you can attach files from client-side, rather than URL.

tinymce.init({
    // Include image plugin on plugin list
    plugins: [ 'image'],
    // Include image button on toolbar
    toolbar: ['image'],
    // Enable title field in the Image dialog
    image_title: true, 
    // Enable automatic uploads of images represented by blob or data URIs
    automatic_uploads: true,
    // URL of your upload handler
    // (YOU SHOULD MAKE AN ENDPOINT TO RECEIVE THIS AND RETURN A JSON CONTAINING: {location: remote_image_url})
    images_upload_url: '/text_images',
    // Here we add custom filepicker only to Image dialog
    file_picker_types: 'image', 
    // And here's your custom image picker
    file_picker_callback: function(cb, value, meta) {
      var input = document.createElement('input');
      input.setAttribute('type', 'file');
      input.setAttribute('accept', 'image/*');

      input.onchange = function() {
        var file = this.files[0];

        // Note: Now we need to register the blob in TinyMCEs image blob
        // registry.
        var id = 'blobid' + (new Date()).getTime();
        var blobCache = tinymce.activeEditor.editorUpload.blobCache;
        var blobInfo = blobCache.create(id, file);
        blobCache.add(blobInfo);

        // Call the callback and populate the Title field with the file name
        cb(blobInfo.blobUri(), { title: file.name });
      };

      input.click();
    }
});

Add text_images to your route.rb file:

  match "text_images" => "text_images#create", via: :post

And create your proccessing action like this:

  def create
    if params[:file].class == ActionDispatch::Http::UploadedFile
        @image = Picture.new(image: params[:file])
        respond_to do |format|
          if @image.save
            format.json { render json: { "location": @image.image.url }.to_json, status: :ok }
          else
            format.json { render json: @image.errors, status: :unprocessable_entity }
          end
        end
      end
    end

This is a very crude implementation, you should make it more secure for your application context, validating and filtering large or invalid files!

UPDATE: There was a recent upgrade on the syntax for new versions of TinyMCE for the onchange function to include a result reader attribute on the create method of the blobCache object:

      input.onchange = function() {
      var file = this.files[0];

      var reader = new FileReader();
      reader.readAsDataURL(file);
      reader.onload = function () {
        // Note: Now we need to register the blob in TinyMCEs image blob
        // registry. In the next release this part hopefully won't be
        // necessary, as we are looking to handle it internally.
        var id = 'blobid' + (new Date()).getTime();
        var blobCache =  tinymce.activeEditor.editorUpload.blobCache;
        var blobInfo = blobCache.create(id, file, reader.result);
        blobCache.add(blobInfo);

        // call the callback and populate the Title field with the file name
        cb(blobInfo.blobUri(), { title: file.name });
      };
    };
ErvalhouS
  • 4,178
  • 1
  • 22
  • 38
  • Thank you so far for that detailed answer. I'll try it out and mark your answer as correct, when it's working :) – Mainz007 Feb 08 '17 at 18:46
  • Ok your answer got me further, but didn't solve the problem, that I had a CSRF-warning, when uploading the picture. I had to write my custom images_upload_handler function. This way I could add the csrf_token that RoR generates. Now the application doesn't throw the warning anymore and kills the session. I will write my final solution at the weekend. – Mainz007 Feb 09 '17 at 23:12
  • You should make your life easier, never run into those problems again http://stackoverflow.com/a/24196317/3399504 – ErvalhouS Feb 10 '17 at 07:01
  • Great thanks for that idea! Now I have a slim and easy working solution. – Mainz007 Feb 11 '17 at 10:59
  • This works but if you are using paperclip for `Picture` then you will need to ignore file type validation as well as `skip_before_action :verify_authenticity_token` on the api endpoint for uploading. – Qwertie Dec 12 '17 at 02:59