It is a memo when creating a Markdown editor that can drag and drop images like the post screen of Qiita in Rails6.
By the way, I learned Rails from GW and created a blog that implements this editor function. (Built with Heroku, GCS) If you are interested, please check out the local spots in the eastern part of Shizuoka prefecture. Surugabu
Mac OS 10.15.4 Ruby 2.6.3p62 Rails 6.0.2.2
It is implemented mainly using three OSS and functions.
SimpleMDE
A great OSS that turns the textarea tag on your browser into a Markdown editor. It is also equipped with various functions such as an automatic save function.
Inline Attachment
It easily implements file transmission with Ajax by dragging and dropping from the browser. In combination with SimpleMDE, dragged and dropped images are sent asynchronously and the uploaded result is reflected in the editor.
Active Storage
File upload functionality built into Rails. You can easily implement the file upload function by using this, and it is an excellent one that also supports uploading to cloud storage such as AWS, Azure, GCP.
#Rails project creation
rails new markdown_drag_and_drop
#Install active storage
rails active_storage:install
rails db:migrate
#Installation of required js module
yarn add simplemde
yarn add inline-attachment
By default, Rails includes turbolinks that force regular websites into partial DOM changes like SPA for speed. However, it is often bad for implementation with js, so I disabled it this time.
app/javascript/packs/application.js
//Invalidation
// require("turbolinks").start()
erb:app/views/layouts/application.html.erb
<!-- 'data-turbolinks-track': 'reload'Delete-->
<%= stylesheet_link_tag 'application', media: 'all' %>
<%= javascript_pack_tag 'application' %>
Create a template with scaffold. The content is a field that saves Markdown as a string.
rails g scaffold article content:text
Place a textarea on the form screen that will be the Markdown editor.
erb:app/views/articles/_from.html.erb
<!--Js used on the screen(Described later) -->
<%= javascript_pack_tag 'article' %>
<%= form_with(model: article, local: true) do |form| %>
<!--Abbreviation-->
<div class="field">
<%= form.label :content %>
<%= form.text_area :content, { id: "editor"} %>
</div>
<div class="actions">
<%= form.submit %>
</div>
<% end %>
Create js to read on the screen.
--Textarea editor --Setting to communicate with ajax when dragged and dropped in the editor
to hold. The process to communicate with ajax will be created later.
app/javascript/packs/article.js
import "inline-attachment/src/inline-attachment";
import "inline-attachment/src/codemirror-4.inline-attachment";
import 'simplemde/dist/simplemde.min.css'
import SimpleMDE from "simplemde";
import Rails from '@rails/ujs'
window.onload = function () {
//Make textarea a Markdown editor
const simplemde = new SimpleMDE({
element: document.getElementById("editor"),
});
//Drag the image into the editor&Processing when dropped
inlineAttachment.editors.codemirror4.attach(simplemde.codemirror, {
uploadUrl: "/articles/attach", //Destination URL to POST
uploadFieldName: "image", //File field name(Key when fetching with params)
allowedTypes: ['image/jpeg', 'image/png', 'image/jpg', 'image/gif'],
extraHeaders: { "X-CSRF-Token": Rails.csrfToken() }, //CSRF measures
});
};
Create a model for sending files with Active Storage.
rails g model attachment
app/models/attachment.rb
class Attachment < ApplicationRecord
has_one_attached :image
end
Add the process for ajax communication to the controller created by scaffold. Save the image and return the URL in JSON. Since filename is a parameter that inlineAttachment receives by default, match it.
app/controllers/articles_controller.rb
class ArticlesController < ApplicationController
...
def attach
attachment = Attachment.create! image: params[:image]
render json: { filename: url_for(attachment.image) }
end
...
end
Add to the routing.
routes.rb
post 'articles/attach', to: 'articles#attach'
If you execute it, drag and drop it into the editor, and Markdown for the image link is output, it is successful.
rails db:migrate
rails s
Instead of returning the uploaded image as it is If you want to use what you want to resize, you can also return the compressed version with variant. Active Storage also does compression, so it's easy.
app/models/attachment.rb
class Attachment < ApplicationRecord
has_one_attached :image
def image_compressed
if image.attached?
image.variant(resize_to_fit: [700, 600]).processed
end
end
end
I showed you how to create a Markdown editor that allows you to drag and drop images in Rails 6. I recently started using Rails, and although I have to remember various implicit rules, it's easy because various processes can be easily implemented.
https://github.com/sparksuite/simplemde-markdown-editor/issues/328
Recommended Posts