Railsにマークダウンとリアルタイムプレビューを実装する

はい、こんばんは。

筆者は現在新婚旅行の真っ最中ですが、特別に勉強時間を与えてもらうことができましたのでアウトプットします。

現在作成中のポートフォリオ兼ブログアプリにマークダウン記法とリアルタイムプレビューを実装しました。

gemの導入

gemfile
gem 'redcarpet', '~> 2.3.0'
gem 'coderay'

bundle install

マークダウン記法の実装

app/heplers/markdown_helper.rb (新規に作成する)
module MarkdownHelper
def markdown(diary) #()内はカラム名を入れる
options = {
filter_html: true,
hard_wrap: true,
space_after_headers: true,
with_toc_data: true
}
extensions = {
autolink: true,
no_intra_emphasis: true,
fenced_code_blocks: true,
tables: true
}
renderer = Redcarpet::Render::HTML.new(options)
markdown = Redcarpet::Markdown.new(renderer, extensions)
markdown.render(diary).html_safe #()内にはカラム名
end
end

上記は最下部に記載する記事より引用させていただきました。
調べて理解してみたいものです。

viewの修正

私の場合、indexとshowアクションにマークダウン記法の記事を表示させたいと思っているので、それを修正する。

before
index.html.erb
<% @blogs.each do |blog| %>
<h2 class="card-header bg-success text-white"><%= "#{blog.title}" %></h2>
<div class="card-body">
<p><%= "#{blog.diary}" %></p> #ここを下記のように修正する。
<%= link_to '記事を読む', blog_path(blog), class: 'btn btn-success text-white' %>
</div>
<% end %>
after
index.html.erb
<% @blogs.each do |blog| %>
<h2 class="card-header bg-success text-white"><%= "#{blog.title}" %></h2>
<div class="card-body">
<p><%= markdown("#{blog.diary}") %></p> #ここを修正した。
<%= link_to '記事を読む', blog_path(blog), class: 'btn btn-success text-white' %>
</div>
<% end %>

before afterで示させていただいた通り、修正したのは#{@blog.diary}をmarkdown(“#{@blog.diary})とした点です。

こうすることで、マークダウン記法を読み取れるようになりました。

show.html.erbでも、同様にマークダウンで表示したいところを書き換える。

リアルタイムプレビューの実装

まず、vue.jsとmarked.jsを読み込むように記述をする。

app/views/layouts/application.html.erb
<-- Vue.js読み込みの記述-->
<script src='https://cdnjs.cloudflare.com/ajax/libs/vue/1.0.10/vue.js'></script>
<--marked.js読み込みの記述-->
<script src='https://cdnjs.cloudflare.com/ajax/libs/marked/0.3.5/marked.js'></script>
view画面の修正

まず最初にソースコードを記述します。

app/views/new.html.erb
<div class='container'>
<h1>新規投稿</h1>
<%= form_with model:@blog, local: true do |f| %>
<div class='form-group'>
<%= f.label :title %>
<%= f.text_field :title, class: 'form-control', id: 'blog_title' %>
</div>
<div class='form-group'>
<div id='editor'>
<%= f.label :diary %>
<%= f.text_area :diary, rows: 5, class: 'form-control', id: 'blog_diary', "v-model" => "input", name: "blog[diary]" %>
<div v-html='input | marked'></div>
</div>
<%= f.submit nil, class: 'btn btn-success' %>
</div>
<% end %>
<!-- リアルタイムプレビュー -->
<script type="text/javascript">
window.onload = function() {
new Vue({
el: '#editor',
data: {
input: '<%== j @blog.diary %>',
},
filters: {
marked: marked,
},
});
};
</script>
</div>

上記のようになるのですが、部分的に解説をします。

<!-- リアルタイムプレビュー -->
<script type="text/javascript">
window.onload = function() {
new Vue({
el: '#editor', #
data: {
input: '<%== j @blog.diary %>', #自分で設定したインスタンス変数とカラム名
},
filters: {
marked: marked,
},
});
};
</script>
</div>

まずjavascriptの部分ですが、最下部の記事を参考に少し変更しました。

次に苦労したのが、form_withのf.text_areaにv-model inputを持たせてやる方法でした。v-というのが、Vue.js独特の記述らしく、Rubyタグの中で使うには

"v-model" => "input"

としてやる必要がありました。-で区切っているため、””なしで記述しても反応がありませんでした。

次にname属性です。

name: "blog[diary]" アプリ名[カラム名]

上記のように指定します。理由はもう少し考えてみます。

最後に、text_areaに記述された部分が表示されるように記述をしてやる必要があります。

<div v-html='input | marked'></div>

v-htmlもvue.jsの表現です。

ここでは、rubyタグではなく、HTMLタグ内の表記なので、このままで問題ありません。

これで文字を入力すると、下記のようになりました。

Gyazo Screen Video

参考にした記事

musicamusik.hatenablog.com

qiita.com

qiita.com

スポンサーリンク

コメント

タイトルとURLをコピーしました