Quần Cam Blog

Build a blog in Elixir with Nabo and Phoenix

Nabo is a simple, extendable and fast blog engine written in Elixir. She is designed to be integrate-able into any component of your application like Phoenix or Plug.

Installation

To start using Nabo, add nabo to your mix.exs.

def deps do
  [{:nabo, "~> 0.2.0"}]
end

After mix deps.get, you can generate a repo for your posts with nabo.gen.repo task.

Set up your repo

mix nabo.gen.repo MyBlog.PostRepo

Nabo assumes your posts located in priv/posts, but if they are not, feel free to change the path using root option in your repo.

defmodule MyBlog.PostRepo do
  use Nabo.Repo, root: "path/to/posts"
end

Write your first blog post

Nabo comes with nabo.gen.post Mix task with which you can generate post.

mix nabo.gen.post say-hello

Note that Nabo post will be in this format: a JSON front-matter, an post excerpt and a post body.

{
  "title": "Say Hello",
  "slug": "say-hello",
  "datetime": "2017-01-01T00:00:00Z"
}
---
This is the excerpt of the post in markdown.
---
This is the *body* of the post in markdown.

And that’s everything you need to set up Nabo.

Phoenix

Now you’ve got everything up for Nabo, we move on with Phoenix.

In your Phoenix app, let’s create a new controller for posts.

defmodule MyBlogWeb.PostController do
  use MyBlogWeb, :controller

  def index(conn, _params) do
    posts = MyBlog.PostRepo.all()
    render conn, "index.html", posts: posts
  end

  def show(conn, %{"id" => id}) do
    case MyBlog.PostRepo.get(id) do
      {:ok, posts} -> render conn, "show.html", post: post
      {:error, _} -> render conn, "404.html"
    end
  end
end

And of course, don’t forget to add your routes to router.

scope "/", MyBlogWeb do
  pipe_through :browser # Use the default browser stack

  get "/", PageController, :index
  resources "/posts", PostController, only: [:index, :show]
end

And also view and templates.

defmodule MyBlogWeb.PostView do
  use MyBlogWeb, :view
end
# lib/my_blog_web/templates/post/index.eex
<div class="row posts--listing">
  <div class="col-lg-12">
    <%= for post <- @posts do %>
      <div class="post">
        <h1 class="post__title">
          <a href="<%= post_path(@conn, :show, post.slug) %>">
            <%= post.title %>
          </a>
        </h1>
        <div class="post__intro"><%= post.excerpt %></div>
      </div>
    <% end %>
  </div>
</div>
# lib/my_blog_web/templates/post/show.eex
<div class="row posts--single">
  <div class="col-lg-12">
    <div class="post">
      <h1 class="post__title">
        <%= @post.title %>
      </h1>
      <div class="post__content"><%= raw @post.body_html %></div>
    </div>
  </div>
</div>

Now run your application with iex -S mix phx.server and access the website at http://localhost:4000/posts.

For more information, you can check out the documentation or the example app.

Advance usage

As I mentioned, Nabo is designed to be extendable.

By default Nabo uses its own Markdown compiler, Nabo.Compilers.Markdown powered by Earmark. To pass your customized Earmark options you can configure the compiler option in your repo.

defmodule MyBlog.PostRepo do
  use Nabo.Repo,
      root: "priv/posts",
      compiler: {
        Nabo.Compilers.Markdown,
        markdown: %Earmark.Options{code_class_prefix: "lang-"}
      }
end

Or if you’re feeling hardcore and would love to write your own compiler, you are more than welcomed to. (and send a pull request maybe?)

defmodule MyAwesomeCompiler do
  @behaviour Nabo.Compiler

  def compile(content, options) do
    post = AwesomeParser.parse(content)
    compiled = Macro.escape(post)

    # return a two-element tuple of post slug and compiled post
    {post.slug, compiled}
  end
end

Then set it up in your repo.

defmodule MyBlog.PostRepo do
  use Nabo.Repo,
      root: "priv/posts",
      compiler: {MyAwesomeCompiler, the_options_above}
end

That’s it, enjoy Nabo-ing!


NGUY HIỂM! KHU VỰC NHIỀU GIÓ!
Khuyến cáo giữ chặt bàn phím và lướt thật nhanh khi đi qua khu vực này.
Chức năng này hỗ trợ markdown và các thứ liên quan.

Bài viết cùng chủ đề

IO data và Vectored IO

Bài viết giới thiệu về IO data, Vectored I/O và tối ưu hóa hệ thống dùng Elixir bằng cách tận dụng Vectored I/O.

Elixir/Erlang, Actors model và Concurrency

Bài viết này sẽ cho bạn cái nhìn tổng quát về concurrency, mô hình actor và Elixir/Erlang, một thực thể áp dụng mô hình này sẽ giúp bạn xây dựng một concurrent, distributed và fault tolerant như thế nào.

Poolboy và kĩ thuật pooling trong Erlang/Elixir