質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
Ruby on Rails

Ruby on Railsは、オープンソースのWebアプリケーションフレームワークです。「同じことを繰り返さない」というRailsの基本理念のもと、他のフレームワークより少ないコードで簡単に開発できるよう設計されています。

Markdown

Markdownは、文書の構造、修飾情報を記述するための軽量マークアップ言語です。

Q&A

解決済

1回答

880閲覧

railsでマークダウン表示がうまくできない

lyon

総合スコア5

Ruby on Rails

Ruby on Railsは、オープンソースのWebアプリケーションフレームワークです。「同じことを繰り返さない」というRailsの基本理念のもと、他のフレームワークより少ないコードで簡単に開発できるよう設計されています。

Markdown

Markdownは、文書の構造、修飾情報を記述するための軽量マークアップ言語です。

0グッド

0クリップ

投稿2021/03/16 14:25

編集2021/03/18 12:03

実現したいこと

マークダウン記法で入力されたフォームを表示できるアプリケーションを作成しようとしています。
(イメージはまさにteratailであったり、Qiitaを思い浮かべていただければ良いです。)

# 困っていること
実装するマークダウンに関する機能としては
①入力フォームに投稿したい内容を打ち込むと、同時にマークダウンプレビューが表示される
②投稿したマークダウンは詳細ページで表示される
としたいのですが、①と②の見た目が同じようにならずに困っています。

具体的な状態

