Perron

Published at 2026/03/24

Perron でブログをつくる

1. アプリ作成

rails new <appname> --minimal -T -O -m https://perron.railsdesigner.com/library/new/template.rb

Markdownパーサーを聞かれるので kramdown を入力:

Which markdown parser would you like to use? kramdown

2. ディレクトリ移動

cd <appname>

3. テンプレート導入

rails app:template LOCATION='https://perron.railsdesigner.com/library/personal-blog/template.rb'

4. ビューの不要な記述を削除

app/views/shared/_navigation.html.erb から下記を削除

  <ul class="flex items-center gap-x-4 sm:gap-x-6">
    <%= render partial: "shared/navigation/item", collection: items %>
  </ul>

app/views/content/posts/show.html.erb から下記を削除

<%= link_to "← View all my writings", posts_path, class: "text-sm font-sans font-normal text-gray-500 transition hover:text-gray-800" %>
<section id="comments" class="mt-8 max-w-4xl mx-auto">
  <chirp-form form-id="ADD_YOUR_CHIRP_FORM_ID_HERE" button-text="Add comment" class="grid gap-y-4 p-2">
    <header slot="header">
      <h2 class="text-lg font-bold tracking-tight text-slate-800 md:text-xl">
        Comments
      </h2>

      <p class="mt-0.5 text-base text-slate-600">
        What do you think? Got ideas or suggestions? Let me know below.
      </p>
    </header>
  </chirp-form>

  <p class="mt-2 px-2 text-xs text-slate-500">
    Comments are powered by <a href="https://chirpform.com/?ref=<%= Rails.application.name %>" rel="nofollow">Chirp Form</a></p>
  </p>

  <chirp-feed form-id="ADD_YOUR_CHIRP_FORM_ID_HERE" filter-url="current" class="grid gap-y-4 mt-4 py-4 border-t border-slate-100">
    <template type="style">
      .content + .content {
        padding-block-start: .875rem;
        border-top: 1px solid #f1f5f9;
      }

      .header {
        display: flex;
        justify-content: space-between;
      }

      .name {
        font-size: .875rem;
        font-weight: 500;
        color: #64748b;
      }

      .time {
        font-size: .75rem;
        color: #94a3b8
      }

      .comment {
        margin: 0;
        font-size: 1rem;
        color: #0f172a
      }
    </template>

    <template type="submission">
      <article class="content">
        <header class="header">
          <strong class="name">{{name}}</strong>

          <time class="time">{{created_at}}</time>
        </header>

        <p class="comment">{{comment}}</p>
      </article>
    </template>
  </chirp-feed>
</section>

5. outputフォルダを.gitignoreから削除

# grep して output が表示されるかの確認
cat .gitignore\|grep output
# output が書かれてたら削除して保存
nano .gitignore
# nano で開いてoutput を削除して保存
cat .gitignore\|grep output

6. Timezone修正

app/config/application.rb を修正

config.time_zone = "Tokyo"

7. CSSを整える

7-1. app/assets/tailwind/application.css に追記

@import "tailwindcss";

@theme {
  --font-sans: "Helvetica Neue", "Arial", "Hiragino Kaku Gothic ProN W6", "Hiragino Sans", "BIZ UDPGothic", "Meiryo", "apple-system", "BlinkMacSystemFont", sans-serif;
  --font-serif: "YuMincho", "Hiragino Mincho ProN", serif;
}

/* 既存のスタイル... */

