sk

開発で得たこと

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: %i(create show new)

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


Qiitaマークダウンの導入

Gemfile

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 */
  }
}

以上です!

ProgateやRailsチュートリアル、プログラミングスクールを通い終えたが現場のコードはかけない、

一体どうやって書くの?と思っているエンジニアのみなさんのためのチュートリアルを公開しています。

チュートリアル