この記事を読む前に、必ず以下の記事をお読みください。
GNU Artanis 紹介
GNU Artanis のホームページはこちらです:https://artanis.dev
今すぐ始めましょう。
MVC は、アプリケーションを以下の3つの主要なコンポーネントに分ける古典的なデザインパターンです: Model、View、および Controller。Model はデータの管理を担当し、View はデータを表示し、Controller はユーザー入力を処理して Model と View を適切に更新します。
このチュートリアルでは、GNU Artanis を使用して MVC を活用する方法を紹介します。簡単なブログシステムを作成し、ユーザーがブログ記事を作成、閲覧、更新、削除できるようにします。Model を使用してブログ記事を管理し、View を使ってブログ記事を表示し、Controller を通じてユーザー入力を処理します。
プロジェクトのコードはこちらです: https://gitlab.com/NalaGinrut/mvc-blog-example
OS は Ubuntu 24.04 LTS を想定しています。
図1: MVC のアーキテクチャ
Artanis アプリの作成とデータベースの設定
art create
conf/artanis.conf を修正してデータベース接続を設定します。
db.enable = true
db.type = sqlite3
例を簡略化するため、SQLite3 をデータベースとして使用します。SQLite3 がインストールされていることを確認してください。
sudo apt-get install sqlite3
Model の作成
この簡単なブログシステムでは、ブログ記事を管理するために1つのモデルのみが必要です。以下のコマンドでモデルを作成します。
art draw model article user
# drawing model article
# working Models `article.scm'
art draw model user
# drawing model user
# working Models `user.scm'
2つのモデルを作成しました:
article: app/models/article.scm
user: app/models/user.scm
article.scm を次のように修正します。
(create-artanis-model article
(:deps user)
(id integer (#:primary-key #:auto-increment))
(title char-field (#:not-null #:maxlen 128))
(timestamp bigint (#:unsigned #:not-null))
(content longtext))
Artanis は起動時に、モデル定義に基づいてデータベース内にテーブルを自動作成します。
user.scm を次のように修正します。
(create-artanis-model user
(:deps)
(id integer (#:primary-key #:auto-increment))
(username char-field (#:not-null #:maxlen 128))
(password char-field (#:not-null #:maxlen 512))
(salt char-field (#:not-null #:maxlen 8))
(email char-field (#:not-null #:maxlen 128)))
デフォルトユーザーの追加
アプリケーションを実行する前に、デフォルトユーザーやウェルカム記事を追加する必要があります。以下のコマンドでマイグレーションを作成します。
art draw migration user
# drawing migration user
# working Migration `user_20241207151014.scm'
art draw migration article
# drawing migration article
# working Migration `article_20241207151048.scm'
db/migration/user_*.scm を以下のように修正します。
(define (add-test-user! name password salt)
(let ((mt (map-table-from-DB (get-conn-from-pool!)))
(real-pass (string->sha-256 (string-append password salt))))
(mt 'set 'user
#:username name
#:email (format #f "~a@artanis.dev" name)
#:password real-pass
#:salt salt))
(migrate-up
(display "Adding user `admin'...")
(add-test-user! "Admin" "1234567" "asdf")
(display "done.\n"))
db/migration/article_*.scm も修正します。
(define (add-welcome-article!)
(let ((mt (map-table-from-DB (get-conn-from-pool!))))
(mt 'set 'article
#:title "Welcome to Artanis"
#:timestamp (current-time)
#:content "This is a simple blog system powered by GNU Artanis.")))
(migrate-up
(display "Adding welcome article...")
(add-welcome-article!)
(display "done.\n"))
次に以下のコマンドを実行してマイグレーションを適用します。
art migrate up user
# Loading /home/nalaginrut/Project/mvc-example-blog/conf/artanis.conf...done.
# connection pools are initilizing...DB pool init ok!
# Now the size of connection pool is 64.
# [Migrating user_20241207151014.scm]
# Creating table `user' defined in model
# ......
# Done.
# Adding user `admin'...done.
art migrate up article
# Loading /home/nalaginrut/Project/mvc-example-blog/conf/artanis.conf...done.
# connection pools are initilizing...DB pool init ok!
# Now the size of connection pool is 64.
# [Migrating article_20241207151048.scm]
# Creating table `user' defined in model
# ......
# Done.
# Creating table `article' defined in model
# ......
# Done.
# Adding welcome article...done.
トラブルシューティング
以下のエラーが発生する場合があります。
Throw to key `artanis-err' with args `(500 ... "database is locked")'.
この場合、SQLite3 で Write-Ahead Logging (WAL) モードを有効にします。
sudo apt install sqlite-utils
sqlite-utils enable-wal blog.db
コントローラとビューを作成
インデックス
最初に、デフォルトでインデックスを作成します:
art draw controller index
# drawing controller index
# working Controllers `index.scm'
# create app/controllers/index.scm
# working Views `index'
app/controllers/index.scm
を以下のように変更します:
(import (app models article)
(srfi srfi-1)) ; for fold
(define blog-title "Artanis blog-engine")
(define footer
(tpl->html
`(div (@ (id "footer"))
(p "Artanis blog-engine based on "
(a (@ (href "https://github.com/HardenedLinux/artanis"))
"GNU Artanis")
"."))))
(define (show-all-articles articles)
(fold
(lambda (x prev)
(cons `(div (@ (class "post"))
(h2 ,(result-ref x "title"))
(p (@ (class "post-date"))
,(strftime "%Y-%m-%d"
(localtime
(result-ref x "timestamp" #:decode? #f))))
(p ,(result-ref x "content")))
prev))
'() articles))
(define (article-get-all)
(cond
(($article 'get #:ret 'all #:order-by '(timestamp desc))
=> show-all-articles)
(else '())))
(index-define
""
(lambda (rc)
(let ((all-posts (tpl->html (article-get-all))))
(view-render "index" (the-environment)))))
(get "/" (lambda (rc) (redirect-to rc "/index")))
コントローラの解説
-
(index-define your_url handler)
この関数は、index
コントローラのアクションを定義します。最終的なURLは/index/your_url
になります。この例では URL が空文字列""
なので、最終的なURLは/index
になります。 -
(view-render path (the-environment))
ビューテンプレートをレンダリングするために使用します。第1引数はビューのテンプレート名、第2引数は常に(the-environment)
です。これは GNU Guile ランタイムで使用される環境情報を展開する特別なマクロです。 -
app/views/index/index.html.tpl
ビューパスは自動的にこのパスに配置されます。
便利のため、ルートURLをインデックスコントローラにリダイレクトする設定を追加しています。
データモデルについて
article
モデルをインポートした後、$article
という特別な関数が利用可能になります。これはテーブル article
のリレーショナルマッピングを行います。この関数は、GNU Artanis がモデル定義に基づいて自動生成したもので、命名規則は $model_name
です。
他のフレームワークでよく見られるオブジェクトリレーショナルマッピング (ORM) は、オブジェクト指向プログラミング (OOP) をリレーショナルデータベーステーブルにマッピングします。一方、GNU Artanis は関数型プログラミングのパラダイムを使用してデータベーステーブルを Scheme クロージャにマッピングします。これにより、より柔軟で軽量な実装が可能になります。
ビューテンプレートを作成
次に、ビューのテンプレート app/views/index/index.html.tpl
を作成します:
<html>
<@include header.html.tpl %>
<body>
<div id="container">
<div id="main">
<%= all-posts %>
</div>
<div id="sidebar">
<form method="get" id="dashboard" action="/dashboard/admin">
<div><button>dashboard</button></div>
</form>
<div id="navigation">
<h3>Navigation</h3>
<ul>
</ul>
</div>
</div>
</div>
<%= footer %>
</body>
</html>
このようにして、index コントローラとビューが完成します。何か追加の解説が必要であればお知らせください!
Dashboard
新しい記事を投稿するためにダッシュボードが必要です。正直に言うと、これは非常に簡略化されており、投稿の編集や削除機能はありません。これらは練習問題としてお任せします。
art draw controller dashboard
# drawing controller dashboard
# working Controllers `dashboard.scm'
# create app/controllers/dashboard.scm
# working Views `dashboard
app/controllers/dashboard.scm
を以下の定義で修正します:
(import (app models article))
(define (gen-login-page rc)
(let ((failed (params rc "failed")))
(view-render "login" (the-environment))))
(dashboard-define
"admin"
(options #:with-auth gen-login-page)
(lambda (rc)
(view-render "admin" (the-environment))))
(dashboard-define
"login"
(options #:session #t)
gen-login-page)
(dashboard-define
"new_post"
(method post)
(options #:with-auth gen-login-page
#:from-post #t)
(lambda (rc)
($article 'set #:title (:from-post rc 'get "title")
#:content (:from-post rc 'get "content")
#:timestamp (current-time)
#:user_id 0)
(redirect-to rc "/")))
(dashboard-define
"auth"
(method post)
(options #:auth '(table user "username" "password")
#:session #t)
(lambda (rc)
(cond
((or (:session rc 'check) (:auth rc))
(let ((referer (get-referer rc #:except "/dashboard/login*"))) ;
(if referer
(redirect-to rc referer)
(redirect-to rc "/dashboard/admin"))))
(else (redirect-to rc "/dashboard/login?login_failed=true")))))
解説
-
#:with-auth gen-login-page
ログインページを指定します。ユーザーがログインしていない場合、ログインページにリダイレクトされます。 -
#:session #t
: セッションを有効にします。GNU Artanis は自動的にユーザーのセッションを作成します。 -
#:from-post #t
: リクエストから POST データを取得するために使用されます。
Login view
次に、テンプレート app/views/dashboard/admin.tpl
を作成します:
<html>
<@include header.html.tpl %>
<body>
<p>記事を編集してください</p>
<form id="post_article" action="/dashboard/new_post" method="POST">
<p>タイトル:</p>
<input type="text" name="title"/></br>
<p>内容:</p>
<textarea name="content" rows="25" cols="38">何かを書いてください</textarea></br>
<input type="submit" value="投稿する"/>
</form>
</body>
</html>
HTML header
最後に、デフォルトで使用する共通の pub/header.html.tpl
を作成します:
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title> GNU Artanis blog engine </title>
<@css common.css %>
</head>
Public ディレクトリ
GNU Artanis では、pub ディレクトリは画像、CSS、JavaScript ファイルなどの静的ファイルを保存するために使用されます。
pub ディレクトリ内のファイルはブラウザから直接アクセス可能です。
ダッシュボードへのログイン
ダッシュボードコントローラーを作成した後、新しい記事を投稿するためにダッシュボードにログインする必要があります。
デフォルトのユーザー名は Admin、パスワードは 1234567 です。
アプリケーションの実行
これでブログシステムが完成しました!アプリケーションを実行してみましょう。
art work
その後、ブラウザを開いて以下にアクセスしてください:
http://localhost:3000
フィードバックをお待ちしております
メールは以下にお送りください:artanis@gnu.org
または、GitLab の issue に投稿してください:
https://gitlab.com/hardenedlinux/artanis
以上。