@layer component {
  .content {
    @apply [&_*+h2,&_*+h3]:mt-8;
    @apply [&_*+h4,&_*+h5,&_*+h6]:mt-4;
    @apply [pre]:mt-5;
    @apply [blockquote]:mt-5;

    /* 下記の2行をコメントアウト */    
    /* @apply [&_*:not(h1,h2,h3,h4,h5,h6)+*:not(pre,code,li,blockquote>p,svg),blockquote+pre]:mt-5; */
    /* @apply [&_h1+p,&_h2+p,&_h3+p,&_h4+p,&_h5+p,&_h6+p]:mt-1.5; */

    /* 既存のスタイル... */

    /* コードブロック */
    @apply [&_pre]:bg-gray-100 [&_pre]:relative;
    @apply [&_pre]:pt-8;    /* 言語ラベルの分の余白 */
    
    & *+pre {
      @apply mt-2; /* preの上の要素とのスペース */
    }
    & pre+* {
      @apply mt-7; /* preの下の要素とのスペース */
    }

    /* リスト */
    li {
      color: var(--color-stone-500);
    }
    li a {
      font-weight: var(--font-weight-bold);
      color: var(--color-stone-800);
    }

    /*段落*/
    p {
      @apply text-gray-500;
      @apply text-base;
    }
    @apply [&_ul,&_ol]:space-y-1.5;

    /* 引用ブロック */
    blockquote {
      @apply border-l-4 border-gray-500 my-8 pl-4 md:pl-8 py-4 mx-4 md:mx-10 max-w-md;
    }
    /* 引用本文 */
    blockquote p {
      @apply text-lg font-medium;
    }
    /* 引用元 */
    blockquote p:has(cite) {
      @apply text-right text-gray-600;
    }
  }
}

7-2. フォントを font-sans に変更

app/views/layouts/application.html.erb

<body class="font-sans antialiased">

8. コードブロックの調整

8-1. 複数行表示

kramdown はデフォルトの設定だとコードブロックが1行になる。
GFM(GitHub Flavored Markdown)モードにするとコードブロックの改行が保持される。

config/initializers/perron.rb に以下を追加する。

config.markdown_options = { input: "GFM" }

kramdownでGFMを使うには kramdown-parser-gfm gemが必要
下記を実行してインストール

bundle add kramdown-parser-gfm

8-2. コピーボタン設置

app/javascript/code_blocks.js を作成

document.addEventListener("DOMContentLoaded", () => {
  document.querySelectorAll("pre code[class*='language-']").forEach((code) => {
    const pre = code.parentElement;
    const lang = code.className.replace("language-", "");

    // 言語ラベル
    const label = document.createElement("span");
    label.textContent = lang;
    label.className = "absolute top-0 left-3 text-xs text-gray-400 font-sans";
    label.style.top = "0.25em";
    label.style.marginTop = "0.25em";
    pre.appendChild(label);

    // コピーボタン
    const button = document.createElement("button");
    button.textContent = "Copy";
    button.className = "absolute top-0 right-3 text-xs text-gray-400 font-sans hover:text-gray-700";
    button.style.top = "0.25em";
    button.style.marginTop = "0.25em";
    button.addEventListener("click", () => {
      navigator.clipboard.writeText(code.textContent).then(() => {
        button.textContent = "Copied!";
        setTimeout(() => button.textContent = "Copy", 2000);
      });
    });
    pre.appendChild(button);
  });
});

8-3. importmap の導入

rails new のときに –minimal していると importmap のインストールがスキップされる
JavaScript を使用する場合は、自分で入れる必要がある

8-3-1. importmap の install

bundle add importmap-rails
rails importmap:install

8-3-2. config/importmap.rb にJSファイルを登録

pin "application"
pin "code_blocks"

8-3-3. app/javascript/application.js に記載

import "code_blocks"

9. メタ文字をエスケープする

マークダウンリンクを取得すると「ページタイトル|サイト名」という形式になっていることがある。
マークダウンでは「|」が表のメタ文字なので、これをエスケープする必要がある。

app/helpers/application_helper.rb

def escape_markdown(text)
  text.gsub(/(?<!\\)\|/, '\|')
end

10. index を最新順で表示する

file_path で降順ソートする

app/controllers/content/posts_controller.rb

def index
  @resources = Content::Post.all.order(file_path: :desc)
end

11. root を posts#index に変更

app/config/routes.rb

# root to: "content/pages#root"
root to: "content/posts#index"

12. 起動して確認

bin/dev