【T9b】簡易ブログソフトウェアの作成 Part.Ⅱ ~ 記事関連機能の実装(6/11)
プロジェクトタイプ | (注意: 本文参照) |
---|
プロジェクト名 | T9b |
---|
ソリューション名 | PIT9 |
---|
注意
- 本ページの作業内容は 前のページまでの続き になっていることに注意せよ.
- 先に前のページまでをすべて読み,指示されている作業を済ませてから本ページを読むこと.
- プロジェクトの作成作業については準備作業を参照せよ.
9b-6. 記事の一覧表示のためのアクションの修正
次に個々のアクションとビューを見直していこう.最初はIndex
アクションである.
Index
アクションでは,データベース内の すべてのユーザーの記事を更新日時順で表示する .
デフォルトではデータコンテキストクラスのArticles
プロパティをリスト化しているだけなので,
_に示すように修正しよう.
Articlesコントローラの修正内容(Index) 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
| // GET: Articles
public async Task<IActionResult> Index()
{
// ログイン中のユーザー情報とそれが管理者ユーザーかどうかを取得する.
BlogUser? currentUser = await _userManager.GetUserAsync(User);
bool isAdminUser = await IsAdminUserAsync(currentUser);
// ログイン済みかどうか
bool isLoggedIn = _signInManager.IsSignedIn(User) && currentUser != null;
var articles = (from a in _context.Articles
where (a.PublicationState == PublicationStateType.Published // その記事が公開状態であるか,
|| (isLoggedIn && a.BlogUserId == currentUser!.Id) // もしくはその記事がログイン中のユーザの記事であるか
|| isAdminUser) // もしくは管理者としてログインしているなら無条件に
orderby a.Modified descending // 更新日時の降順で
select a).Include(a => a.BlogUser); // 記事を取得する.
ViewBag.CurrentUser = currentUser; // ↑でチェックした
ViewBag.IsAdminUser = isAdminUser; // ユーザー関連の情報を
ViewBag.IsLoggedIn = isLoggedIn; // ViewBagに入れておく(表示に使う).
return View(await articles.ToListAsync());
}
|
Index
アクションでは基本的に公開状態が「公開済み」である記事のみを表示するが,
通常ユーザーとしてログイン済みであり,その記事がログイン中のユーザーのものであれば公開状態に関係なくすべての記事を表示する.
また,管理者ユーザーでログインしている場合には記事の所有者や公開状態にかかわらずすべての記事を表示する.
このためのフィルター条件がLINQのwhere句の部分(12~14行目)の部分である.
なお,このチェック条件はリスト9b-5-2で定義したIsReadableAsync()
メソッドとほぼ同じものであるが,
残念ながらここでこのメソッドを使った条件式で閲覧の可否をチェックすることはできない .ここで重要な事実を述べておこう.
Entity Framework Core では,C#のコードとして有効なLINQの式であっても,すべての式が実際の問い合わせに使用できるわけではない.
Entity Framework Core における
LINQを用いた問い合わせは,SQLに変換できる式である必要がある.LINQに含まれるすべてのC#の式は,問い合わせを実行する時点で
データベースサーバに送ることができる定数などとして解決できる必要がある.また,C#のコードとして定義したメソッドは,SQLの式としてマッピング
できないので一切使用することはできない .ただし,データベースサーバ側であらかじめ定義したユーザー定義関数であれば,LINQの式として使用可能である.詳しくは
User-defined function mapping - EF Core - Microsoft Docsを
読むとよい.
このIndex
アクションのためのビューも変更しておこう.
Views/Articles/Index.cshtml を_に示すように変更しよう.
Views/Articles/Index.cshtmlの内容 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
| @model IEnumerable<T9b.Models.Article>
@{
ViewData["Title"] = "記事一覧";
var currentUser = (BlogUser?)ViewBag.CurrentUser; // アクションメソッドでチェックした
var isAdminUser = (bool)ViewBag.IsAdminUser; // ユーザー関連の情報を
var isLoggedIn = (bool)ViewBag.IsLoggedIn; // ViewBagから取り出す.
if (Model is null) throw new ArgumentNullException(nameof(Model)); // ad-hoc! 非null保証のための回避策
}
@foreach(var a in Model)
{
<section class="article">
@* 記事のタイトル(Title)の表示 *@
<h3><a asp-action="Details" asp-route-id="@a.ArticleId">@a.Title</a></h3>
@* 記事の作成者の表示 *@
<p> @(a.BlogUser?.Nickname ?? a.BlogUser?.UserName) による投稿</p>
@* 記事の本文を表示(整形済みテキストとして表示) *@
<pre>@a.Body</pre>
@* 「編集」や「削除」のリンクを表示するかどうかの判定 *@
@* (ログイン済みで,かつ管理者であるかログイン中のユーザーの作成した記事なら表示する) *@
@if (isLoggedIn && (isAdminUser || (currentUser != null && a.BlogUserId == currentUser.Id)))
{
@* 記事の公開状態を表示 *@
<p>@Html.DisplayNameFor(_ => a.PublicationState):@Html.DisplayFor(_ => a.PublicationState)</p>
@* 「編集」や「削除」のリンクを表示 *@
<p>
<a asp-action="Edit" asp-route-id="@a.ArticleId">編集</a>
| <a asp-action="Delete" asp-route-id="@a.ArticleId">削除</a>
</p>
}
</section>
}
@* ログイン済みの場合は「新規作成」のリンクを表示 *@
@if (isLoggedIn)
{
<a asp-action="Create">新規作成</a>
}
|
各記事のタイトルにはその記事の個別表示,すなわちDetails
アクションへのリンクを張っている(17行目).
20行目では「ユーザー名
による投稿」という文言を表示している.ここでは??演算子を用いてニックネームが設定されている場合はそれを表示するようにしている.
記事の本文は,ここでは単純に pre 要素(整形済みテキスト)として表示している.一般的なウェブログソフトウェアであれば
多少の制限のあるHTMLや,MarkdownやAsciiDocといった軽量マークアップ言語を用いて記事を作成できることが多いが
今回は簡単のために単にベタテキストとして表示するのみにとどめている.
ログイン済みの場合は,ページ下部に「新規作成」のリンク(=Create
アクションへのリンク)を表示する(42~45行目).
また,同じくログイン済みの場合,各記事ごとにそれがログイン中のユーザーが書いた記事であるならばその公開状態と
「編集」と「削除」のリンクを表示している(33~36行目).
Last updated on 2024-06-19
Published on 2024-06-19