読者です 読者をやめる 読者になる 読者になる

5分でRailsアプリにマークダウンとプレビューを実装。

f:id:sksksksksk:20170510221830j:plain

Railsアプリにマークダウン機能を実装します。

今回はQiitaマークダウンというGemを使用します。

アプリの作成

$ rails g model post content:text
$ rails g controller posts
$ rake db:migrate

/app/controller/posts_controller.rb

    def new
        @post = Post.new
    end
    
    def create
          @post = Post.new(post_params)
          @post.save
          redirect_to @post
    end
    
    def show
        @post = Post.find(params[:id])
        @post.save!
    end

    private
    
     def post_params
         params.require(:post).permit(:content)
     end

/app/views/new.html.erb

<%= form_for(@post) do |f| %>
    <%= f.text_area :content %>
    <%= f.submit %>
<% end %>

/app/views/show.html.erb

<%= @post.content %>

/config/routes.rb

  resources :posts, only:[:create, :show, :new]

これで投稿できるようになります。


Qiitaマークダウンの導入

gem 'qiita-markdown'
gem 'github-linguist'
bundle

bundleが失敗する人は2つのプラグインが足りていません
以下を実行してください。

ちなみにCloud9ではエラーは出ません。

$ sudo yum -y install libicu-devel
$ gem install charlock_holmes -v '0.7.3'
$ sudo yum -y install cmake
$ gem install rugged -v '0.25.0b4'

これでマークダウンが使えます。
show.html.erbを以下のように修正してください。

<%= qiita_markdown(@post.content) %>

helperも必要になります。

/application_helper.rb

module ApplicationHelper
  def qiita_markdown(markdown)
    processor = Qiita::Markdown::Processor.new(hostname: "example.com")
    processor.call(markdown)[:output].to_s.html_safe
  end
end

プレビューを作成

書いた記事が横もしくは下でリアルタイムで表示されます。

マークダウン記法では自分の記事がうまく描かれるかチェックしなければならないので必須でしょう。

ここでは、そのプレビューも作成してみましょう。



Vue.jsとmarked.jsを読み込みます。

app/views/application.html.erb

 <script src='https://cdnjs.cloudflare.com/ajax/libs/marked/0.3.5/marked.js'></script>
 <script src='https://cdnjs.cloudflare.com/ajax/libs/vue/1.0.10/vue.js'></script>

formを編集します。
/new.html.erb

<%= form_for(@post) do |f| %>
<div class="form-group">
<div id='editor'>
<textarea name="post[content]" id="n" class="form-control" rows="20" v-model='input' debounce='50'></textarea>
<div class="di_inline_t preview">
<div v-html='input | marked' style: :"width: 650px;"></div>
 </div>
</div>
</div>
<%= f.submit %>
<% end %>


<script type="text/javascript">
 window.onload = function() {
 new Vue({
 el: '#editor',
 data: {
 input: '<%== j @post.content %>',
 },
 filters: {
 marked: marked,
 },
 });
 };
</script>

Bootstrapの導入

bootstrapを導入しないと一部のマークダウンが反映されません。

gem 'bootstrap-sass'

なんでもいいです.scss

@import "bootstrap-sprockets";
@import "bootstrap";

再起動します。
これで使えるようになります。
リロードしないと使えないという人はapplication.jsの//= require turbolinksを決してください。
あるとうまく動かないことがあります。

おしゃれなマークダウン

コードをみやすくする為にscssに以下のコードを追加するといいかもしれません。

//------------------------シンタックスハイライト

