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

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

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

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

![スクリーンショット (172).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/536448/04842c2f-7271-4cb5-1ef9-74aefd90c699.png)



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

## 前提

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

``` Gemfile

 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

```html.erb: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](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/536448/d12e401b-1ac0-6fd3-fc54-14b7b08a98ce.png)

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


[RailsにMarkdown導入してプレビュー表示させるまで](https://qiita.com/shimoch/items/466ed5cc5c232e58b34f)

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