3
3

More than 3 years have passed since last update.

【Rails】markdownで記事を書いてプレビューを表示する

Last updated at Posted at 2021-07-07

ふとした時にブログサイトを作成していたのですが、実際に記事を書いている段階でいまいちデザインのイメージやレイアウトがつかめない…

通常Railsにデフォルトで用意されている入力エリアだとtextしか入力できないので一度投稿しないと勝手がわからず効率が悪いんですよね…

そこでQiita記事のようなプレビュー機能があったらいいなと思ったのでこちらでまとめてみました。

スクリーンショット (172).png

完成形は☝のようにmarkdown形式でtextエリアに入力し、プレビューボタンを押すとその結果が表示されるようになります。

前提

  • model: Article(title: string, content: text)
  • controller: articles_controller

 gem 'redcarpet'

$ bundle install

helpers/markdown_helper.rb

module MarkdownHelper

  def markdown(text)
     unless @markdown
       options = {
      filter_html:     true,
      hard_wrap:       true,
      space_after_headers: true,
    }

    extensions = {
      autolink:           true,
      no_intra_emphasis:  true,
      fenced_code_blocks: true,
    }
       renderer = Redcarpet::Render::HTML.new(options)
       @markdown = Redcarpet::Markdown.new(renderer, extensions)
     end

     @markdown.render(text).html_safe
   end

end

controllerの設定

今回は通常のコントローラーとは別にapiというapiというnamspaceを作成し、こちらにviewからリクエストをjson形式で送り、結果をプレビューエリアに表示します。

apiディレクトリを作成

その配下にarticles_controller.rbを作成(通常のarticle_controllerとは別途)

controllers/api/articles_controller.rb
class Api::ArticlesController < ApplicationController
  def preview
    @html = view_context.markdown(params[:body])
  end
end

routes

リクエストを受け取れるようにルーティングも変更します。

routes.rb

  resources :articles
  ## json形式でのルーティングを作成
  namespace :api, format: 'json' do
    get 'articles/preview'
  end


js

肝心なjsです。

javascripts/preview.js

window.addEventListener('DOMContentLoaded', function(){

 //画面がロードされてからイベントを発生

  $('#preview').on('click', function() {
    var content = $('#mark-down-area').val();

    $.ajax({
      url: '/api/articles/preview',
      dataType: 'json',
   type: 'GET',
      data: { body: content }
    })
    .done(function(html) {

      $('#preview-area').toggleClass("open");
      $('#preview-area').append(html.body);

      $('#markdown').fadeToggle();
      $('#preview').fadeToggle();
    })
    .fail(function() {
      alert('プレビューを表示できませんでした。');
    })
  })


  $('#markdown').on('click', function() {
    $('#preview-area').empty();
    $('#preview-area').toggleClass("open");
    $('#preview').fadeToggle();
    $('#markdown').fadeToggle();
  })
});

json builder

views/api/articles/preview.json.builder
json.body @html

view

articles/new.html.erb

<%= form_for @article, :html => {multipart: true} do |f| %>
<div class = "pd col-6 right preview-area" id = "preview-area">

</div>

  <div class="form-group">
    <div class = "col-md-10">
      <%= f.label "タイトル" %>
      <span style = "color:red">*</span>
      <%= f.text_field :title, required: true, class: "form-control",maxlength: 32  %>
    </div>
    <div class = "col-md-10"><%= f.label "本文"%>
      <%= f.text_area :content, required: true, class: "form-control", id: "mark-down-area"%>
    </div>
  </div>

    <div class = "col-md-10">
      <label >カテゴリー</label>
      <div class="ui field ">
          <%= f.collection_check_boxes :category_ids, Category.all, :id, :name do |cd| %>
          <%= cd.label(){cd.check_box(class: "ui radio checkbox") + cd.text} %>
          <% end %>

        </div>
    </div>
    <div class="row center margin-vertical">
      <div class="col-3">
        <div class="btn btn-success" id = "markdown" style = "display:none">
          戻す
        </div>
      </div>

      <div class="col-3">
        <div class="btn btn-success" id = "preview">
          プレビュー
        </div>
      </div>

    </div>

   <div class = "form-group center">
    <%= f.submit "保存", class: "col-4 btn btn-primary" %>
   </div>

<% end %>


最後にcssでデザインを整えてプレビューボタンのクリック時にプレビューエリアがスライドインされるようにします。

また今回はより使いやすいように表示エリア(.article-display)とプレビューエリア(.preview-area)のデザインを統一してます。

css

# プレビューエリアと実際の表示エリアを同じデザインに統一
.preview-area,.article-display{
  color: rgb(80,80,80);
  font:{
    size:16px;
    weight: normal;
  }

  h2{
    border-left: solid 5px orange;
    padding:20px;
    margin: 50px 0;
    background-color:rgb(250,250,250);
    font-weight: bold;
    font-size: 28px;
  }

  h3{
    border-left: solid 5px skyblue;
    padding-left: 20px;
    margin: 30px 0;
    font-weight: bold;
      font-size: 24px;
  }

  ul{
    padding:10px;
    border: dashed 2px royalblue;
    background-color: rgb(250,250,270);
  }

  p{
    img{
    width: 100%;
  }
}
}

----------------------------

.preview-area{
  transform: translate(1000px);
  position: fixed;
  top: 0;
  bottom:0;
  right: 0;
  z-index: 10;
  border-left:dashed 1px rgb(200,200,200);
  background-color:white;
  overflow-y: auto;
  transition: all .5s;
}

.open{
  transform:translate(0);
}
# openクラスを付与することでプレビューエリアを横からスライドイン

これで投稿画面でプレビューボタンをクリックするとプレビュー画面がスライドインされるようになりました。

スクリーンショット (172).png

参考にさせていただいた記事

RailsにMarkdown導入してプレビュー表示させるまで

大いに参考させていただきました、ありがとうございます。

3
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
3