Using TinyMCE with Rails 7 and Uploading Images to an S3 Bucket

November 15, 2022

I'm in the process of building out the Right Rudder Marketing website. Take a look here! I wanted to implement a blog section for the site and create something similar to what I have on this website. This would help with SEO because generating more content gives search engines more data to process. 

My current setup with Trix on the timjedrek website


This meant implementing a WYSIWYG editor into the form to create my own CMS. Since I built out this website using Rails, the go-to option was Trix editor. More specifically ActionText. It works okay and I'm even writing this article on using Trix editor but there are some limitations. Trix editor and ActionText are just really too barebones. It's going to have to require a bunch of customization to really get it to work nicely. 


On the other hand, TinyMCE is very mature in its development and has a lot of support. A ton of plugins and options that work right out of the box. Problem is that because it is so mature, they push you to use their API and implement their software through a cloud platform. This of course costs money. That's the main reason I stayed away from TinyMCE when I made the timjedrek website.


Well, I forgot about it after I abandoned it since I had implemented Trix, but since I am currently building a new CMS for the Right Rudder Marketing website, I figured I'd take a look at the documentation once more and try to figure it out. There's a nice ruby gem that helps get the software loaded into your ruby app.


As of this writing, it looks like it is currently being maintained so I went ahead and installed it and tried it out. It uses their open source SDK and because it's self hosted, there's no additional fees! It was little daunting at first to get it configured but now I got the plugins and toolbars set up to how I like it. This is my current set up:



config/tinymce.yml

promotion: false
toolbar:
  - undo redo | blocks | bold italic underline | forecolor backcolor | 
alignleft aligncenter alignright alignjustify bullist numlist | image link
plugins:
  - table
  - image
  - link
  - lists
  - media
  - autoresize
  - help

It actually looks pretty sweet and the tool is really intuitive. There were some tailwind css issues that I also encountered when I installed ActionText but it is manageable. Basically, since tailwind strips all of the regular CSS away since you're going to typing the CSS through HTML so your input won't be formatted correctly, but since this is a WYSIWYG editor, you can't really add HTML classes to the text you input.

TinyMCE editor

I had fixed the tailwind css issues with the Tim Jedrek website manually, but I came across this stack overflow article and it helped me get the tailwind css issues fixed. Since my tailwind file is in CSS and not SCSS, I distilled it down to this:

@layer base {
  .no-tailwindcss-base h1, .no-tailwindcss-base h2, .no-tailwindcss-base h3, 
.no-tailwindcss-base h4, .no-tailwindcss-base h5, .no-tailwindcss-base h6 {
    font-size: revert;
    font-weight: revert;
 }
  .no-tailwindcss-base ol, .no-tailwindcss-base ul {
    list-style: revert;
    margin: revert;
    padding: revert;
 }
 .no-tailwindcss-base a {
  @apply text-blue-700 underline;
 }
}

And now I have no tailwind conflicts with my WYSIWYG editor!


The only issue I came across was getting images uploaded to a S3 bucket. This is where this article came into play.  Kabošienė's code configures TinyMCE by using POST to uploader/image which comes from TinyMCE and routes it to uploader#image. uploader#image is a controller we make which I'll share down below. This controller stores in the model database a route to the storage location of the image using a blob. Unfortunately, this was in Rails 6 and not Rails 7 so the create_after_upload! function was not working. I was getting 500 errors when I uploaded files, so I had to consult the documentation


My errors: 

Completed 500 Internal Server Error in 55ms (ActiveRecord: 0.0ms Allocations: 9654) 
NoMethodError (undefined method `create_after_upload!' for ActiveStorage::Blob:Class
Did you mean?  create_and_upload!):

Turns out, the function you want to use is create_and_upload! 


So now app/controllers/uploader_controller.rb looks like this:

class UploaderController < ApplicationController
  skip_forgery_protection
  def image
    blob = ActiveStorage::Blob.create_and_upload!(
      io: params[:file],
      filename: params[:file].original_filename,
      content_type: params[:file].content_type
    )
    
     render json: {location: url_for(blob)}, content_type:  "text / html"
  end
end

This is the final solution, but I still got another error..

Completed 500 Internal Server Error in 14ms (ActiveRecord: 6.2ms | Allocations: 6492) 
ActiveRecord::StatementInvalid (PG::UndefinedTable: 
ERROR:  relation "active_storage_blobs" does not exist

Turns out, I forgot to run

rails active_storage:install

Oops. Facepalm. I didn't install active_storage. I had set everything up prior to that but I forgot to add the active_storage extension in my rails package. To connect active_storage to your models, you need to configure storage.yml file in the config folder. 

amazon:
  service: S3
  access_key_id: <%= ENV["s3_access_key_id"] %>
  secret_access_key: <%= ENV["s3_secret_access_key"] %>
  region: us-east-2
  bucket: ##YOURBUCKETNAME##


and then in you config/environments/production.rb or config/environments/development.rb change 

config.active_storage.service = :local

to

config.active_storage.service = :amazon

Have the S3 gem installed by add the gem to your Gemfile

gem 'aws-sdk-s3', require: false


and then run bundle.


Ensure that in your S3 bucket you have properly configured your CORS JSON file to work so that it will accept uploads.

[
  {
        "AllowedHeaders": [
            "*"
        ],
        "AllowedMethods": [
            "PUT"
        ],
        "AllowedOrigins": [
            "http://localhost:3000",
            "https://yourURLgoeshere.com
        ],
        "ExposeHeaders": []
    }
  ]
[

Now I'm able to upload images and get them to an S3 bucket! This new interface is pretty slick. I am considering upgrading the timjedrek website to this.

Using TinyMCE to upload an image

But I encountered a bug. Whenever I went the form, the TinyMCE editor wasn't working. It would just be a naked form. None of the formatting options and toolbar was seen.  However, if I refreshed the page, it showed up. It was a really weird bug.. 


This was due to Turbo and Rails 7. Basically, the input field is not getting refreshed so the JS for TInyMCE doesn't get loaded. This is an easy fix by just putting 

data: { turbo: false }

into the link that takes you to the form. If I had the model Posts and then a button or a link would like this in the .html.erb view.

<%= link_to 'New Post', new_post_path, class: "", data: { turbo: false } %>


If you need help configuring your WYSIWYG editor into you CMS, send me a message here.

Hope this helps anyone trying to get TinyMCE to work with S3 and Rails 7. Happy coding!

-Tim Jedrek