エラーが発生したとのことですね。リポジトリを確認して、問題を特定しましょう。
まず、リポジトリの構造を見てみます。
github.com
このリポジトリはRust製のWebフレームワーク「Loco.rs」を使用したブログアプリケーションですね。
「Syntax error in textmermaid version 11.4.1」というエラーは、Mermaid図表の構文エラーを示しています。これは、リポジトリのREADMEや他のドキュメントにMermaid形式の図が含まれていて、それが正しく解析できない可能性があります。
対処法をいくつか提案します:
- Mermaid図表を避けてリポジトリを解析
- GitHubのリポジトリページを直接見る
- ファイルを個別に確認する
- READMEのソースコードを見る(レンダリングされていない状態)
- 具体的に知りたい情報を教えてください
- プロジェクトの構造を知りたいですか?
- 特定のファイルの内容を見たいですか?
- 技術スタックを理解したいですか?
- 私が代わりに解析します
- どのような情報が必要か教えていただければ、私がリポジトリから必要な情報を取得します
どのような情報をお探しですか?例えば:
- プロジェクトの技術構成
- ファイル構造
- 使用しているライブラリ
- 特定のコード部分
お手伝いできることを教えてください!
ブログ記事を確認して、両者のアーキテクチャを比較しますね。
blogspot.com
ブログ記事の内容を確認しました。では、blog.rsとブログ記事のアーキテクチャを比較してみましょう。
blog.rs (Loco.rs + Rust) の優れている点
1. 技術スタックの統一性
blog.rsはLoco.rsフレームワークを使用しており、Rustで統一された構成 blogspotです。一方、ブログ記事のアーキテクチャはJavaScript/TypeScript(Express + Webpack)を使用しており、フロントエンドとバックエンドで技術が分散しています。
優位性:
- 型安全性がバックエンド全体で保証される
- メモリ安全性が言語レベルで担保される
- 単一言語での開発により学習コストが低減
2. パフォーマンス
Rustベースのため、以下の点で優れています:
- ゼロコストの抽象化
- コンパイル時の最適化
- Node.jsと比較して低メモリフットプリント
- 並行処理が安全かつ効率的
3. セキュリティ
ブログ記事ではミドルウェアをルーティング直後に配置すべきと指摘 blogspotしていますが、Loco.rsでは:
- コンパイル時の型チェックでセキュリティホールを防止
- メモリ安全性が言語レベルで保証
- 所有権システムにより、データ競合が発生しない
4. マイグレーション管理
blog.rsは構造化されたマイグレーションシステムを持ち:
- バージョン管理が明確
- ロールバックが容易
- 環境ごとの設定が分離されている
ブログ記事ではマイグレーションがデータベースと直接接続されているが、環境管理が不明と指摘 blogspotされています。
5. 設定管理
blog.rsは環境別の設定ファイルを明確に分離:
config/development.yamlconfig/production.yamlconfig/test.yaml
これにより、環境ごとの設定ミスを防止できます。
ブログ記事のアーキテクチャの問題点(blog.rsでは解決済み)
ブログ記事では以下の問題点が指摘されています blogspot:
- レイヤー間の依存関係が不明瞭 → Loco.rsは明確なMVCパターンを採用
- セキュリティ上の懸念 → Rustの型システムとLocoのミドルウェアで解決
- スケーラビリティの問題 → Rustの並行処理とLocoのワーカーシステムで対応
- キャッシュ層が見当たらない → Loco.rsはRedis統合をサポート
まとめ
blog.rs (Loco.rs) は以下の点でブログ記事のアーキテクチャより優れています:
- 型安全性とメモリ安全性: コンパイル時にバグを検出
- パフォーマンス: Rustの効率的な実行
- 明確なアーキテクチャ: MVCパターンと環境別設定の分離
- 保守性: 単一言語での開発と明確な責務分離
- セキュリティ: 言語レベルでの安全性保証
ただし、ブログ記事が提案する改善案(レイヤードアーキテクチャの徹底、テスト戦略の明確化、可観測性の追加)は、blog.rsにも適用できる重要な指摘です。
より詳しい比較や、blog.rsに足りない部分についても知りたいですか?
リポジトリの詳細な構成を確認して、追加で必要なファイルを特定しましょう。
10件の結果
リポジトリの構成を調べましたが、具体的なファイル構成が見つからなかったので、Loco.rsの標準的な構成を基に必要なファイルをまとめます。
blog.rs を動かすために必要なもの
1. 必須インフラ
PostgreSQLとRedisのローカルインスタンスが必要 githubです。
# PostgreSQL を起動
docker run -d -p 5432:5432 \
-e POSTGRES_USER=loco \
-e POSTGRES_DB=loco_app \
-e POSTGRES_PASSWORD="loco" \
postgres:15.3-alpine
# Redis を起動
docker run -d -p 6379:6379 redis:alpine
2. 追加で必要な設定ファイル
リポジトリには含まれていない可能性が高いファイル:
.env ファイル(環境変数)
プロジェクトルートに作成:
# .env
DATABASE_URL=postgres://loco:loco@localhost:5432/loco_app
REDIS_URL=redis://localhost:6379
JWT_SECRET=your_secret_key_change_this_in_production
config/development.yaml の確認
開発環境の設定ファイルを確認する必要があります githubが、リポジトリに含まれていない場合は以下を参考に作成:
# config/development.yaml
server:
port: 5150
host: 0.0.0.0
database:
uri: postgres://loco:loco@localhost:5432/loco_app
enable_logging: true
auto_migrate: true
redis:
uri: redis://localhost:6379
auth:
jwt:
secret: "development-secret-change-in-production"
expiration: 3600
3. Rust のインストール
# Rust がインストールされていない場合
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
# 最新版に更新
rustup update
4. Loco CLI のインストール
cargo install loco-cli
5. セットアップ手順
# 1. リポジトリをクローン
git clone https://github.com/mateusfg7/blog.rs.git
cd blog.rs
# 2. 依存関係をインストール
cargo build
# 3. データベースマイグレーション実行
cargo loco db migrate
# 4. アプリケーション起動
cargo loco start
6. 確認すべきファイル
リポジトリをダウンロード後、以下のファイルが存在するか確認してください:
Cargo.toml- Rust の依存関係定義config/development.yaml- 開発環境設定migration/- データベースマイグレーションファイルsrc/- ソースコードsrc/app.rssrc/controllers/src/models/
7. 不足している可能性があるファイル
以下のファイルが含まれていない場合は手動で作成が必要:
.env- 環境変数(通常は.gitignoreで除外される)config/production.yaml- 本番環境設定(オプション).dockerignore- Docker 使用時(オプション)
トラブルシューティング
もし起動時にエラーが出たら:
- データベース接続エラー: PostgreSQL と Redis が起動しているか確認
- マイグレーションエラー:
cargo loco db resetでデータベースをリセット - ポート競合:
config/development.yamlでポート番号を変更
リポジトリをダウンロードした後、具体的にどのファイルが不足しているか確認できたら、より詳しいサポートができます!
結論から言うと Fedora では docker-cli と podman-docker を同時に入れることはできません(衝突します)。
代わりに Podman だけで Docker と同じコマンドを使えるようにすればOK です。
✅ 一番安全で推奨の解決方法(Docker不要・Podmanのみ)
Fedora は標準で Podman を推奨しています。
Docker コマンドをそのまま使いたいなら、以下だけをインストールします:
podman-docker は docker コマンドを podman にエイリアス するパッケージです。
なので以下のように使えます:
→ 内部では podman run ... が実行されます。
❗あなたが今やろうとしていたこと
これは 衝突する2つを同時インストールしようとして失敗した 状態です。
docker-cli は Docker 本体のコマンドセットpodman-docker は docker という名前の Podman 互換 layer
だから同時には絶対に入りません。
✅ 解決手順(正しい方向)
① まず podman-docker のみ入れる
これで docker コマンドが使えるようになります。
⭐ PostgreSQL コンテナを動かしたいなら(Podman でOK)
Docker と同じコマンドで動きます:
※Podman は postgres:15.3-alpine を自動で docker.io から pull します。
🔍 “どうしても本物の Docker を入れたい” 場合
Fedora では公式 docker パッケージは非推奨になっていて、
「Docker Engine を使いたいなら Docker の公式 RPM を使う必要」があります。
Fedora 43 用 Docker CE repo を追加する必要があります。
もし本物の Docker を入れたいなら、必要なら手順を説明します。
📌 結論まとめ
| 目的 | 解決策 |
|---|---|
| Docker と同じようにコンテナ動かしたい | podman-docker を入れるだけでOK |
| docker-cli と podman-docker は両立可? | ❌ 絶対不可(衝突) |
| 本物の Docker を使いたい | Docker CE の公式 repo を追加すべき |
必要なら:
-
Docker CE の正しいインストール方法(Fedora 43 用)
-
Podman で Postgres 永続化する方法(volume)
-
Loco(Rust)の DB 接続設定
なども続けて説明します。
次どうしますか?
ChatGPT:
# blog.rs 拡張: コントローラ、ルート、テンプレート追加
## 1. Cargo.toml に依存関係追加
```toml
[dependencies]
loco-rs = { version = "0.5" }
axum = "0.7"
tokio = { version = "1", features = ["full"] }
serde = { version = "1", features = ["derive"] }
serde_json = "1"
sqlx = { version = "0.7", features = ["runtime-tokio-rustls", "postgres", "macros", "chrono"] }
sea-orm = { version = "0.12", features = ["sqlx-postgres", "runtime-tokio-rustls", "macros"] }
chrono = { version = "0.4", features = ["serde"] }
askama = "0.12"
askama_axum = "0.4"
[dependencies.uuid]
version = "1.0"
features = ["serde", "v4"]
```
## 2. Post モデルの作成
```rust
// src/models/posts.rs
use chrono::NaiveDateTime;
use sea_orm::entity::prelude::*;
use serde::{Deserialize, Serialize};
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Serialize, Deserialize)]
#[sea_orm(table_name = "posts")]
pub struct Model {
#[sea_orm(primary_key)]
pub id: i32,
pub title: String,
pub content: String,
pub slug: String,
pub author_id: i32,
pub published: bool,
pub created_at: NaiveDateTime,
pub updated_at: NaiveDateTime,
}
#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
pub enum Relation {
#[sea_orm(
belongs_to = "super::users::Entity",
from = "Column::AuthorId",
to = "super::users::Column::Id"
)]
User,
}
impl Related for Entity {
fn to() -> RelationDef {
Relation::User.def()
}
}
impl ActiveModelBehavior for ActiveModel {}
```
## 3. マイグレーションファイル
```rust
// migration/src/m20240101_000001_create_posts.rs
use sea_orm_migration::prelude::*;
#[derive(DeriveMigrationName)]
pub struct Migration;
#[async_trait::async_trait]
impl MigrationTrait for Migration {
async fn up(&self, manager: &SchemaManager) -> Result<(), DbErr> {
manager
.create_table(
Table::create()
.table(Posts::Table)
.if_not_exists()
.col(
ColumnDef::new(Posts::Id)
.integer()
.not_null()
.auto_increment()
.primary_key(),
)
.col(ColumnDef::new(Posts::Title).string().not_null())
.col(ColumnDef::new(Posts::Content).text().not_null())
.col(ColumnDef::new(Posts::Slug).string().not_null().unique_key())
.col(ColumnDef::new(Posts::AuthorId).integer().not_null())
.col(ColumnDef::new(Posts::Published).boolean().not_null().default(false))
.col(ColumnDef::new(Posts::CreatedAt).timestamp().not_null())
.col(ColumnDef::new(Posts::UpdatedAt).timestamp().not_null())
.foreign_key(
ForeignKey::create()
.name("fk_posts_author")
.from(Posts::Table, Posts::AuthorId)
.to(Users::Table, Users::Id)
.on_delete(ForeignKeyAction::Cascade),
)
.to_owned(),
)
.await?;
manager
.create_index(
Index::create()
.name("idx_posts_slug")
.table(Posts::Table)
.col(Posts::Slug)
.to_owned(),
)
.await
}
async fn down(&self, manager: &SchemaManager) -> Result<(), DbErr> {
manager
.drop_table(Table::drop().table(Posts::Table).to_owned())
.await
}
}
#[derive(Iden)]
enum Posts {
Table,
Id,
Title,
Content,
Slug,
AuthorId,
Published,
CreatedAt,
UpdatedAt,
}
#[derive(Iden)]
enum Users {
Table,
Id,
}
```
## 4. Askama テンプレート
```html
1. 記事一覧ページ(index.html)
<!-- templates/posts/index.html -->
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>ブログ記事一覧</title>
<style>
body {
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
max-width: 800px;
margin: 0 auto;
padding: 20px;
background-color: #f5f5f5;
}
h1 {
color: #333;
border-bottom: 3px solid #007bff;
padding-bottom: 10px;
}
.post {
background: white;
padding: 20px;
margin: 20px 0;
border-radius: 8px;
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
}
.post h2 {
margin-top: 0;
color: #007bff;
}
.post-meta {
color: #666;
font-size: 0.9em;
margin: 10px 0;
}
.post-content {
line-height: 1.6;
color: #444;
}
.read-more {
display: inline-block;
margin-top: 10px;
color: #007bff;
text-decoration: none;
font-weight: bold;
}
.read-more:hover {
text-decoration: underline;
}
.create-btn {
display: inline-block;
padding: 10px 20px;
background-color: #28a745;
color: white;
text-decoration: none;
border-radius: 5px;
margin-bottom: 20px;
}
.create-btn:hover {
background-color: #218838;
}
</style>
</head>
<body>
<h1>📝 ブログ記事一覧</h1>
<a href="/posts/new" class="create-btn">+ 新規作成</a>
<!-- 記事がない場合 -->
<p>まだ記事がありません。</p>
<!-- 記事リスト -->
<div class="post">
<h2><a href="/posts/sample-post">サンプル記事タイトル</a></h2>
<div class="post-meta">
投稿日: 2025-01-15
<span style="color: green;">● 公開中</span>
</div>
<div class="post-content">
記事の内容がここに表示されます...
</div>
<a href="/posts/sample-post" class="read-more">続きを読む →</a>
</div>
</body>
</html>
2. 記事詳細ページ(show.html)
<!-- templates/posts/show.html -->
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>記事タイトル</title>
<style>
body {
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
max-width: 800px;
margin: 0 auto;
padding: 20px;
background-color: #f5f5f5;
}
.article {
background: white;
padding: 40px;
border-radius: 8px;
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
}
h1 {
color: #333;
margin-bottom: 10px;
}
.meta {
color: #666;
font-size: 0.9em;
margin-bottom: 30px;
padding-bottom: 20px;
border-bottom: 1px solid #eee;
}
.content {
line-height: 1.8;
color: #444;
font-size: 1.1em;
}
.back-link {
display: inline-block;
margin-top: 30px;
color: #007bff;
text-decoration: none;
}
.back-link:hover {
text-decoration: underline;
}
.action-buttons {
margin-top: 20px;
}
.btn {
display: inline-block;
padding: 8px 16px;
margin-right: 10px;
text-decoration: none;
border-radius: 4px;
}
.btn-edit {
background-color: #ffc107;
color: #333;
}
.btn-delete {
background-color: #dc3545;
color: white;
}
</style>
</head>
<body>
<div class="article">
<h1>記事のタイトルがここに表示されます</h1>
<div class="meta">
投稿日: 2025-01-15 | 更新日: 2025-01-15
</div>
<div class="content">
<p>記事の本文がここに表示されます。</p>
<p>複数の段落で構成される長い文章も問題なく表示できます。</p>
</div>
<div class="action-buttons">
<a href="/posts/sample-post/edit" class="btn btn-edit">編集</a>
<a href="/posts/sample-post/delete" class="btn btn-delete"
onclick="return confirm('本当に削除しますか?')">削除</a>
</div>
<a href="/posts" class="back-link">← 記事一覧に戻る</a>
</div>
</body>
</html>
3. 記事作成・編集フォーム(form.html)
<!-- templates/posts/form.html -->
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>記事作成・編集</title>
<style>
body {
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
max-width: 800px;
margin: 0 auto;
padding: 20px;
background-color: #f5f5f5;
}
.form-container {
background: white;
padding: 40px;
border-radius: 8px;
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
}
h1 {
color: #333;
margin-bottom: 30px;
}
.form-group {
margin-bottom: 20px;
}
label {
display: block;
margin-bottom: 5px;
color: #333;
font-weight: bold;
}
input[type="text"],
textarea {
width: 100%;
padding: 10px;
border: 1px solid #ddd;
border-radius: 4px;
font-size: 1em;
box-sizing: border-box;
}
textarea {
min-height: 300px;
font-family: inherit;
}
.checkbox-group {
margin: 20px 0;
}
.checkbox-group input {
margin-right: 8px;
}
.button-group {
margin-top: 30px;
}
button {
padding: 12px 24px;
margin-right: 10px;
border: none;
border-radius: 4px;
font-size: 1em;
cursor: pointer;
}
.btn-submit {
background-color: #007bff;
color: white;
}
.btn-submit:hover {
background-color: #0056b3;
}
.btn-cancel {
background-color: #6c757d;
color: white;
}
.btn-cancel:hover {
background-color: #545b62;
}
</style>
</head>
<body>
<div class="form-container">
<h1>新規記事作成</h1>
<form method="POST" action="/posts">
<div class="form-group">
<label for="title">タイトル</label>
<input type="text" id="title" name="title" required>
</div>
<div class="form-group">
<label for="slug">スラッグ(URL用)</label>
<input type="text" id="slug" name="slug" required>
</div>
<div class="form-group">
<label for="content">本文</label>
<textarea id="content" name="content" required></textarea>
</div>
<div class="checkbox-group">
<label>
<input type="checkbox" name="published">
公開する
</label>
</div>
<div class="button-group">
<button type="submit" class="btn-submit">作成</button>
<a href="/posts">
<button type="button" class="btn-cancel">キャンセル</button>
</a>
</div>
</form>
</div>
</body>
</html>
## 5. テンプレート構造体
## 5. テンプレート構造体
```rust
// src/views/posts.rs
use askama::Template;
use crate::models::posts::Model as Post;
#[derive(Template)]
#[template(path = "posts/index.html")]
pub struct IndexTemplate {
pub posts: Vec,
}
#[derive(Template)]
#[template(path = "posts/show.html")]
pub struct ShowTemplate {
pub post: Post,
}
#[derive(Template)]
#[template(path = "posts/form.html")]
pub struct FormTemplate {
pub post: Option,
}
```
## 6. コントローラの作成
```rust
// src/controllers/posts.rs
use axum::{
extract::{Path, State},
response::{Html, IntoResponse, Redirect},
Form,
};
use loco_rs::prelude::*;
use sea_orm::{ActiveModelTrait, EntityTrait, Set, ActiveValue};
use serde::Deserialize;
use crate::{
models::posts::{self, Entity as Posts},
views::posts::{IndexTemplate, ShowTemplate, FormTemplate},
};
#[derive(Debug, Deserialize)]
pub struct CreatePostForm {
pub title: String,
pub slug: String,
pub content: String,
pub published: Option,
}
/// 記事一覧表示
pub async fn index(State(ctx): State) -> Result<Html> {
let posts = Posts::find()
.all(&ctx.db)
.await
.map_err(|e| Error::InternalServerError)?;
let template = IndexTemplate { posts };
Ok(Html(template.render().map_err(|_| Error::InternalServerError)?))
}
/// 記事詳細表示
pub async fn show(
State(ctx): State,
Path(slug): Path,
) -> Result<Html> {
let post = Posts::find()
.filter(posts::Column::Slug.eq(slug))
.one(&ctx.db)
.await
.map_err(|_| Error::InternalServerError)?
.ok_or(Error::NotFound)?;
let template = ShowTemplate { post };
Ok(Html(template.render().map_err(|_| Error::InternalServerError)?))
}
/// 新規作成フォーム表示
pub async fn new() -> Result<Html> {
let template = FormTemplate { post: None };
Ok(Html(template.render().map_err(|_| Error::InternalServerError)?))
}
/// 記事作成処理
pub async fn create(
State(ctx): State,
Form(form): Form,
) -> Result {
let post = posts::ActiveModel {
title: Set(form.title),
slug: Set(form.slug.clone()),
content: Set(form.content),
author_id: Set(1), // TODO: 認証ユーザーIDを使用
published: Set(form.published.is_some()),
created_at: Set(chrono::Utc::now().naive_utc()),
updated_at: Set(chrono::Utc::now().naive_utc()),
..Default::default()
};
post.insert(&ctx.db)
.await
.map_err(|_| Error::InternalServerError)?;
Ok(Redirect::to(&format!("/posts/{}", form.slug)))
}
/// 編集フォーム表示
pub async fn edit(
State(ctx): State,
Path(slug): Path,
) -> Result<Html> {
let post = Posts::find()
.filter(posts::Column::Slug.eq(slug))
.one(&ctx.db)
.await
.map_err(|_| Error::InternalServerError)?
.ok_or(Error::NotFound)?;
let template = FormTemplate { post: Some(post) };
Ok(Html(template.render().map_err(|_| Error::InternalServerError)?))
}
/// 記事更新処理
pub async fn update(
State(ctx): State,
Path(slug): Path,
Form(form): Form,
) -> Result {
let post = Posts::find()
.filter(posts::Column::Slug.eq(&slug))
.one(&ctx.db)
.await
.map_err(|_| Error::InternalServerError)?
.ok_or(Error::NotFound)?;
let mut post: posts::ActiveModel = post.into();
post.title = Set(form.title);
post.slug = Set(form.slug.clone());
post.content = Set(form.content);
post.published = Set(form.published.is_some());
post.updated_at = Set(chrono::Utc::now().naive_utc());
post.update(&ctx.db)
.await
.map_err(|_| Error::InternalServerError)?;
Ok(Redirect::to(&format!("/posts/{}", form.slug)))
}
/// 記事削除処理
pub async fn delete(
State(ctx): State,
Path(slug): Path,
) -> Result {
let post = Posts::find()
.filter(posts::Column::Slug.eq(slug))
.one(&ctx.db)
.await
.map_err(|_| Error::InternalServerError)?
.ok_or(Error::NotFound)?;
post.delete(&ctx.db)
.await
.map_err(|_| Error::InternalServerError)?;
Ok(Redirect::to("/posts"))
}
```
## 7. ルーティング設定
```rust
// src/controllers/mod.rs
pub mod posts;
use axum::Router;
use loco_rs::prelude::*;
pub fn routes(ctx: &AppContext) -> Router {
Router::new()
.route("/posts", get(posts::index).post(posts::create))
.route("/posts/new", get(posts::new))
.route("/posts/:slug", get(posts::show))
.route("/posts/:slug/edit", get(posts::edit).post(posts::update))
.route("/posts/:slug/delete", get(posts::delete))
.with_state(ctx.clone())
}
```
## 8. アプリケーション統合
```rust
// src/app.rs
use axum::Router;
use loco_rs::prelude::*;
mod controllers;
mod models;
mod views;
pub struct App;
#[async_trait]
impl Hooks for App {
fn app_name() -> &'static str {
"blog"
}
fn routes(ctx: &AppContext) -> AppRoutes {
AppRoutes::with_default_routes()
.add_route(controllers::routes(ctx))
}
async fn boot(mode: StartMode, environment: &Environment) -> Result {
// 起動処理
Ok(BootResult::default())
}
}
```
## 使用方法
1. **マイグレーション実行**:
```bash
cargo loco db migrate
```
2. **アプリケーション起動**:
```bash
cargo loco start
```
3. **アクセス**:
- 記事一覧: http://localhost:5150/posts
- 新規作成: http://localhost:5150/posts/new
- 記事詳細: http://localhost:5150/posts/{slug}
## 機能
✅ 記事一覧表示
✅ 記事詳細表示
✅ 新規記事作成
✅ 記事編集
✅ 記事削除
✅ 公開/下書き切り替え
✅ スラッグベースURL
✅ レスポンシブデザイン
完成しました!blog.rsに以下の機能を追加したコード例を作成しました:
追加した機能
1. コントローラ
-
- 記事一覧表示 (
index)
- 記事一覧表示 (
-
- 記事詳細表示 (
show)
- 記事詳細表示 (
-
- 新規作成フォーム (
new)
- 新規作成フォーム (
-
- 記事作成処理 (
create)
- 記事作成処理 (
-
- 編集フォーム (
edit)
- 編集フォーム (
-
- 記事更新処理 (
update)
- 記事更新処理 (
-
- 記事削除処理 (
delete)
- 記事削除処理 (
2. ルート(RESTful)
-
GET /posts- 記事一覧
-
GET /posts/new- 新規作成フォーム
-
POST /posts- 記事作成
-
GET /posts/:slug- 記事詳細
-
GET /posts/:slug/edit- 編集フォーム
-
POST /posts/:slug- 記事更新
-
GET /posts/:slug/delete- 記事削除
3. Askamaテンプレート
-
index.html- 記事一覧ページ
-
show.html- 記事詳細ページ
-
form.html- 作成/編集フォーム
4. 追加機能
-
- スラッグベースのURL(SEOフレンドリー)
-
- 公開/下書き切り替え
-
- 作成日時・更新日時の自動記録
-
- レスポンシブデザイン
-
- データベースマイグレーション
セットアップ手順
# 1. 依存関係をCargo.tomlに追加
# 2. テンプレートディレクトリ作成
mkdir -p templates/posts
# 3. マイグレーション実行
cargo loco db migrate
# 4. 起動
cargo loco start
この実装により、完全に機能するブログシステムが完成します!さらにカスタマイズしたい部分があれば教えてください。
0 件のコメント:
コメントを投稿