①の入力フォームとプレビュー画面はこんな感じです。
一応きちんと表示されています
![イメージ説明

これを保存し、詳細画面に遷移しようとすると、
イメージ説明
とエラーが出てしまいます。

ソースコード

関係のあると思われる箇所を貼っていきます。不足があればご教授ください

ruby

1<%#articles/new.html.erb%> 2<div class="article-new-form"> 3 <%= form_with model: @article, url: articles_path, class: 'registration-main', local: true do |f| %> 4<%# 中略 %> 5 <div class="form-group-max"> 6 <div class="form-text-wrap"> 7 <%= f.label :detail, '本文', class:"form-text" %> 8 <span class="indispensable">必須</span> 9 </div> 10 <div id="detail" class="article-detail"> 11 <%= f.text_area :detail, placeholder: '本文を記入してください。', "v-model" => "text", class: "input-article-detail" %> 12 <div v-html='text | marked' class="review-article"></div> 13 </div> 14 </div> 15 <div class="register-btn"> 16 <%= f.submit "記事投稿", class: 'register-link' %> 17 </div> 18 </div> 19 <% end %> 20</div> 21<%= render "shared/footer"%> 22 23<script type="text/javascript"> 24 window.onload = function() { 25 new Vue({ 26 el: '#detail', 27 data: { 28 text: '<%== j @article.detail %>', 29 }, 30 filters: { 31 marked: marked, 32 }, 33 }); 34 }; 35</script>

ruby

1<%#application_helper.rb%> 2module ApplicationHelper 3 require 'redcarpet' 4 require 'coderay' 5 6 7 class HTMLwithCoderay < Redcarpet::Render::HTML 8 def block_code(code, language) 9 language = language.split(':')[0] 10 11 lang = case language.to_s 12 when 'rb' 13 'ruby' 14 when 'yml' 15 'yaml' 16 when 'css' 17 'css' 18 when 'html' 19 'html' 20 when '' 21 'md' 22 else 23 language 24 end 25 26 CodeRay.scan(code, lang).div 27 end 28 end 29 30 def markdown(text) 31 html_render = HTMLwithCoderay.new(filter_html: true, hard_wrap: true) 32 options = { 33 autolink: true, 34 space_after_headers: true, 35 no_intra_emphasis: true, 36 fenced_code_blocks: true, 37 tables: true, 38 hard_wrap: true, 39 xhtml: true, 40 lax_html_blocks: true, 41 strikethrough: true 42 } 43 markdown = Redcarpet::Markdown.new(html_render, options) 44 markdown.render(text) 45 end 46end 47

ruby

1<%# articles/show.html.erb %> 2<%# 関連する記述のみ抜粋 %> 3 <div class="article-main"> 4 <%= sanitize markdown(@article.detail), tags: %w(h1 h2 h3 h4 h5 strong em a p ul li code pre a), attributes: %w(href) %> 5 </div>

試したこと

エラーの内容からすると、"code```という idは存在しないよ"ということなので、3つのバッククォートで囲んでいるcodeの部分もコードブロックとして読みに行っていることになります。
そのためapplication_helper.rbのblock_codeの部分を消せば、エラーは出なくなるのですが、コードブロックとしてプレビューで表示されているものも表示されなくなってしまう弊害があります。
実際に使う場合にはプレビューと投稿後の表示が異なってしまっては意味がないと思いますので、両者を同じ見た目にする方法をご教授いただければ幸いです。

追記

プレビュー機能を実現するためにvue.jsとmarked.jsのCDNを読み込んでいます

ruby

1<!--application.html.erb--> 2<!DOCTYPE html> 3<html> 4 <head> 5 <title>App</title> 6 <%= csrf_meta_tags %> 7 <%= csp_meta_tag %> 8 9 <%= stylesheet_link_tag 'application', media: 'all' %> 10 <%= javascript_pack_tag 'application' %> 11 <script src='https://cdnjs.cloudflare.com/ajax/libs/vue/1.0.10/vue.js'></script> 12 <script src='https://cdnjs.cloudflare.com/ajax/libs/marked/0.3.5/marked.js'></script> 13 14 <body> 15 <%= yield %> 16 </body> 17</html>

これによりarticles/new.html.erbのVue部分にて、入力フォームに値が入力されるたびにプレビューがマークダウン形式で更新される仕組みになっています。
※marked.jsでマークダウン記法でHTML形式に変換できるようになっています

環境

ruby:2.6.5
rails:6.0.0.3
gemファイル:redcarpet/coderay

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答1

0

ベストアンサー

これ,入力が間違ってますよね?
Markdown で ```code``` がインラインのコードと解釈されるかは Markdown の処理系に依るのかもしれませんが,CommonMark 仕様では見つけられなかったので,100% 間違いと言い切れるかは自信がありませんが,インラインのコードとみなさない処理系があってもおかしくはないと思います。

なので,block_code メソッドで,language の値が正しい形式になっていなかったら何かしらケアしてあげる必要があると思います。

投稿2021/03/17 12:57

scivola

総合スコア2108

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

lyon

2021/03/17 14:15

コメントありがとうございます。 実際入力が間違っている可能性はあるかなと思いつつ、プレビューの方ではインラインコードとして認識していたので、差ができてしまうのが気持ち悪いなというところです。 languageの値の形式が正しいかの判断は正規表現を用いて制約をかけるイメージですか?
scivola

2021/03/18 03:28

(後半について)そうですね,言語指定の値としておかしな形式の文字列だったら握りつぶすとか,何かエラーメッセージみたいなものを挿入するとか。 もちろん正規表現を使うことになるでしょう。
scivola

2021/03/18 11:22

よく理解できてないのですが,プレビューはどうやって実現しているのですか?
lyon

2021/03/18 12:04

ご質問の件に関し、更新してみました。ご確認お願いします。
scivola

2021/03/18 12:19

なるほど,つまり,Markdown テキストの HTML 化を異なる二つの手段で行っているわけですね。 これは避けたほうがいいでしょう。 結果が違って当然というか,私も詳しくはありませんが,合わせるのはかなり大変だと思います。
lyon

2021/03/18 12:44

冷静に考えるとおっしゃる通りですね。。 次善策を考えた方が良さそうですね。(最悪プレビュー機能は諦めます) ありがとうございます。
scivola

2021/03/18 12:52

ものすごいアクセスがある,とかじゃなければ,サーバー側でプレビューもやるとか。 要は Markdown テキストを受け取って HTML を返すアクションを作ればいいんですよね。 markdown ヘルパーは既にありますし,コントローラー側はかなり簡単に書けそう。 ただ,markdown ヘルパーは,呼ばれるたびに Redcarpet::Markdown オブジェクトと HTMLwithCoderay オブジェクトを生成しているのがハイコストな印象です。初回だけ作ればいいのではないでしょうか。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問