はじめに
Ruby on RailsでMediumEditorを導入するまで。
Medium.comのかっこいいエディタをRailsプロジェクトに簡単に導入出来るので、オススメのWysiwygエディタです。
環境
- Ruby 2.4.0
- Rails 5.2.0
1. Railsプロジェクトの作成
Railsプロジェクトの作成からやっていきます。
$ rails new medium-editor
以上でmedium-editor
というプロジェクトを作成します。
2. gem install
使用するgemをインストールします。
Gemfile
を開き以下を入力します。
# medium editor
gem 'medium-editor-rails'
gem 'medium-editor-insert-plugin-rails'
以上を記載したら、bundle install
を行います。
gemをインストールしたら、medium-editorで使用するjsとcssを読み込ませます。
app/assets/javascripts/application.js
に以下を追記
//= require medium-editor
//= require medium-editor-insert-plugin
app/assets/stylesheets/application.css
に以下を追記
*= require medium-editor/medium-editor
*= require medium-editor/themes/beagle
*= require medium-editor-insert-plugin
3. scaffoldで投稿機能の作成
scaffold
でCRUDの投稿機能をささっと作ってしまいます。
$ rails g scaffold Article title:string body:text
$ rails db:migrate
ここまで実行したら、http://localhost:3000/articlesを確認して見ましょう。
4. routes.rbを変更する
http://localhost:3000/articlesでもいいのですが、articlesと入力しなくてもアクセスが出来るようにしておきます。
config/routes.rb
に以下のようにします。
Rails.application.routes.draw do
resources :articles
root 'articles#index'
end
5. フォームにmedium-editorを適用させる
app/views/articles/_form.html.erb
を開く
テキストエリアにeditable
というクラスを付与させておく。
該当ファイルの最終行に以下を追記することで、medium-editorを適用することが出来る。
<script>
var editor = new MediumEditor('.editable', {
// placeholder settings
placeholder: {
text: 'Type your story',
hideOnClick: true
}
});
$('.editable').mediumInsert({
editor: editor
});
</script>
6. 見た目を整える
scaffold
をしただけでは、寂しいので、Siimpleを使って見た目を最低限整えてあげましょう。
layouts/application.html.erb
app/views/layouts/application.rb
を以下のようにします。
今回はCDN経由でSiimpleを使えるようにしておきます。
<!DOCTYPE html>
<html>
<head>
<title>MediumEditor</title>
<%= csrf_meta_tags %>
<%= csp_meta_tag %>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/siimple@3.0.0/dist/siimple.min.css">
<%= stylesheet_link_tag 'application', media: 'all', 'data-turbolinks-track': 'reload' %>
<%= javascript_include_tag 'application', 'data-turbolinks-track': 'reload' %>
</head>
<body>
<%= yield %>
</body>
</html>
articles/index.html.erb
app/views/articles/index.html.erb
<div class="siimple-content">
<p id="notice"><%= notice %></p>
<h1 class="siimple-h2">Articles</h1>
<table class="siimple-box">
<thead>
<tr>
<th>Title</th>
<th>Body</th>
<th colspan="3"></th>
</tr>
</thead>
<tbody>
<% @articles.each do |article| %>
<tr>
<td><%= article.title %></td>
<td><%= link_to 'Show', article, class: 'siimple-link' %></td>
<td><%= link_to 'Edit', edit_article_path(article), class: "siimple-link" %></td>
<td><%= link_to 'Destroy', article, class: 'siimple-link', method: :delete, data: { confirm: 'Are you sure?' } %></td>
</tr>
<% end %>
</tbody>
</table>
<br>
<%= link_to 'New Article', new_article_path, class: 'siimple-link' %>
</div>
articles/show.html.erb
app/views/articles/show.html.erb
<div class="siimple-size siimple-size--large">
<div class="siimple-box">
<p id="notice"><%= notice %></p>
<p class="siimple-box-title">
<strong>Title:</strong>
<%= @article.title %>
</p>
<p class="siimple-box-detail">
<strong>Body:</strong>
<%= @article.body.html_safe %>
</p>
</div>
<%= link_to 'Edit', edit_article_path(@article), class: 'siimple-link' %> |
<%= link_to 'Back', articles_path, class: 'siimple-link' %>
</div>
articles/_form.html.erb
app/views/articles/_form.html.erb
<%= form_with(model: article, local: true, class: 'siimple-form') do |form| %>
<% if article.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(article.errors.count, "error") %> prohibited this article from being saved:</h2>
<ul>
<% article.errors.full_messages.each do |message| %>
<li><%= message %></li>
<% end %>
</ul>
</div>
<% end %>
<div class="siimple-form-field">
<%= form.label :title, class: 'siimple-label' %>
<%= form.text_field :title, id: :article_title, class: 'siimple-input' %>
</div>
<div class="siimple-form-field">
<%= form.label :body, class: 'siimple-label' %>
<%= form.text_area :body, id: :article_body, class: 'editable siimple-textarea siimple-textarea--fluid' %>
</div>
<div class="siimple-form-field">
<%= form.submit class: 'siimple-btn siimple-btn--blue' %>
</div>
<% end %>
articles/new.html.erb
app/views/articles/new.html.erb
<h1 class="siimple-h2">New Article</h1>
<%= render 'form', article: @article %>
<%= link_to 'Back', articles_path, class: 'siimple-link' %>
articles/edit.html.erb
app/views/articles/edit.html.erb
<h1 class="siimple-h2">Editing Article</h1>
<%= render 'form', article: @article %>
<%= link_to 'Show', @article, class: 'siimple-link' %> |
<%= link_to 'Back', articles_path, class: 'siimple-link' %>
7. carrierwaveを使って画像を保存出来るようにする
以上までで、投稿が出来るようになったのですが、文中に挿入した画像を保存出来るようにします。
Gemfile
Gemfile
を開き、以下を追加
gem 'carrierwave'
追加したら、bundle install
uploaderを生成
rails g uploader Image
画像保存用のリソースの作成
rails g scaffold Image file:string
imageモデルの修正
生成されたapp/models/image.rb
を以下のように修正
class Image < ApplicationRecord
mount_uploader :file, ImageUploader
end
routes.rbにpostメソッドを加える
config/routes.rb
を開き、以下を加える
post 'images/upload', to: 'images#upload'
images_controller.rb
app/controllers/images_controller.rb
を以下のように編集する。
scaffoldで生成したアクションは全て消してしまって大丈夫です。
class ImagesController < ApplicationController
def upload
files = params.require(:files)
@image = Image.new
@image.file = files[0]
respond_to do |format|
if @image.save
format.html { redirect_to @image, notice: 'Image was successfully created.' }
format.json do
render json: {
files:
[
{
url: @image.file.metadata['url']+"?id=#{@image.file.model.id}",
thumbnail_url: @image.file.metadata['url']+"?id=#{@image.file.model.id}",
size: 0,
delete_url: "/images/delete",
delete_type: "DELETE"
}
]
}
end
else
format.html { render :new }
format.json { render json: @image.errors, status: :unprocessable_entity }
end
end
end
end
articles/_form.html.erbを修正する
app/views/articles/_form.html.erb
の最終行に追加したscript
タグの中身を変更する。
<script>
$(document).ready(function(){
var editor = new MediumEditor('.editable', {
// placeholder settings
placeholder: {
text: 'Type your story',
hideOnClick: true
}
});
$('.editable').mediumInsert({
editor: editor,
addons: {
images: {
fileUploadOptions: {
url: '/images/upload',
type: 'post',
acceptFileTypes: /(.|\/)(gif|jpe?g|png)$/i
}
}
}
});
});
</script>
8. 完成形のスクリーンショット
上記で一通り使えるまでには出来たかと思います。
そのうち、画像のストレージをCloudinaryに置き換えて画像を保存する方法について書こうと思います。
何かあればコメントください。