.code-frame {

  background-color: #eee;

  .code-lang {
    span {
      padding: .5em;
      color: #fff;
      background-color: #666;
    }
  }

  .highlight {
    .hll { background-color: #ffffcc }
    .c { color: #999988; font-style: italic } /* Comment */
    .err { color: #a61717; background-color: #e3d2d2 } /* Error */
    .k { color: #000000; font-weight: bold } /* Keyword */
    .o { color: #000000; font-weight: bold } /* Operator */
    .cm { color: #999988; font-style: italic } /* Comment.Multiline */
    .cp { color: #999999; font-weight: bold; font-style: italic } /* Comment.Preproc */
    .c1 { color: #999988; font-style: italic } /* Comment.Single */
    .cs { color: #999999; font-weight: bold; font-style: italic } /* Comment.Special */
    .gd { color: #000000; background-color: #ffdddd } /* Generic.Deleted */
    .ge { color: #000000; font-style: italic } /* Generic.Emph */
    .gr { color: #aa0000 } /* Generic.Error */
    .gh { color: #999999 } /* Generic.Heading */
    .gi { color: #000000; background-color: #ddffdd } /* Generic.Inserted */
    .go { color: #888888 } /* Generic.Output */
    .gp { color: #555555 } /* Generic.Prompt */
    .gs { font-weight: bold } /* Generic.Strong */
    .gu { color: #aaaaaa } /* Generic.Subheading */
    .gt { color: #aa0000 } /* Generic.Traceback */
    .kc { color: #000000; font-weight: bold } /* Keyword.Constant */
    .kd { color: #000000; font-weight: bold } /* Keyword.Declaration */
    .kn { color: #000000; font-weight: bold } /* Keyword.Namespace */
    .kp { color: #000000; font-weight: bold } /* Keyword.Pseudo */
    .kr { color: #000000; font-weight: bold } /* Keyword.Reserved */
    .kt { color: #445588; font-weight: bold } /* Keyword.Type */
    .m { color: #009999 } /* Literal.Number */
    .s { color: #d01040 } /* Literal.String */
    .na { color: #008080 } /* Name.Attribute */
    .nb { color: #0086B3 } /* Name.Builtin */
    .nc { color: #445588; font-weight: bold } /* Name.Class */
    .no { color: #008080 } /* Name.Constant */
    .nd { color: #3c5d5d; font-weight: bold } /* Name.Decorator */
    .ni { color: #800080 } /* Name.Entity */
    .ne { color: #990000; font-weight: bold } /* Name.Exception */
    .nf { color: #990000; font-weight: bold } /* Name.Function */
    .nl { color: #990000; font-weight: bold } /* Name.Label */
    .nn { color: #555555 } /* Name.Namespace */
    .nt { color: #000080 } /* Name.Tag */
    .nv { color: #008080 } /* Name.Variable */
    .ow { color: #000000; font-weight: bold } /* Operator.Word */
    .w { color: #bbbbbb } /* Text.Whitespace */
    .mf { color: #009999 } /* Literal.Number.Float */
    .mh { color: #009999 } /* Literal.Number.Hex */
    .mi { color: #009999 } /* Literal.Number.Integer */
    .mo { color: #009999 } /* Literal.Number.Oct */
    .sb { color: #d01040 } /* Literal.String.Backtick */
    .sc { color: #d01040 } /* Literal.String.Char */
    .sd { color: #d01040 } /* Literal.String.Doc */
    .s2 { color: #d01040 } /* Literal.String.Double */
    .se { color: #d01040 } /* Literal.String.Escape */
    .sh { color: #d01040 } /* Literal.String.Heredoc */
    .si { color: #d01040 } /* Literal.String.Interpol */
    .sx { color: #d01040 } /* Literal.String.Other */
    .sr { color: #009926 } /* Literal.String.Regex */
    .s1 { color: #d01040 } /* Literal.String.Single */
    .ss { color: #990073 } /* Literal.String.Symbol */
    .bp { color: #999999 } /* Name.Builtin.Pseudo */
    .vc { color: #008080 } /* Name.Variable.Class */
    .vg { color: #008080 } /* Name.Variable.Global */
    .vi { color: #008080 } /* Name.Variable.Instance */
    .il { color: #009999 } /* Literal.Number.Integer.Long */
  }
}

以上です!



*********************************************************
「作ったアプリを発信しましょう!」

自分が作ったものを他者に発信しましょう。

Ruppishはあなたが作ったものを世に出すお手伝いをします。

Ruppish

*********************************************************